New file change notification system

This commit is contained in:
Allen Webster 2019-08-12 21:19:02 -07:00
parent 422d67c41f
commit ac04842f97
10 changed files with 154 additions and 88 deletions

101
4ed.cpp
View File

@ -12,6 +12,24 @@
#define DEFAULT_DISPLAY_WIDTH 672 #define DEFAULT_DISPLAY_WIDTH 672
#define DEFAULT_MINIMUM_BASE_DISPLAY_WIDTH 550 #define DEFAULT_MINIMUM_BASE_DISPLAY_WIDTH 550
////////////////////////////////
Mutex_Lock::Mutex_Lock(System_Functions *s, System_Mutex m){
s->mutex_acquire(m);
this->system = s;
this->mutex = m;
}
Mutex_Lock::~Mutex_Lock(){
this->system->mutex_release(this->mutex);
}
Mutex_Lock::operator System_Mutex(){
return(this->mutex);
}
////////////////////////////////
internal App_Coroutine_State internal App_Coroutine_State
get_state(Application_Links *app){ get_state(Application_Links *app){
App_Coroutine_State state = {}; App_Coroutine_State state = {};
@ -732,15 +750,15 @@ make_arena_models(Models *models){
//////////////////////////////// ////////////////////////////////
internal App_Vars* internal Models*
app_setup_memory(System_Functions *system, Application_Memory *memory){ app_setup_memory(System_Functions *system, Application_Memory *memory){
Cursor cursor = make_cursor(memory->vars_memory, memory->vars_memory_size); Cursor cursor = make_cursor(memory->vars_memory, memory->vars_memory_size);
App_Vars *vars = push_array_zero(&cursor, App_Vars, 1); Models *models = push_array_zero(&cursor, Models, 1);
vars->models.mem.arena = make_arena_system(system); models->mem.arena = make_arena_system(system);
vars->models.base_allocator = vars->models.mem.arena.base_allocator; models->base_allocator = models->mem.arena.base_allocator;
heap_init(&vars->models.mem.heap); heap_init(&models->mem.heap);
heap_extend(&vars->models.mem.heap, memory->target_memory, memory->target_memory_size); heap_extend(&models->mem.heap, memory->target_memory, memory->target_memory_size);
return(vars); return(models);
} }
internal u32 internal u32
@ -822,21 +840,21 @@ launch_command_via_keycode(System_Functions *system, Models *models, View *view,
App_Read_Command_Line_Sig(app_read_command_line){ App_Read_Command_Line_Sig(app_read_command_line){
i32 out_size = 0; i32 out_size = 0;
App_Vars *vars = app_setup_memory(system, memory); Models *models = app_setup_memory(system, memory);
App_Settings *settings = &vars->models.settings; App_Settings *settings = &models->settings;
memset(settings, 0, sizeof(*settings)); memset(settings, 0, sizeof(*settings));
plat_settings->font_size = 16; plat_settings->font_size = 16;
if (argc > 1){ if (argc > 1){
init_command_line_settings(&vars->models.settings, plat_settings, argc, argv); init_command_line_settings(&models->settings, plat_settings, argc, argv);
} }
*files = vars->models.settings.init_files; *files = models->settings.init_files;
*file_count = &vars->models.settings.init_files_count; *file_count = &models->settings.init_files_count;
return(out_size); return(out_size);
} }
App_Init_Sig(app_init){ App_Init_Sig(app_init){
App_Vars *vars = (App_Vars*)memory->vars_memory; Models *models = (Models*)memory->vars_memory;
Models *models = &vars->models; models->system = system;
models->keep_playing = true; models->keep_playing = true;
app_links_init(system, &models->app_links, memory->user_memory, memory->user_memory_size); app_links_init(system, &models->app_links, memory->user_memory, memory->user_memory_size);
@ -893,7 +911,10 @@ App_Init_Sig(app_init){
dynamic_workspace_init(&models->mem.heap, &models->lifetime_allocator, DynamicWorkspace_Global, 0, &models->dynamic_workspace); dynamic_workspace_init(&models->mem.heap, &models->lifetime_allocator, DynamicWorkspace_Global, 0, &models->dynamic_workspace);
// NOTE(allen): file setup // NOTE(allen): file setup
working_set_init(system, &models->working_set); working_set_init(models, &models->working_set);
Mutex_Lock file_order_lock(system, models->working_set.mutex);
models->working_set.default_display_width = DEFAULT_DISPLAY_WIDTH; models->working_set.default_display_width = DEFAULT_DISPLAY_WIDTH;
models->working_set.default_minimum_base_display_width = DEFAULT_MINIMUM_BASE_DISPLAY_WIDTH; models->working_set.default_minimum_base_display_width = DEFAULT_MINIMUM_BASE_DISPLAY_WIDTH;
@ -929,10 +950,6 @@ App_Init_Sig(app_init){
models->title_space = push_array(arena, char, models->title_capacity); models->title_space = push_array(arena, char, models->title_capacity);
block_copy(models->title_space, WINDOW_NAME, sizeof(WINDOW_NAME)); block_copy(models->title_space, WINDOW_NAME, sizeof(WINDOW_NAME));
// NOTE(allen): init system context
models->system = system;
models->vars = vars;
// NOTE(allen): init baked in buffers // NOTE(allen): init baked in buffers
File_Init init_files[] = { File_Init init_files[] = {
{ string_u8_litinit("*messages*"), &models->message_buffer, true , }, { string_u8_litinit("*messages*"), &models->message_buffer, true , },
@ -978,6 +995,8 @@ App_Init_Sig(app_init){
App_Step_Sig(app_step){ App_Step_Sig(app_step){
Models *models = (Models*)memory->vars_memory; Models *models = (Models*)memory->vars_memory;
Mutex_Lock file_order_lock(system, models->working_set.mutex);
models->next_animate_delay = max_u32; models->next_animate_delay = max_u32;
models->animate_next_frame = false; models->animate_next_frame = false;
@ -996,50 +1015,6 @@ App_Step_Sig(app_step){
} }
} }
#if 0
// NOTE(allen): check files are up to date
{
b32 mem_too_small = 0;
i32 size = 0;
i32 buffer_size = KB(32);
Arena *scratch = &models->mem.arena;
Temp_Memory temp = begin_temp(scratch);
char *buffer = push_array(scratch, char, buffer_size);
u32 unmark_top = 0;
u32 unmark_max = Thousand(8);
Editing_File **unmark = (Editing_File**)push_array(scratch, Editing_File*, unmark_max);
Working_Set *working_set = &models->working_set;
for (;system->get_file_change(buffer, buffer_size, &mem_too_small, &size);){
Assert(!mem_too_small);
Editing_File_Name canon = {};
if (get_canon_name(system, scratch, SCu8(buffer, size), &canon)){
Editing_File *file = working_set_contains_canon(working_set, string_from_file_name(&canon));
if (file != 0){
if (file->state.ignore_behind_os == 0){
file_add_dirty_flag(file, DirtyState_UnloadedChanges);
}
else if (file->state.ignore_behind_os == 1){
file->state.ignore_behind_os = 2;
unmark[unmark_top++] = file;
if (unmark_top == unmark_max){
break;
}
}
}
}
}
for (u32 i = 0; i < unmark_top; ++i){
unmark[i]->state.ignore_behind_os = 0;
}
end_temp(temp);
}
#endif
// NOTE(allen): reorganizing panels on screen // NOTE(allen): reorganizing panels on screen
Vec2_i32 prev_dim = layout_get_root_size(&models->layout); Vec2_i32 prev_dim = layout_get_root_size(&models->layout);
Vec2_i32 current_dim = V2i32(target->width, target->height); Vec2_i32 current_dim = V2i32(target->width, target->height);

View File

@ -35,6 +35,7 @@ enum App_State{
}; };
struct Models{ struct Models{
System_Functions *system;
Base_Allocator *base_allocator; Base_Allocator *base_allocator;
Mem_Options mem; Mem_Options mem;
@ -121,10 +122,6 @@ struct Models{
b32 animated_last_frame; b32 animated_last_frame;
u64 last_render_usecond_stamp; u64 last_render_usecond_stamp;
// System Context
System_Functions *system;
struct App_Vars *vars;
// Event Context // Event Context
Application_Step_Input *input; Application_Step_Input *input;
Key_Event_Data key; Key_Event_Data key;
@ -162,11 +159,6 @@ struct Consumption_Record{
char consumer[32]; char consumer[32];
}; };
// TODO(allen): GET RID OF IT!
struct App_Vars{
Models models;
};
typedef i32 App_Coroutine_Purpose; typedef i32 App_Coroutine_Purpose;
enum{ enum{
Co_View, Co_View,
@ -217,6 +209,16 @@ enum{
AppCoroutineRequest_ModifyFace = 2, AppCoroutineRequest_ModifyFace = 2,
}; };
////////////////////////////////
struct Mutex_Lock{
Mutex_Lock(System_Functions *system, System_Mutex mutex);
~Mutex_Lock();
operator System_Mutex();
System_Functions *system;
System_Mutex mutex;
};
#endif #endif
// BOTTOM // BOTTOM

View File

@ -94,13 +94,13 @@ file_set_unimportant(Editing_File *file, b32 val){
if (val){ if (val){
file->state.dirty = DirtyState_UpToDate; file->state.dirty = DirtyState_UpToDate;
} }
file->settings.unimportant = (b8)(val != false); file->settings.unimportant = (b8)(val);
} }
internal void internal void
file_set_to_loading(Editing_File *file){ file_set_to_loading(Editing_File *file){
memset(&file->state, 0, sizeof(file->state)); block_zero_struct(&file->state);
memset(&file->settings, 0, sizeof(file->settings)); block_zero_struct(&file->settings);
file->is_loading = true; file->is_loading = true;
} }

View File

@ -98,17 +98,18 @@ struct Editing_File{
Node main_chain_node; Node main_chain_node;
}; };
Node touch_node; Node touch_node;
Node reloaded_node;
Node edit_finished_mark_node;
b32 edit_finished_marked;
b32 is_loading;
Buffer_ID id; Buffer_ID id;
Editing_File_Settings settings; Editing_File_Settings settings;
b32 is_loading;
Editing_File_State state; Editing_File_State state;
File_Attributes attributes; File_Attributes attributes;
Lifetime_Object *lifetime_object; Lifetime_Object *lifetime_object;
Editing_File_Name base_name; Editing_File_Name base_name;
Editing_File_Name unique_name; Editing_File_Name unique_name;
Editing_File_Name canon; Editing_File_Name canon;
b32 edit_finished_marked;
Node edit_finished_mark_node;
}; };
#endif #endif

View File

@ -61,6 +61,12 @@ typedef Sys_Wake_Up_Timer_Set_Sig(System_Wake_Up_Timer_Set);
#define Sys_Wake_Up_Timer_Check_Sig(name) u64 name(Plat_Handle handle) #define Sys_Wake_Up_Timer_Check_Sig(name) u64 name(Plat_Handle handle)
typedef Sys_Wake_Up_Timer_Check_Sig(System_Wake_Up_Timer_Check); typedef Sys_Wake_Up_Timer_Check_Sig(System_Wake_Up_Timer_Check);
#define Sys_Signal_Step_Sig(name) void name(u32 code)
typedef Sys_Signal_Step_Sig(System_Signal_Step);
#define Sys_Sleep_Sig(name) void name(u64 microseconds)
typedef Sys_Sleep_Sig(System_Sleep);
// clipboard // clipboard
#define Sys_Post_Clipboard_Sig(name) void name(String_Const_u8 str) #define Sys_Post_Clipboard_Sig(name) void name(String_Const_u8 str)
typedef Sys_Post_Clipboard_Sig(System_Post_Clipboard); typedef Sys_Post_Clipboard_Sig(System_Post_Clipboard);
@ -179,6 +185,8 @@ struct System_Functions{
System_Wake_Up_Timer_Create *wake_up_timer_create; System_Wake_Up_Timer_Create *wake_up_timer_create;
System_Wake_Up_Timer_Release *wake_up_timer_release; System_Wake_Up_Timer_Release *wake_up_timer_release;
System_Wake_Up_Timer_Set *wake_up_timer_set; System_Wake_Up_Timer_Set *wake_up_timer_set;
System_Signal_Step *signal_step;
System_Sleep *sleep;
// clipboard // clipboard
System_Post_Clipboard *post_clipboard; System_Post_Clipboard *post_clipboard;

View File

@ -19,6 +19,54 @@ working_set_file_default_settings(Working_Set *working_set, Editing_File *file){
//////////////////////////////// ////////////////////////////////
internal void
file_change_notification_check(System_Functions *system, Working_Set *working_set, Editing_File *file){
if (file->canon.name_size > 0 && !file->settings.unimportant){
String_Const_u8 name = SCu8(file->canon.name_space, file->canon.name_size);
File_Attributes attributes = system->quick_file_attributes(name);
if (attributes.last_write_time > file->attributes.last_write_time){
if (!HasFlag(file->state.dirty, DirtyState_UnloadedChanges)){
file_add_dirty_flag(file, DirtyState_UnloadedChanges);
dll_insert_back(&working_set->has_reloaded_sentinel,
&file->reloaded_node);
system->signal_step(0);
}
}
file->attributes = attributes;
}
}
internal void
file_change_notification_thread_main(void *ptr){
Models *models = (Models*)ptr;
System_Functions *system = models->system;
Working_Set *working_set = &models->working_set;
for (;;){
system->sleep(Thousand(250));
Mutex_Lock lock(system, working_set->mutex);
if (working_set->active_file_count > 0){
i32 check_count = working_set->active_file_count/16;
check_count = clamp(1, check_count, 100);
Node *used = &working_set->active_file_sentinel;
Node *node = working_set->sync_check_iterator;
if (node == 0 || node == used){
node = used->next;
}
for (i32 i = 0; i < check_count; i += 1){
Editing_File *file = CastFromMember(Editing_File, main_chain_node, node);
node = node->next;
if (node == used){
node = node->next;
}
file_change_notification_check(system, working_set, file);
}
working_set->sync_check_iterator = node;
}
}
}
////////////////////////////////
internal Editing_File* internal Editing_File*
working_set_allocate_file(Working_Set *working_set, Lifetime_Allocator *lifetime_allocator){ working_set_allocate_file(Working_Set *working_set, Lifetime_Allocator *lifetime_allocator){
Editing_File *file = working_set->free_files; Editing_File *file = working_set->free_files;
@ -47,6 +95,9 @@ working_set_allocate_file(Working_Set *working_set, Lifetime_Allocator *lifetime
internal void internal void
working_set_free_file(Heap *heap, Working_Set *working_set, Editing_File *file){ working_set_free_file(Heap *heap, Working_Set *working_set, Editing_File *file){
if (working_set->sync_check_iterator == &file->main_chain_node){
working_set->sync_check_iterator = working_set->sync_check_iterator->next;
}
dll_remove(&file->main_chain_node); dll_remove(&file->main_chain_node);
dll_remove(&file->touch_node); dll_remove(&file->touch_node);
working_set->active_file_count -= 1; working_set->active_file_count -= 1;
@ -65,8 +116,9 @@ working_set_get_file(Working_Set *working_set, Buffer_ID id){
} }
internal void internal void
working_set_init(System_Functions *system, Working_Set *working_set){ working_set_init(Models *models, Working_Set *working_set){
block_zero_struct(working_set); block_zero_struct(working_set);
System_Functions *system = models->system;
working_set->arena = make_arena_system(system); working_set->arena = make_arena_system(system);
working_set->id_counter = 1; working_set->id_counter = 1;
@ -82,6 +134,10 @@ working_set_init(System_Functions *system, Working_Set *working_set){
working_set->id_to_ptr_table = make_table_u64_u64(allocator, slot_count); working_set->id_to_ptr_table = make_table_u64_u64(allocator, slot_count);
working_set->canon_table = make_table_Data_u64(allocator, slot_count); working_set->canon_table = make_table_Data_u64(allocator, slot_count);
working_set->name_table = make_table_Data_u64(allocator, slot_count); working_set->name_table = make_table_Data_u64(allocator, slot_count);
dll_init_sentinel(&working_set->has_reloaded_sentinel);
working_set->mutex = system->mutex_make();
working_set->file_change_thread = system->thread_launch(file_change_notification_thread_main, models);
} }
internal Editing_File* internal Editing_File*

View File

@ -13,6 +13,10 @@
#define FRED_WORKING_SET_H #define FRED_WORKING_SET_H
struct Working_Set{ struct Working_Set{
// NOTE(allen): After initialization of file_change_thread
// the members of this struct should only be accessed by a thread
// who owns the mutex member.
Arena arena; Arena arena;
Editing_File *free_files; Editing_File *free_files;
@ -32,15 +36,22 @@ struct Working_Set{
Table_Data_u64 canon_table; Table_Data_u64 canon_table;
Table_Data_u64 name_table; Table_Data_u64 name_table;
Node *sync_check_iterator;
Node has_reloaded_sentinel;
System_Mutex mutex;
System_Thread file_change_thread;
i32 default_display_width;
i32 default_minimum_base_display_width;
// TODO(allen): do(update clipboard system to exist fully in the custom layer) // TODO(allen): do(update clipboard system to exist fully in the custom layer)
// NOTE(allen): These members have nothing to do with the working set or
// the mutex that gaurds the other members.
String_Const_u8 clipboards[64]; String_Const_u8 clipboards[64];
i32 clipboard_size; i32 clipboard_size;
i32 clipboard_max_size; i32 clipboard_max_size;
i32 clipboard_current; i32 clipboard_current;
i32 clipboard_rolling; i32 clipboard_rolling;
i32 default_display_width;
i32 default_minimum_base_display_width;
}; };
internal void internal void

View File

@ -28,6 +28,8 @@ link_system_code(void){
SYSLINK(wake_up_timer_create); SYSLINK(wake_up_timer_create);
SYSLINK(wake_up_timer_release); SYSLINK(wake_up_timer_release);
SYSLINK(wake_up_timer_set); SYSLINK(wake_up_timer_set);
SYSLINK(signal_step);
SYSLINK(sleep);
SYSLINK(post_clipboard); SYSLINK(post_clipboard);

View File

@ -270,8 +270,8 @@ handle_type_ptr(void *ptr){
//////////////////////////////// ////////////////////////////////
internal void internal void
system_schedule_step(){ system_schedule_step(u32 code){
PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0); PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, code, 0);
} }
//////////////////////////////// ////////////////////////////////
@ -894,6 +894,17 @@ Sys_Wake_Up_Timer_Set_Sig(system_wake_up_timer_set){
} }
} }
internal
Sys_Signal_Step_Sig(system_signal_step){
system_schedule_step(code);
}
internal
Sys_Sleep_Sig(system_sleep){
u32 milliseconds = (u32)(microseconds/Thousand(1));
Sleep(milliseconds);
}
//////////////////////////////// ////////////////////////////////
internal DWORD internal DWORD
@ -1919,7 +1930,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
// NOTE(allen): schedule another step if needed // NOTE(allen): schedule another step if needed
if (result.animating){ if (result.animating){
system_schedule_step(); system_schedule_step(0);
} }
// NOTE(allen): sleep a bit to cool off :) // NOTE(allen): sleep a bit to cool off :)

View File

@ -375,7 +375,7 @@ int_color_from_colorref(COLORREF ref, int_color alpha_from){
} }
internal void internal void
system_schedule_step(); system_schedule_step(u32 code);
internal UINT_PTR CALLBACK internal UINT_PTR CALLBACK
color_picker_hook(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam){ color_picker_hook(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam){
@ -428,7 +428,7 @@ color_picker_hook(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam){
if(*picker->dest != new_color) if(*picker->dest != new_color)
{ {
*picker->dest = new_color; *picker->dest = new_color;
system_schedule_step(); system_schedule_step(0);
} }
} }
} }