From c4242cf1624844dab61ea5b07b40244ce3627788 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 19 Jan 2024 10:00:53 -0800 Subject: [PATCH] non-helper os_properties_from_file_path - can use accelerated path here which just looks at path for properties, rather than having to open a handle; also tweak txti layer to gracefully fail if a write happened between its load of file data --- src/os/core/linux/os_core_linux.c | 8 + src/os/core/os_core.c | 9 - src/os/core/os_core.h | 2 +- src/os/core/win32/os_core_win32.c | 19 ++ src/txti/txti.c | 291 +++++++++++++++--------------- 5 files changed, 177 insertions(+), 152 deletions(-) diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index f9c2af02..2907ffac 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -1198,6 +1198,14 @@ os_file_path_exists(String8 path) return 0; } +internal FileProperties +os_properties_from_file_path(String8 path) +{ + FileProperties props = {0}; + NotImplemented; + return props; +} + //- rjf: file maps internal OS_Handle diff --git a/src/os/core/os_core.c b/src/os/core/os_core.c index 3baa2a25..e1429d1d 100644 --- a/src/os/core/os_core.c +++ b/src/os/core/os_core.c @@ -126,15 +126,6 @@ os_write_data_list_to_file_path(String8 path, String8List list) return good; } -internal FileProperties -os_properties_from_file_path(String8 path) -{ - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path); - FileProperties props = os_properties_from_file(file); - os_file_close(file); - return props; -} - internal OS_FileID os_id_from_file_path(String8 path) { diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 8bdab734..1f5c9d31 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -176,7 +176,6 @@ internal void os_relaunch_self(void); internal String8 os_data_from_file_path(Arena *arena, String8 path); internal B32 os_write_data_to_file_path(String8 path, String8 data); internal B32 os_write_data_list_to_file_path(String8 path, String8List list); -internal FileProperties os_properties_from_file_path(String8 path); internal OS_FileID os_id_from_file_path(String8 path); internal S64 os_file_id_compare(OS_FileID a, OS_FileID b); internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range); @@ -260,6 +259,7 @@ internal B32 os_delete_file_at_path(String8 path); internal B32 os_copy_file_path(String8 dst, String8 src); internal String8 os_full_path_from_path(Arena *arena, String8 path); internal B32 os_file_path_exists(String8 path); +internal FileProperties os_properties_from_file_path(String8 path); //- rjf: file maps internal OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file); diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 8aceb136..5de8e3c2 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -791,6 +791,25 @@ os_file_path_exists(String8 path) return exists; } +internal FileProperties +os_properties_from_file_path(String8 path) +{ + WIN32_FIND_DATAW find_data = {0}; + Temp scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + HANDLE handle = FindFirstFileW((WCHAR *)path16.str, &find_data); + FindClose(handle); + FileProperties props = {0}; + { + props.size = Compose64Bit(find_data.nFileSizeHigh, find_data.nFileSizeLow); + w32_dense_time_from_file_time(&props.created, &find_data.ftCreationTime); + w32_dense_time_from_file_time(&props.modified, &find_data.ftLastWriteTime); + props.flags = w32_file_property_flags_from_dwFileAttributes(find_data.dwFileAttributes); + } + scratch_end(scratch); + return props; +} + //- rjf: file maps internal OS_Handle diff --git a/src/txti/txti.c b/src/txti/txti.c index 62f17a7c..89db9fc7 100644 --- a/src/txti/txti.c +++ b/src/txti/txti.c @@ -976,17 +976,20 @@ txti_mut_thread_entry_point(void *p) TXTI_Stripe *stripe = &txti_state->entity_map_stripes.v[stripe_idx]; //- rjf: load file if we need it + B32 load_valid = 0; String8 file_contents = {0}; TXTI_LangKind lang_kind = TXTI_LangKind_Null; U64 timestamp = 0; if(msg->kind == TXTI_MsgKind_Reload) { + FileProperties pre_load_props = os_properties_from_file_path(msg->string); OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, msg->string); - FileProperties props = os_properties_from_file(file); - timestamp = props.modified; - file_contents = os_string_from_file_range(scratch.arena, file, r1u64(0, props.size)); + timestamp = pre_load_props.modified; + file_contents = os_string_from_file_range(scratch.arena, file, r1u64(0, pre_load_props.size)); lang_kind = txti_lang_kind_from_extension(str8_skip_last_dot(msg->string)); os_file_close(file); + FileProperties post_load_props = os_properties_from_file_path(msg->string); + load_valid = (post_load_props.modified == pre_load_props.modified); } //- rjf: nonzero lang kind -> unpack lang info @@ -1003,6 +1006,7 @@ txti_mut_thread_entry_point(void *p) //- rjf: detect line end kind TXTI_LineEndKind line_end_kind = TXTI_LineEndKind_Null; + if(load_valid) { U64 lf_count = 0; U64 cr_count = 0; @@ -1029,7 +1033,7 @@ txti_mut_thread_entry_point(void *p) //- rjf: obtain initial buffer_apply_gen, reset byte processing counters U64 initial_buffer_apply_gen = 0; - OS_MutexScopeR(stripe->rw_mutex) + if(load_valid) OS_MutexScopeR(stripe->rw_mutex) { TXTI_Entity *entity = 0; for(TXTI_Entity *e = slot->first; e != 0; e = e->next) @@ -1052,16 +1056,56 @@ txti_mut_thread_entry_point(void *p) } //- rjf: apply edits - for(U64 buffer_apply_idx = 0; - buffer_apply_idx < TXTI_ENTITY_BUFFER_COUNT; - buffer_apply_idx += 1) + if(load_valid) { - // rjf: last buffer we're going to edit? -> bump buffer_apply_gen, - // so that before we touch this last buffer, all readers of this - // entity will get the already-modified buffers. - if(buffer_apply_idx == TXTI_ENTITY_BUFFER_COUNT-1) + for(U64 buffer_apply_idx = 0; + buffer_apply_idx < TXTI_ENTITY_BUFFER_COUNT; + buffer_apply_idx += 1) { - OS_MutexScopeW(stripe->rw_mutex) + // rjf: last buffer we're going to edit? -> bump buffer_apply_gen, + // so that before we touch this last buffer, all readers of this + // entity will get the already-modified buffers. + if(buffer_apply_idx == TXTI_ENTITY_BUFFER_COUNT-1) + { + OS_MutexScopeW(stripe->rw_mutex) + { + TXTI_Entity *entity = 0; + for(TXTI_Entity *e = slot->first; e != 0; e = e->next) + { + if(e->id == id) + { + entity = e; + break; + } + } + if(entity != 0) + { + entity->buffer_apply_gen += 1; + if(line_end_kind != TXTI_LineEndKind_Null) + { + entity->line_end_kind = line_end_kind; + } + if(lang_kind != TXTI_LangKind_Null) + { + entity->lang_kind = lang_kind; + } + if(timestamp != 0) + { + entity->timestamp = timestamp; + } + } + } + } + + // rjf: apply edit to this buffer. + // + // NOTE(rjf): all edits can apply *with a shared mutex lock*, + // because only the mutator thread for this buffer can touch the + // non-currently-viewable buffers. we only need to have an + // exclusive lock to bump the buffer_apply_gen (to change the + // actively viewable buffer). + // + OS_MutexScopeR(stripe->rw_mutex) { TXTI_Entity *entity = 0; for(TXTI_Entity *e = slot->first; e != 0; e = e->next) @@ -1074,147 +1118,110 @@ txti_mut_thread_entry_point(void *p) } if(entity != 0) { - entity->buffer_apply_gen += 1; - if(line_end_kind != TXTI_LineEndKind_Null) - { - entity->line_end_kind = line_end_kind; - } - if(lang_kind != TXTI_LangKind_Null) - { - entity->lang_kind = lang_kind; - } - if(timestamp != 0) - { - entity->timestamp = timestamp; - } - } - } - } - - // rjf: apply edit to this buffer. - // - // NOTE(rjf): all edits can apply *with a shared mutex lock*, - // because only the mutator thread for this buffer can touch the - // non-currently-viewable buffers. we only need to have an - // exclusive lock to bump the buffer_apply_gen (to change the - // actively viewable buffer). - // - OS_MutexScopeR(stripe->rw_mutex) - { - TXTI_Entity *entity = 0; - for(TXTI_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - TXTI_Buffer *buffer = &entity->buffers[(initial_buffer_apply_gen+1+buffer_apply_idx)%TXTI_ENTITY_BUFFER_COUNT]; - - // rjf: clear old analysis data - arena_clear(buffer->analysis_arena); - buffer->lines_count = 0; - buffer->lines_ranges = 0; - buffer->lines_max_size = 0; - MemoryZeroStruct(&buffer->tokens); - - // rjf: perform edit to buffer data - switch(msg->kind) - { - default:{}break; + TXTI_Buffer *buffer = &entity->buffers[(initial_buffer_apply_gen+1+buffer_apply_idx)%TXTI_ENTITY_BUFFER_COUNT]; - // rjf: replace range - case TXTI_MsgKind_Append: ProfScope("append") - { - U8 *append_data_buffer = push_array_no_zero(buffer->data_arena, U8, msg->string.size); - MemoryCopy(append_data_buffer, msg->string.str, msg->string.size); - buffer->data.size += msg->string.size; - if(buffer->data.str == 0 && msg->string.size != 0) - { - buffer->data.str = append_data_buffer; - } - }break; + // rjf: clear old analysis data + arena_clear(buffer->analysis_arena); + buffer->lines_count = 0; + buffer->lines_ranges = 0; + buffer->lines_max_size = 0; + MemoryZeroStruct(&buffer->tokens); - // rjf: reload from disk - case TXTI_MsgKind_Reload: ProfScope("reload") + // rjf: perform edit to buffer data + switch(msg->kind) { - arena_clear(buffer->data_arena); - if(file_contents.size != 0) + default:{}break; + + // rjf: replace range + case TXTI_MsgKind_Append: ProfScope("append") { - buffer->data = push_str8_copy(buffer->data_arena, file_contents); - } - else - { - MemoryZeroStruct(&buffer->data); - } - }break; - } - - // rjf: parse & store line range info - { - // rjf: count # of lines - U64 line_count = 1; - U64 byte_process_start_idx = 0; - for(U64 idx = 0; idx < buffer->data.size; idx += 1) - { - if(buffer_apply_idx == 0 && idx-byte_process_start_idx >= 1000) - { - ins_atomic_u64_add_eval(&entity->bytes_processed, (idx-byte_process_start_idx)); - byte_process_start_idx = idx; - } - if(buffer->data.str[idx] == '\n' || buffer->data.str[idx] == '\r') - { - line_count += 1; - if(buffer->data.str[idx] == '\r') + U8 *append_data_buffer = push_array_no_zero(buffer->data_arena, U8, msg->string.size); + MemoryCopy(append_data_buffer, msg->string.str, msg->string.size); + buffer->data.size += msg->string.size; + if(buffer->data.str == 0 && msg->string.size != 0) { - idx += 1; + buffer->data.str = append_data_buffer; + } + }break; + + // rjf: reload from disk + case TXTI_MsgKind_Reload: ProfScope("reload") + { + arena_clear(buffer->data_arena); + if(file_contents.size != 0) + { + buffer->data = push_str8_copy(buffer->data_arena, file_contents); + } + else + { + MemoryZeroStruct(&buffer->data); + } + }break; + } + + // rjf: parse & store line range info + { + // rjf: count # of lines + U64 line_count = 1; + U64 byte_process_start_idx = 0; + for(U64 idx = 0; idx < buffer->data.size; idx += 1) + { + if(buffer_apply_idx == 0 && idx-byte_process_start_idx >= 1000) + { + ins_atomic_u64_add_eval(&entity->bytes_processed, (idx-byte_process_start_idx)); + byte_process_start_idx = idx; + } + if(buffer->data.str[idx] == '\n' || buffer->data.str[idx] == '\r') + { + line_count += 1; + if(buffer->data.str[idx] == '\r') + { + idx += 1; + } + } + } + + // rjf: allocate & store line ranges + buffer->lines_count = line_count; + buffer->lines_ranges = push_array_no_zero(buffer->analysis_arena, Rng1U64, buffer->lines_count); + U64 line_idx = 0; + U64 line_start_idx = 0; + for(U64 idx = 0; idx <= buffer->data.size; idx += 1) + { + if(idx == buffer->data.size || buffer->data.str[idx] == '\n' || buffer->data.str[idx] == '\r') + { + Rng1U64 line_range = r1u64(line_start_idx, idx); + U64 line_size = dim_1u64(line_range); + buffer->lines_ranges[line_idx] = line_range; + buffer->lines_max_size = Max(buffer->lines_max_size, line_size); + line_idx += 1; + line_start_idx = idx+1; + if(idx < buffer->data.size && buffer->data.str[idx] == '\r') + { + line_start_idx += 1; + idx += 1; + } } } } - // rjf: allocate & store line ranges - buffer->lines_count = line_count; - buffer->lines_ranges = push_array_no_zero(buffer->analysis_arena, Rng1U64, buffer->lines_count); - U64 line_idx = 0; - U64 line_start_idx = 0; - for(U64 idx = 0; idx <= buffer->data.size; idx += 1) + // rjf: lex file contents + if(lex_function != 0) { - if(idx == buffer->data.size || buffer->data.str[idx] == '\n' || buffer->data.str[idx] == '\r') - { - Rng1U64 line_range = r1u64(line_start_idx, idx); - U64 line_size = dim_1u64(line_range); - buffer->lines_ranges[line_idx] = line_range; - buffer->lines_max_size = Max(buffer->lines_max_size, line_size); - line_idx += 1; - line_start_idx = idx+1; - if(idx < buffer->data.size && buffer->data.str[idx] == '\r') - { - line_start_idx += 1; - idx += 1; - } - } + buffer->tokens = lex_function(buffer->analysis_arena, buffer_apply_idx == 0 ? &entity->bytes_processed : 0, buffer->data); + } + + // rjf: mark final process counter + if(buffer_apply_idx == 0) + { + ins_atomic_u64_eval_assign(&entity->bytes_processed, entity->bytes_to_process); + } + + // rjf: mark task completion + if(buffer_apply_idx == TXTI_ENTITY_BUFFER_COUNT-1) + { + ins_atomic_u64_eval_assign(&entity->working_count, 0); } - } - - // rjf: lex file contents - if(lex_function != 0) - { - buffer->tokens = lex_function(buffer->analysis_arena, buffer_apply_idx == 0 ? &entity->bytes_processed : 0, buffer->data); - } - - // rjf: mark final process counter - if(buffer_apply_idx == 0) - { - ins_atomic_u64_eval_assign(&entity->bytes_processed, entity->bytes_to_process); - } - - // rjf: mark task completion - if(buffer_apply_idx == TXTI_ENTITY_BUFFER_COUNT-1) - { - ins_atomic_u64_eval_assign(&entity->working_count, 0); } } }