diff --git a/4ed.cpp b/4ed.cpp index 5d323598..44ac9039 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -26,16 +26,16 @@ restore_state(Application_Links *app, App_Coroutine_State state){ app->type_coroutine = state.type; } -internal Coroutine_Head* -app_coroutine_handle_request(Models *models, Coroutine_Head *co, u32 *vals){ - Coroutine_Head *result = 0; +internal Coroutine* +app_coroutine_handle_request(Models *models, Coroutine *co, u32 *vals){ + Coroutine *result = 0; System_Functions *system = models->system; switch (vals[2]){ case AppCoroutineRequest_NewFontFace: { Face_Description *description = ((Face_Description**)vals)[0]; Face_ID face_id = font_set_new_face(&models->font_set, description); - result = system->resume_coroutine(co, &face_id, vals); + result = coroutine_run(&models->coroutines, co, &face_id, vals); }break; case AppCoroutineRequest_ModifyFace: @@ -43,36 +43,22 @@ app_coroutine_handle_request(Models *models, Coroutine_Head *co, u32 *vals){ Face_Description *description = ((Face_Description**)vals)[0]; Face_ID face_id = ((Face_ID*)vals)[3]; b32 success = alter_font_and_update_files(system, models, face_id, description); - result = system->resume_coroutine(co, &success, vals); + result = coroutine_run(&models->coroutines, co, &success, vals); }break; } return(result); } -internal Coroutine_Head* -app_launch_coroutine(System_Functions *system, Application_Links *app, Coroutine_Type type, Coroutine_Head *co, void *in, u32 *out){ +internal Coroutine* +app_coroutine_run(Models *models, App_Coroutine_Purpose purpose, Coroutine *co, void *in, u32 *out){ + Application_Links *app = &models->app_links; App_Coroutine_State prev_state = get_state(app); app->current_coroutine = co; - app->type_coroutine = type; + app->type_coroutine = purpose; u32 coroutine_out[4] = {}; - Coroutine_Head *result = system->launch_coroutine(co, in, coroutine_out); + Coroutine *result = coroutine_run(&models->coroutines, co, in, coroutine_out); for (;result != 0 && coroutine_out[2] != 0;){ - result = app_coroutine_handle_request((Models*)app->cmd_context, result, coroutine_out); - } - block_copy(out, coroutine_out, sizeof(*out)*2); - restore_state(app, prev_state); - return(result); -} - -internal Coroutine_Head* -app_resume_coroutine(System_Functions *system, Application_Links *app, Coroutine_Type type, Coroutine_Head *co, void *in, u32 *out){ - App_Coroutine_State prev_state = get_state(app); - app->current_coroutine = co; - app->type_coroutine = type; - u32 coroutine_out[4] = {}; - Coroutine_Head *result = system->resume_coroutine(co, in, coroutine_out); - for (;result != 0 && coroutine_out[2] != 0;){ - result = app_coroutine_handle_request((Models*)app->cmd_context, co, coroutine_out); + result = app_coroutine_handle_request(models, result, coroutine_out); } block_copy(out, coroutine_out, sizeof(*out)*2); restore_state(app, prev_state); @@ -475,7 +461,7 @@ interpret_binding_buffer(Models *models, void *buffer, i32 size){ #include "4ed_api_implementation.cpp" internal void -command_caller(Coroutine_Head *coroutine){ +command_caller(Coroutine *coroutine){ Command_In *cmd_in = (Command_In*)coroutine->in; Models *models = cmd_in->models; if (models->command_caller != 0){ @@ -795,7 +781,7 @@ force_abort_coroutine(System_Functions *system, Models *models, View *view){ User_Input user_in = {}; user_in.abort = true; for (u32 j = 0; j < 10 && models->command_coroutine != 0; ++j){ - models->command_coroutine = app_resume_coroutine(system, &models->app_links, Co_Command, models->command_coroutine, &user_in, models->command_coroutine_flags); + models->command_coroutine = app_coroutine_run(models, Co_Command, models->command_coroutine, &user_in, models->command_coroutine_flags); } if (models->command_coroutine != 0){ // TODO(allen): post grave warning @@ -813,14 +799,14 @@ launch_command_via_event(System_Functions *system, Models *models, View *view, K if (cmd_bind.custom != 0){ Assert(models->command_coroutine == 0); - Coroutine_Head *command_coroutine = system->create_coroutine(command_caller); + Coroutine *command_coroutine = coroutine_create(&models->coroutines, command_caller); models->command_coroutine = command_coroutine; Command_In cmd_in = {}; cmd_in.models = models; cmd_in.bind = cmd_bind; - models->command_coroutine = app_launch_coroutine(system, &models->app_links, Co_Command, models->command_coroutine, &cmd_in, models->command_coroutine_flags); + models->command_coroutine = app_coroutine_run(models, Co_Command, models->command_coroutine, &cmd_in, models->command_coroutine_flags); models->prev_command = cmd_bind; if (event.keycode != key_animate){ @@ -863,6 +849,9 @@ App_Init_Sig(app_init){ Arena *arena = &models->mem.arena; + // NOTE(allen): coroutines + coroutine_system_init(system, &models->coroutines); + // NOTE(allen): font set font_set_init(system, &models->font_set); @@ -1010,6 +999,7 @@ App_Step_Sig(app_step){ } } +#if 0 // NOTE(allen): check files are up to date { b32 mem_too_small = 0; @@ -1051,6 +1041,7 @@ App_Step_Sig(app_step){ end_temp(temp); } +#endif // NOTE(allen): reorganizing panels on screen Vec2_i32 prev_dim = layout_get_root_size(&models->layout); @@ -1262,12 +1253,11 @@ App_Step_Sig(app_step){ case EventConsume_Command: { - // NOTE(allen): update command coroutine if (models->command_coroutine != 0){ models->key = *key_ptr; - Coroutine_Head *command_coroutine = models->command_coroutine; + Coroutine *command_coroutine = models->command_coroutine; u32 abort_flags = models->command_coroutine_flags[1]; u32 get_flags = models->command_coroutine_flags[0] | abort_flags; @@ -1280,7 +1270,7 @@ App_Step_Sig(app_step){ user_in.key = *key_ptr; user_in.command.command = cmd_bind.custom; user_in.abort = ((abort_flags & event_flags) != 0); - models->command_coroutine = app_resume_coroutine(system, &models->app_links, Co_Command, command_coroutine, &user_in, models->command_coroutine_flags); + models->command_coroutine = app_coroutine_run(models, Co_Command, command_coroutine, &user_in, models->command_coroutine_flags); if (user_in.key.keycode != key_animate){ models->animate_next_frame = true; diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index eba9b285..48594876 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -30,7 +30,7 @@ api_check_buffer(Editing_File *file){ internal b32 api_check_buffer_and_tokens(Editing_File *file){ - return(api_check_buffer(file) && file->state.token_array.tokens != 0 && file->state.tokens_complete); + return(api_check_buffer(file) && file->state.token_array.tokens != 0); } internal b32 @@ -856,13 +856,8 @@ DOC_SEE(Buffer_Setting_ID) if (!file->settings.tokens_exist){ file_first_lex_serial(system, models, file); } - if (!file->state.still_lexing){ - file->settings.virtual_white = true; - full_remeasure = true; - } - else{ - result = false; - } + file->settings.virtual_white = true; + full_remeasure = true; } } else{ @@ -2583,11 +2578,11 @@ DOC_SEE(User_Input) System_Functions *system = models->system; User_Input result = {}; if (app->type_coroutine == Co_Command){ - Coroutine_Head *coroutine = (Coroutine_Head*)app->current_coroutine; + Coroutine *coroutine = (Coroutine*)app->current_coroutine; Assert(coroutine != 0); ((u32*)coroutine->out)[0] = get_type; ((u32*)coroutine->out)[1] = abort_type; - system->yield_coroutine(coroutine); + coroutine_yield(coroutine); result = *(User_Input*)coroutine->in; } return(result); @@ -3027,11 +3022,11 @@ DOC_SEE(Face_Description) Face_ID result = 0; if (is_running_coroutine(app)){ System_Functions *system = models->system; - Coroutine_Head *coroutine = (Coroutine_Head*)app->current_coroutine; + Coroutine *coroutine = (Coroutine*)app->current_coroutine; Assert(coroutine != 0); ((Face_Description**)coroutine->out)[0] = description; ((u32*)coroutine->out)[2] = AppCoroutineRequest_NewFontFace; - system->yield_coroutine(coroutine); + coroutine_yield(coroutine); result = *(Face_ID*)(coroutine->in); } else{ @@ -3058,12 +3053,12 @@ DOC_SEE(try_create_new_face) b32 result = false; if (is_running_coroutine(app)){ System_Functions *system = models->system; - Coroutine_Head *coroutine = (Coroutine_Head*)app->current_coroutine; + Coroutine *coroutine = (Coroutine*)app->current_coroutine; Assert(coroutine != 0); ((Face_Description**)coroutine->out)[0] = description; ((u32*)coroutine->out)[2] = AppCoroutineRequest_ModifyFace; ((u32*)coroutine->out)[3] = id; - system->yield_coroutine(coroutine); + coroutine_yield(coroutine); result = *(b32*)(coroutine->in); } else{ diff --git a/4ed_app_models.h b/4ed_app_models.h index 03e8fcab..14ed685f 100644 --- a/4ed_app_models.h +++ b/4ed_app_models.h @@ -38,7 +38,8 @@ struct Models{ Mapping mapping; Command_Binding prev_command; - Coroutine_Head *command_coroutine; + Coroutine_Group coroutines; + Coroutine *command_coroutine; u32 command_coroutine_flags[2]; Child_Process_Container child_processes; @@ -176,7 +177,8 @@ struct App_Vars{ App_State state; }; -enum Coroutine_Type{ +typedef i32 App_Coroutine_Purpose; +enum{ Co_View, Co_Command, }; diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index a10868f7..bef16c88 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -44,6 +44,7 @@ struct Mem_Options{ #include "4ed_render_target.h" #include "4ed.h" #include "4ed_buffer_model.h" +#include "4ed_coroutine.h" #define FCPP_FORBID_MALLOC #include "4coder_lib/4cpp_lexer.h" @@ -72,6 +73,7 @@ struct Mem_Options{ #include "4ed_font_set.h" #include "4ed_app_models.h" +#include "4ed_coroutine.cpp" #include "4ed_mem.cpp" #include "4ed_ptr_check.cpp" #include "4ed_memory_bank.cpp" diff --git a/4ed_code_wrap.cpp b/4ed_code_wrap.cpp index f8eb6574..046ff62a 100644 --- a/4ed_code_wrap.cpp +++ b/4ed_code_wrap.cpp @@ -483,7 +483,7 @@ file_measure_wraps(System_Functions *system, Mem_Options *mem, Editing_File *fil Potential_Wrap_Indent_Pair *potential_marks = 0; i32 max_wrap_indent_mark = Million(1); - if (params.virtual_white && file->state.tokens_complete && !file->state.still_lexing){ + if (params.virtual_white && file->state.token_array.tokens != 0){ wrap_state_init(&wrap_state, file, face); use_tokens = true; diff --git a/4ed_coroutine.cpp b/4ed_coroutine.cpp new file mode 100644 index 00000000..ac0889d4 --- /dev/null +++ b/4ed_coroutine.cpp @@ -0,0 +1,162 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 19.07.2017 + * + * Coroutine implementation from thread+mutex+cv + * + */ + +// TOP + +internal void +coroutine__pass_control(Coroutine *me, Coroutine *other, + Coroutine_State my_new_state, Coroutine_Pass_Control control){ + Assert(me->state == CoroutineState_Active); + Assert(me->sys == other->sys); + + System_Functions *system = me->system; + + me->state = my_new_state; + other->state = CoroutineState_Active; + me->sys->active = other; + system->condition_variable_signal(other->cv); + if (control == CoroutinePassControl_BlockMe){ + for (;me->state != CoroutineState_Active;){ + system->condition_variable_wait(me->cv, me->sys->lock); + } + } +} + +internal void +coroutine_main(void *ptr){ + Coroutine *me = (Coroutine*)ptr; + System_Functions *system = me->system; + + // NOTE(allen): Init handshake + Assert(me->state == CoroutineState_Dead); + system->mutex_acquire(me->sys->lock); + me->sys->did_init = true; + system->condition_variable_signal(me->sys->init_cv); + + for (;;){ + // NOTE(allen): Wait until someone wakes us up, then go into our procedure. + for (;me->state != CoroutineState_Active;){ + system->condition_variable_wait(me->cv, me->sys->lock); + } + Assert(me->type != CoroutineType_Root); + Assert(me->yield_ctx != 0); + Assert(me->function != 0); + + me->function(me); + + // NOTE(allen): Wake up the caller and set this coroutine back to being dead. + Coroutine *other = me->yield_ctx; + Assert(other != 0); + Assert(other->state == CoroutineState_Waiting); + + coroutine__pass_control(me, other, CoroutineState_Dead, CoroutinePassControl_ExitMe); + me->function = 0; + } +} + +internal void +coroutine_sub_init(Coroutine *co, Coroutine_Group *sys){ + System_Functions *system = sys->system; + block_zero_struct(co); + co->system = system; + co->sys = sys; + co->state = CoroutineState_Dead; + co->type = CoroutineType_Sub; + co->cv = system->condition_variable_make(); + sys->did_init = false; + co->thread = system->thread_launch(coroutine_main, co); + for (;!sys->did_init;){ + system->condition_variable_wait(sys->init_cv, sys->lock); + } +} + +internal void +coroutine_system_init(System_Functions *system, Coroutine_Group *sys){ + sys->arena = make_arena_system(system); + sys->system = system; + + Coroutine *root = &sys->root; + + sys->lock = system->mutex_make(); + sys->init_cv = system->condition_variable_make(); + sys->active = root; + + block_zero_struct(root); + root->system = system; + root->sys = sys; + root->state = CoroutineState_Active; + root->type = CoroutineType_Root; + root->cv = system->condition_variable_make(); + + sys->unused = 0; + + system->mutex_acquire(sys->lock); +} + +internal Coroutine* +coroutine_system_alloc(Coroutine_Group *sys){ + Coroutine *result = sys->unused; + if (result != 0){ + sll_stack_pop(sys->unused); + } + else{ + result = push_array(&sys->arena, Coroutine, 1); + coroutine_sub_init(result, sys); + } + result->next = 0; + return(result); +} + +internal void +coroutine_system_free(Coroutine_Group *sys, Coroutine *coroutine){ + sll_stack_push(sys->unused, coroutine); +} + +//////////////////////////////// + +internal Coroutine* +coroutine_create(Coroutine_Group *coroutines, Coroutine_Function *func){ + Coroutine *result = coroutine_system_alloc(coroutines); + Assert(result->state == CoroutineState_Dead); + result->function = func; + return(result); +} + +internal Coroutine* +coroutine_run(Coroutine_Group *sys, Coroutine *other, void *in, void *out_arena){ + other->in = in; + other->out = out; + + Coroutine *me = other->sys->active; + Assert(me != 0); + Assert(me->sys == other->sys); + Assert(other->state == CoroutineState_Dead || other->state == CoroutineState_Inactive); + other->yield_ctx = me; + coroutine__pass_control(me, other, CoroutineState_Waiting, CoroutinePassControl_BlockMe); + Assert(me == other->sys->active); + + Coroutine *result = other; + if (other->state == CoroutineState_Dead){ + coroutine_system_free(sys, other); + result = 0; + } + return(result); +} + +internal void +coroutine_yield(Coroutine *me){ + Coroutine *other = me->yield_ctx; + Assert(other != 0); + Assert(me->sys == other->sys); + Assert(other->state == CoroutineState_Waiting); + coroutine__pass_control(me, other, CoroutineState_Inactive, CoroutinePassControl_BlockMe); +} + +// BOTTOM + diff --git a/4ed_coroutine.h b/4ed_coroutine.h new file mode 100644 index 00000000..066f26a4 --- /dev/null +++ b/4ed_coroutine.h @@ -0,0 +1,67 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 03.08.2019 + * + * Coroutine implementation from thread+mutex+cv + * + */ + +// TOP + +#if !defined(FRED_COROUTINE_H) +#define FRED_COROUTINE_H + +typedef void Coroutine_Function(struct Coroutine *head); + +typedef u32 Coroutine_State; +enum{ + CoroutineState_Dead, + CoroutineState_Active, + CoroutineState_Inactive, + CoroutineState_Waiting, +}; + +typedef u32 Coroutine_Type; +enum{ + CoroutineType_Uninitialized, + CoroutineType_Root, + CoroutineType_Sub, +}; + +struct Coroutine{ + Coroutine *next; + void *in; + void *out; + System_Functions *system; + System_Thread thread; + System_Condition_Variable cv; + struct Coroutine_Group *sys; + Coroutine_Function *function; + Coroutine *yield_ctx; + Coroutine_State state; + Coroutine_Type type; +}; + +struct Coroutine_Group{ + Arena arena; + System_Functions *system; + System_Mutex lock; + System_Condition_Variable init_cv; + b32 did_init; + Coroutine *active; + Coroutine *unused; + Coroutine root; +}; + +//////////////////////////////// + +typedef i32 Coroutine_Pass_Control; +enum{ + CoroutinePassControl_ExitMe, + CoroutinePassControl_BlockMe, +}; + +#endif + +// BOTTOM diff --git a/4ed_edit.cpp b/4ed_edit.cpp index 07372853..117912d4 100644 --- a/4ed_edit.cpp +++ b/4ed_edit.cpp @@ -12,14 +12,6 @@ internal void edit_pre_state_change(Models *models, Heap *heap, Editing_File *file){ System_Functions *system = models->system; - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_array.tokens){ - heap_free(heap, file->state.swap_array.tokens); - file->state.swap_array.tokens = 0; - } - file->state.still_lexing = 0; - } file_add_dirty_flag(file, DirtyState_UnsavedChanges); file_unmark_edit_finished(&models->working_set, file); Layout *layout = &models->layout; diff --git a/4ed_file.cpp b/4ed_file.cpp index 8cc0cd31..ccaac86b 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -485,13 +485,6 @@ file_create_from_string(System_Functions *system, Models *models, Editing_File * internal void file_free(System_Functions *system, Heap *heap, Lifetime_Allocator *lifetime_allocator, Working_Set *working_set, Editing_File *file){ - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_array.tokens){ - heap_free(heap, file->state.swap_array.tokens); - file->state.swap_array.tokens = 0; - } - } if (file->state.token_array.tokens){ heap_free(heap, file->state.token_array.tokens); } @@ -522,7 +515,7 @@ file_get_current_record_index(Editing_File *file){ internal b32 file_tokens_are_ready(Editing_File *file){ - return(file->state.token_array.tokens != 0 && file->state.tokens_complete && !file->state.still_lexing); + return(file->state.token_array.tokens != 0); } internal Managed_Scope diff --git a/4ed_file.h b/4ed_file.h index 2dfd4d7a..89a12112 100644 --- a/4ed_file.h +++ b/4ed_file.h @@ -78,11 +78,7 @@ struct Editing_File_State{ i32 current_record_index; Cpp_Token_Array token_array; - Cpp_Token_Array swap_array; - u32 lex_job; - b8 tokens_complete; - b8 still_lexing; - b8 in_edit_handler; + b32 in_edit_handler; Text_Effect paste_effect; diff --git a/4ed_file_lex.cpp b/4ed_file_lex.cpp index fa610b6c..897ff512 100644 --- a/4ed_file_lex.cpp +++ b/4ed_file_lex.cpp @@ -9,159 +9,13 @@ // TOP -// TODO(allen): this needs a rewrite _BAD_ -internal void -job_full_lex(System_Functions *system, Thread_Context *thread, Thread_Memory *memory, void *data[4]){ - Editing_File *file = (Editing_File*)data[0]; - Heap *heap = (Heap*)data[1]; - Models *models = (Models*)data[2]; - - Parse_Context parse_context = parse_context_get(&models->parse_context_memory, file->settings.parse_context_id, memory->data, memory->size); - if (!parse_context.valid){ - return; - } - - Gap_Buffer *buffer = &file->state.buffer; - i32 text_size = buffer_size(buffer); - - u32 aligned_buffer_size = (text_size + 3)&(~3); - - for (;memory->size < aligned_buffer_size + parse_context.memory_size;){ - void *old_base = memory->data; - system->grow_thread_memory(memory); - parse_context_rebase(&parse_context, old_base, memory->data); - } - - u8 *data_ptr = (u8*)memory->data; - umem data_size = memory->size; - data_ptr += parse_context.memory_size; - data_size -= parse_context.memory_size; - - Cpp_Token_Array tokens = {}; - tokens.tokens = (Cpp_Token*)(data_ptr); - tokens.max_count = (u32)(data_size / sizeof(Cpp_Token)); - tokens.count = 0; - - b32 still_lexing = true; - - Cpp_Lex_Data lex = cpp_lex_data_init(file->settings.tokens_without_strings, parse_context.kw_table, parse_context.pp_table); - - String_Const_u8 chunk_space[3]; - Cursor chunk_cursor = make_cursor(chunk_space, sizeof(chunk_space)); - String_Const_u8_Array chunks = buffer_get_chunks(&chunk_cursor, buffer); - - i32 chunk_index = 0; - - do{ - u8 *chunk = chunks.vals[chunk_index].str; - umem chunk_size = chunks.vals[chunk_index].size; - - i32 result = cpp_lex_step(&lex, (char*)chunk, (i32)chunk_size, text_size, &tokens, 2048); - switch (result){ - case LexResult_NeedChunk: - { - ++chunk_index; - Assert(chunk_index < chunks.count); - }break; - - case LexResult_NeedTokenMemory: - { - if (system->check_cancel(thread)){ - return; - } - - void *old_base = memory->data; - system->grow_thread_memory(memory); - cpp_rebase_tables(&lex, old_base, memory->data); - - data_ptr = (u8*)memory->data; - data_size = memory->size; - data_ptr += parse_context.memory_size; - data_size -= parse_context.memory_size; - tokens.tokens = (Cpp_Token*)(data_ptr); - tokens.max_count = (u32)(data_size / sizeof(Cpp_Token)); - }break; - - case LexResult_HitTokenLimit: - { - if (system->check_cancel(thread)){ - return; - } - }break; - - case LexResult_Finished: - { - still_lexing = false; - }break; - } - }while(still_lexing); - - i32 new_max = round_up_i32(tokens.count + 1, KB(1)); - - system->acquire_lock(FRAME_LOCK); - { - Assert(file->state.swap_array.tokens == 0); - file->state.swap_array.tokens = heap_array(heap, Cpp_Token, new_max); - } - system->release_lock(FRAME_LOCK); - - u8 *dest = (u8*)file->state.swap_array.tokens; - u8 *src = (u8*)tokens.tokens; - - memcpy(dest, src, tokens.count*sizeof(Cpp_Token)); - - system->acquire_lock(FRAME_LOCK); - { - Cpp_Token_Array *file_token_array = &file->state.token_array; - file_token_array->count = tokens.count; - file_token_array->max_count = new_max; - if (file_token_array->tokens){ - heap_free(heap, file_token_array->tokens); - } - file_token_array->tokens = file->state.swap_array.tokens; - file->state.swap_array.tokens = 0; - } - file->state.tokens_complete = true; - file->state.still_lexing = false; - file_mark_edit_finished(&models->working_set, file); - system->release_lock(FRAME_LOCK); -} - internal void file_kill_tokens(System_Functions *system, Heap *heap, Editing_File *file){ file->settings.tokens_exist = false; - if (file->state.still_lexing){ - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - if (file->state.swap_array.tokens){ - heap_free(heap, file->state.swap_array.tokens); - file->state.swap_array.tokens = 0; - } - } - if (file->state.token_array.tokens){ + if (file->state.token_array.tokens != 0){ heap_free(heap, file->state.token_array.tokens); } - file->state.tokens_complete = false; - file->state.token_array = null_cpp_token_array; -} - -internal void -file_first_lex_parallel(System_Functions *system, Models *models, Editing_File *file){ - Heap *heap = &models->mem.heap; - file->settings.tokens_exist = true; - - if (!file->is_loading && !file->state.still_lexing){ - Assert(file->state.token_array.tokens == 0); - - file->state.tokens_complete = false; - file->state.still_lexing = true; - - Job_Data job; - job.callback = job_full_lex; - job.data[0] = file; - job.data[1] = heap; - job.data[2] = models; - file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); - } + block_zero_struct(&file->state.token_array); } internal void @@ -171,8 +25,6 @@ file_first_lex_serial(System_Functions *system, Models *models, Editing_File *fi Heap *heap = &mem->heap; file->settings.tokens_exist = true; - Assert(!file->state.still_lexing); - if (file->is_loading == 0){ Assert(file->state.token_array.tokens == 0); @@ -200,7 +52,7 @@ file_first_lex_serial(System_Functions *system, Models *models, Editing_File *fi i32 chunk_index = 0; - Cpp_Token_Array *swap_array = &file->state.swap_array; + Cpp_Token_Array new_array = {}; do{ u8 *chunk = chunks.vals[chunk_index].str; @@ -218,22 +70,22 @@ file_first_lex_serial(System_Functions *system, Models *models, Editing_File *fi case LexResult_Finished: case LexResult_NeedTokenMemory: { - u32 new_max = round_up_u32(swap_array->count + new_tokens.count + 1, KB(1)); - if (swap_array->tokens == 0){ - swap_array->tokens = heap_array(heap, Cpp_Token, new_max); + u32 new_max = round_up_u32(new_array.count + new_tokens.count + 1, KB(1)); + if (new_array.tokens == 0){ + new_array.tokens = heap_array(heap, Cpp_Token, new_max); } else{ - u32 old_count = swap_array->count; + u32 old_count = new_array.count; Cpp_Token *new_token_mem = heap_array(heap, Cpp_Token, new_max); - memcpy(new_token_mem, swap_array->tokens, sizeof(*new_token_mem)*old_count); - heap_free(heap, swap_array->tokens); - swap_array->tokens = new_token_mem; + memcpy(new_token_mem, new_array.tokens, sizeof(*new_token_mem)*old_count); + heap_free(heap, new_array.tokens); + new_array.tokens = new_token_mem; } - swap_array->max_count = new_max; + new_array.max_count = new_max; - Assert(swap_array->count + new_tokens.count <= swap_array->max_count); - memcpy(swap_array->tokens + swap_array->count, new_tokens.tokens, new_tokens.count*sizeof(Cpp_Token)); - swap_array->count += new_tokens.count; + Assert(new_array.count + new_tokens.count <= new_array.max_count); + memcpy(new_array.tokens + new_array.count, new_tokens.tokens, new_tokens.count*sizeof(Cpp_Token)); + new_array.count += new_tokens.count; new_tokens.count = 0; if (result == LexResult_Finished){ @@ -246,155 +98,23 @@ file_first_lex_serial(System_Functions *system, Models *models, Editing_File *fi } while (still_lexing); Cpp_Token_Array *token_array = &file->state.token_array; - token_array->count = swap_array->count; - token_array->max_count = swap_array->max_count; + token_array->count = new_array.count; + token_array->max_count = new_array.max_count; if (token_array->tokens != 0){ heap_free(heap, token_array->tokens); } - token_array->tokens = swap_array->tokens; + token_array->tokens = new_array.tokens; - swap_array->tokens = 0; - swap_array->count = 0; - swap_array->max_count = 0; - - file->state.tokens_complete = true; - file->state.still_lexing = false; + new_array.tokens = 0; + new_array.count = 0; + new_array.max_count = 0; end_temp(temp); - file->state.tokens_complete = true; file_mark_edit_finished(&models->working_set, file); } } -internal b32 -file_relex_parallel(System_Functions *system, Models *models, Editing_File *file, i32 start_i, i32 end_i, i32 shift_amount){ - Mem_Options *mem = &models->mem; - Arena *scratch = &mem->arena; - Heap *heap = &mem->heap; - - b32 result = true; - if (file->state.token_array.tokens == 0){ - file_first_lex_parallel(system, models, file); - } - else{ - b32 internal_lex = !file->state.still_lexing; - if (internal_lex){ - Gap_Buffer *buffer = &file->state.buffer; - i32 extra_tolerance = 100; - - Cpp_Token_Array *array = &file->state.token_array; - Cpp_Relex_Range relex_range = cpp_get_relex_range(array, start_i, end_i); - - i32 relex_space_size = relex_range.end_token_index - relex_range.start_token_index + extra_tolerance; - - Temp_Memory temp = begin_temp(scratch); - Parse_Context parse_context = parse_context_get(scratch, &models->parse_context_memory, file->settings.parse_context_id); - Assert(parse_context.valid); - - Cpp_Token_Array relex_array; - relex_array.count = 0; - relex_array.max_count = relex_space_size; - relex_array.tokens = push_array(scratch, Cpp_Token, relex_array.max_count); - - i32 size = buffer_size(buffer); - - Cpp_Relex_Data state = cpp_relex_init(array, start_i, end_i, shift_amount, file->settings.tokens_without_strings, parse_context.kw_table, parse_context.pp_table); - - String_Const_u8_Array chunk_space[3]; - Cursor chunk_cursor = make_cursor(chunk_space, sizeof(chunk_space)); - String_Const_u8_Array chunks = buffer_get_chunks(&chunk_cursor, buffer, BufferGetChunk_ZeroTerminated); - - i32 chunk_index = 0; - u8 *chunk = chunks.vals[chunk_index].str; - umem chunk_size = chunks.vals[chunk_index].size; - - for (;!cpp_relex_is_start_chunk(&state, (char*)chunk, (i32)chunk_size);){ - ++chunk_index; - Assert(chunk_index < chunks.count); - chunk = chunks.vals[chunk_index].str; - chunk_size = chunks.vals[chunk_index].size; - } - - for (;;){ - Cpp_Lex_Result lex_result = - cpp_relex_step(&state, (char*)chunk, (i32)chunk_size, size, array, &relex_array); - - switch (lex_result){ - case LexResult_NeedChunk: - { - ++chunk_index; - Assert(chunk_index < chunks.count); - chunk = chunks.vals[chunk_index].str; - chunk_size = chunks.vals[chunk_index].size; - }break; - - case LexResult_NeedTokenMemory: - { - internal_lex = false; - }goto doublebreak; - - case LexResult_Finished: goto doublebreak; - } - } - doublebreak:; - - if (internal_lex){ - i32 new_count = cpp_relex_get_new_count(&state, array->count, &relex_array); - if (new_count > array->max_count){ - i32 new_max = round_up_i32(new_count, KB(1)); - void *memory = heap_allocate(heap, new_max*sizeof(Cpp_Token)); - memcpy(memory, array->tokens, array->count*sizeof(Cpp_Token)); - heap_free(heap, array->tokens); - array->tokens = (Cpp_Token*)memory; - array->max_count = new_max; - } - - cpp_relex_complete(&state, array, &relex_array); - file_mark_edit_finished(&models->working_set, file); - } - else{ - cpp_relex_abort(&state, array); - } - - end_temp(temp); - } - - if (!internal_lex){ - Cpp_Token_Array *array = &file->state.token_array; - Cpp_Get_Token_Result get_token_result = cpp_get_token(*array, end_i); - i32 end_token_i = get_token_result.token_index; - - if (end_token_i < 0){ - end_token_i = 0; - } - else if (end_i > array->tokens[end_token_i].start){ - ++end_token_i; - } - - cpp_shift_token_starts(array, end_token_i, shift_amount); - --end_token_i; - if (end_token_i >= 0){ - Cpp_Token *token = array->tokens + end_token_i; - if (token->start < end_i && token->start + token->size > end_i){ - token->size += shift_amount; - } - } - - file->state.still_lexing = true; - - Job_Data job = {}; - job.callback = job_full_lex; - job.data[0] = file; - job.data[1] = heap; - job.data[2] = models; - file->state.lex_job = system->post_job(BACKGROUND_THREADS, job); - result = false; - } - } - return(result); -} - internal b32 file_relex_serial(System_Functions *system, Models *models, Editing_File *file, i32 start_i, i32 end_i, i32 shift_amount){ Mem_Options *mem = &models->mem; @@ -405,8 +125,6 @@ file_relex_serial(System_Functions *system, Models *models, Editing_File *file, file_first_lex_serial(system, models, file); } else{ - Assert(!file->state.still_lexing); - Gap_Buffer *buffer = &file->state.buffer; Cpp_Token_Array *array = &file->state.token_array; @@ -477,22 +195,12 @@ file_relex_serial(System_Functions *system, Models *models, Editing_File *file, internal void file_first_lex(System_Functions *system, Models *models, Editing_File *file){ - if (!file->settings.virtual_white){ - file_first_lex_parallel(system, models, file); - } - else{ - file_first_lex_serial(system, models, file); - } + file_first_lex_serial(system, models, file); } internal void file_relex(System_Functions *system, Models *models, Editing_File *file, i32 start, i32 end, i32 shift_amount){ - if (!file->settings.virtual_white){ - file_relex_parallel(system, models, file, start, end, shift_amount); - } - else{ - file_relex_serial(system, models, file, start, end, shift_amount); - } + file_relex_serial(system, models, file, start, end, shift_amount); } // BOTTOM diff --git a/4ed_file_track.h b/4ed_file_track.h deleted file mode 100644 index 6a162cd0..00000000 --- a/4ed_file_track.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 20.07.2016 - * - * File tracking API. - * - */ - -// TOP - -#if !defined(FILE_TRACK_4TECH_H) -#define FILE_TRACK_4TECH_H - -#if !defined(FILE_TRACK_LINK) -# define FILE_TRACK_LINK static -#endif - -struct File_Track_System{ - u8 opaque[128]; -}; - -typedef i32 File_Track_Result; -enum{ - FileTrack_Good = 0, - FileTrack_MemoryTooSmall = 1, - FileTrack_OutOfTableMemory = 2, - FileTrack_OutOfListenerMemory = 3, - FileTrack_NoMoreEvents = 4, - FileTrack_FileSystemError = 5 -}; - -FILE_TRACK_LINK File_Track_Result -init_track_system(File_Track_System *system, Partition *scratch, void *table_memory, i32 table_memory_size, void *listener_memory, i32 listener_memory_size); - -FILE_TRACK_LINK File_Track_Result -add_listener(File_Track_System *system, Partition *scratch, u8 *filename); - -FILE_TRACK_LINK File_Track_Result -remove_listener(File_Track_System *system, Partition *scratch, u8 *filename); - -FILE_TRACK_LINK File_Track_Result -move_track_system(File_Track_System *system, Partition *scratch, void *mem, i32 size); - -FILE_TRACK_LINK File_Track_Result -expand_track_system_listeners(File_Track_System *system, Partition *scratch, void *mem, i32 size); - -FILE_TRACK_LINK File_Track_Result -get_change_event(File_Track_System *system, Partition *scratch, u8 *buffer, i32 max, i32 *size); - -FILE_TRACK_LINK File_Track_Result -shut_down_track_system(File_Track_System *system, Partition *scratch); - -#endif - -// BOTTOM diff --git a/4ed_system.h b/4ed_system.h index a3a0e92a..b045a36d 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -45,16 +45,6 @@ typedef Sys_Load_Close_Sig(System_Load_Close); #define Sys_Save_File_Sig(name) File_Attributes name(char *filename, char *buffer, u32 size) typedef Sys_Save_File_Sig(System_Save_File); -// file changes -#define Sys_Add_Listener_Sig(name) b32 name(char *filename) -typedef Sys_Add_Listener_Sig(System_Add_Listener); - -#define Sys_Remove_Listener_Sig(name) b32 name(char *filename) -typedef Sys_Remove_Listener_Sig(System_Remove_Listener); - -#define Sys_Get_File_Change_Sig(name) b32 name(char *buffer, i32 max, b32 *mem_too_small, i32 *required_size) -typedef Sys_Get_File_Change_Sig(System_Get_File_Change); - // time #define Sys_Now_Time_Sig(name) u64 name() typedef Sys_Now_Time_Sig(System_Now_Time); @@ -98,98 +88,49 @@ typedef Sys_CLI_Update_Step_Sig(System_CLI_Update_Step); #define Sys_CLI_End_Update_Sig(name) b32 name(CLI_Handles *cli) typedef Sys_CLI_End_Update_Sig(System_CLI_End_Update); -// coroutine - -struct Coroutine_Head{ - void *in; - void *out; -}; - -#define COROUTINE_SIG(n) void n(Coroutine_Head *coroutine) -typedef COROUTINE_SIG(Coroutine_Function); - -#define Sys_Create_Coroutine_Sig(name) Coroutine_Head *name(Coroutine_Function *func) -typedef Sys_Create_Coroutine_Sig(System_Create_Coroutine); - -#define Sys_Launch_Coroutine_Sig(name) Coroutine_Head *name(Coroutine_Head *head, void *in, void *out) -typedef Sys_Launch_Coroutine_Sig(System_Launch_Coroutine); - -#define Sys_Resume_Coroutine_Sig(name) Coroutine_Head *name(Coroutine_Head *head, void *in, void *out) -typedef Sys_Resume_Coroutine_Sig(System_Resume_Coroutine); - -#define Sys_Yield_Coroutine_Sig(name) void name(Coroutine_Head *head) -typedef Sys_Yield_Coroutine_Sig(System_Yield_Coroutine); - // #define Sys_Open_Color_Picker_Sig(name) void name(Color_Picker *picker) typedef Sys_Open_Color_Picker_Sig(System_Open_Color_Picker); // thread -struct Thread_Context; +typedef Plat_Handle System_Thread; +typedef Plat_Handle System_Mutex; +typedef Plat_Handle System_Condition_Variable; +typedef void Thread_Function(void *ptr); -enum Lock_ID{ - FRAME_LOCK, - CANCEL_LOCK0, - CANCEL_LOCK1, - CANCEL_LOCK2, - CANCEL_LOCK3, - CANCEL_LOCK4, - CANCEL_LOCK5, - CANCEL_LOCK6, - CANCEL_LOCK7, - LOCK_COUNT -}; +#define Sys_Thread_Launch_Sig(name) System_Thread name(Thread_Function *proc, void *ptr) +typedef Sys_Thread_Launch_Sig(System_Thread_Launch); -enum Thread_Group_ID{ - BACKGROUND_THREADS, - THREAD_GROUP_COUNT -}; +#define Sys_Thread_Join_Sig(name) void name(System_Thread thread) +typedef Sys_Thread_Join_Sig(System_Thread_Join); -struct Thread_Memory{ - void *data; - u32 size; - u32 id; -}; -global Thread_Memory null_thread_memory = {}; +#define Sys_Thread_Free_Sig(name) void name(System_Thread thread) +typedef Sys_Thread_Free_Sig(System_Thread_Free); -struct Thread_Exchange; -struct System_Functions; +#define Sys_Mutex_Make_Sig(name) System_Mutex name(void) +typedef Sys_Mutex_Make_Sig(System_Mutex_Make); -#define Job_Callback_Sig(name) void name( \ -System_Functions *system, \ -Thread_Context *thread, \ -Thread_Memory *memory, \ -void *data[4]) +#define Sys_Mutex_Acquire_Sig(name) void name(System_Mutex mutex) +typedef Sys_Mutex_Acquire_Sig(System_Mutex_Acquire); -typedef void Job_Callback(System_Functions *system, Thread_Context *thread, Thread_Memory *memory, void *data[4]); +#define Sys_Mutex_Release_Sig(name) void name(System_Mutex mutex) +typedef Sys_Mutex_Release_Sig(System_Mutex_Release); -struct Job_Data{ - Job_Callback *callback; - void *data[4]; -}; +#define Sys_Mutex_Free_Sig(name) void name(System_Mutex mutex) +typedef Sys_Mutex_Free_Sig(System_Mutex_Free); -#define QUEUE_WRAP 256 +#define Sys_Condition_Variable_Make_Sig(name) System_Condition_Variable name(void) +typedef Sys_Condition_Variable_Make_Sig(System_Condition_Variable_Make); -#define THREAD_NOT_ASSIGNED 0xFFFFFFFF +#define Sys_Condition_Variable_Wait_Sig(name) void name(System_Condition_Variable cv, System_Mutex mutex) +typedef Sys_Condition_Variable_Wait_Sig(System_Condition_Variable_Wait); -#define Sys_Post_Job_Sig(name) u32 name(Thread_Group_ID group_id, Job_Data job) -typedef Sys_Post_Job_Sig(System_Post_Job); +#define Sys_Condition_Variable_Signal_Sig(name) void name(System_Condition_Variable cv) +typedef Sys_Condition_Variable_Signal_Sig(System_Condition_Variable_Signal); -#define Sys_Cancel_Job_Sig(name) void name(Thread_Group_ID group_id, u32 job_id) -typedef Sys_Cancel_Job_Sig(System_Cancel_Job); - -#define Sys_Check_Cancel_Sig(name) b32 name(Thread_Context *thread) -typedef Sys_Check_Cancel_Sig(System_Check_Cancel); - -#define Sys_Grow_Thread_Memory_Sig(name) void name(Thread_Memory *memory) -typedef Sys_Grow_Thread_Memory_Sig(System_Grow_Thread_Memory); - -#define Sys_Acquire_Lock_Sig(name) void name(i32 id) -typedef Sys_Acquire_Lock_Sig(System_Acquire_Lock); - -#define Sys_Release_Lock_Sig(name) void name(i32 id) -typedef Sys_Release_Lock_Sig(System_Release_Lock); +#define Sys_Condition_Variable_Free_Sig(name) void name(System_Condition_Variable cv) +typedef Sys_Condition_Variable_Free_Sig(System_Condition_Variable_Free); // memory #define Sys_Memory_Allocate_Sig(name) void* name(umem size) @@ -223,12 +164,9 @@ struct System_Functions{ Graphics_Get_Texture_Function *get_texture; Graphics_Fill_Texture_Function *fill_texture; - // files (tracked api): 11 + // files System_Get_Canonical *get_canonical; System_Get_File_List *get_file_list; - System_Add_Listener *add_listener; - System_Remove_Listener *remove_listener; - System_Get_File_Change *get_file_change; System_Quick_File_Attributes *quick_file_attributes; System_Load_Handle *load_handle; System_Load_Attributes *load_attributes; @@ -236,39 +174,38 @@ struct System_Functions{ System_Load_Close *load_close; System_Save_File *save_file; - // time: 4 + // time System_Now_Time *now_time; System_Wake_Up_Timer_Create *wake_up_timer_create; System_Wake_Up_Timer_Release *wake_up_timer_release; System_Wake_Up_Timer_Set *wake_up_timer_set; - // clipboard: 1 + // clipboard System_Post_Clipboard *post_clipboard; - // coroutine: 4 - System_Create_Coroutine *create_coroutine; - System_Launch_Coroutine *launch_coroutine; - System_Resume_Coroutine *resume_coroutine; - System_Yield_Coroutine *yield_coroutine; - - // cli: 4 + // cli System_CLI_Call *cli_call; System_CLI_Begin_Update *cli_begin_update; System_CLI_Update_Step *cli_update_step; System_CLI_End_Update *cli_end_update; // TODO(allen): - System_Open_Color_Picker *open_color_picker; + System_Open_Color_Picker *open_color_picker; - // threads: 6 - System_Post_Job *post_job; - System_Cancel_Job *cancel_job; - System_Check_Cancel *check_cancel; - System_Grow_Thread_Memory *grow_thread_memory; - System_Acquire_Lock *acquire_lock; - System_Release_Lock *release_lock; + // threads + System_Thread_Launch *thread_launch; + System_Thread_Join *thread_join; + System_Thread_Free *thread_free; + System_Mutex_Make *mutex_make; + System_Mutex_Acquire *mutex_acquire; + System_Mutex_Release *mutex_release; + System_Mutex_Free *mutex_free; + System_Condition_Variable_Make *condition_variable_make; + System_Condition_Variable_Wait *condition_variable_wait; + System_Condition_Variable_Signal *condition_variable_signal; + System_Condition_Variable_Free *condition_variable_free; - // custom: 9 + // custom System_Memory_Allocate *memory_allocate; System_Memory_Set_Protection *memory_set_protection; System_Memory_Free *memory_free; diff --git a/4ed_view.cpp b/4ed_view.cpp index 643c5bdf..a753d6f2 100644 --- a/4ed_view.cpp +++ b/4ed_view.cpp @@ -524,9 +524,9 @@ render_loaded_file_in_view__inner(Models *models, Render_Target *target, View *v Assert(!file->is_dummy); Assert(buffer_good(&file->state.buffer)); - b32 tokens_use = file->state.tokens_complete && (file->state.token_array.count > 0); Cpp_Token_Array token_array = file->state.token_array; - b32 wrapped = !file->settings.unwrapped_lines; + b32 tokens_use = (token_array.tokens != 0); + b32 wrapped = (!file->settings.unwrapped_lines); Face_ID font_id = file->settings.font_id; i32 *line_starts = file->state.buffer.line_starts; diff --git a/4ed_working_set.cpp b/4ed_working_set.cpp index 3236741a..0fc43546 100644 --- a/4ed_working_set.cpp +++ b/4ed_working_set.cpp @@ -307,7 +307,6 @@ file_bind_file_name(System_Functions *system, Heap *heap, Working_Set *working_s file->canon.name_size = size; block_copy(file->canon.name_space, canon_file_name.str, size); file_name_terminate(&file->canon); - system->add_listener((char*)file->canon.name_space); b32 result = working_set_canon_add(working_set, file, string_from_file_name(&file->canon)); Assert(result); } @@ -316,7 +315,6 @@ internal void buffer_unbind_file(System_Functions *system, Working_Set *working_set, Editing_File *file){ Assert(file->unique_name.name_size == 0); Assert(file->canon.name_size != 0); - system->remove_listener((char*)file->canon.name_space); working_set_canon_remove(working_set, string_from_file_name(&file->canon)); file->canon.name_size = 0; } diff --git a/platform_all/4ed_coroutine.cpp b/platform_all/4ed_coroutine.cpp deleted file mode 100644 index 5a92236d..00000000 --- a/platform_all/4ed_coroutine.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 19.07.2017 - * - * Coroutine implementation from thread+mutex+cv - * - */ - -// TOP - -typedef u32 Coroutine_State; -enum{ - CoroutineState_Dead, - CoroutineState_Active, - CoroutineState_Inactive, - CoroutineState_Waiting, -}; - -typedef u32 Coroutine_Type; -enum{ - CoroutineType_Uninitialized, - CoroutineType_Root, - CoroutineType_Sub, -}; - -struct Coroutine{ - Coroutine_Head head; - - Thread thread; - Condition_Variable cv; - struct Coroutine_System *sys; - Coroutine_Function *function; - Coroutine *yield_ctx; - Coroutine_State state; - Coroutine_Type type; -}; - -struct Coroutine_System{ - Mutex lock; - Condition_Variable init_cv; - b32 did_init; - Coroutine *active; -}; - -#define COROUTINE_INT_SKIP_SLEEP false - -internal void -coroutine_internal_pass_control(Coroutine *me, Coroutine *other, Coroutine_State my_new_state, b32 do_sleep_loop = true){ - Assert(me->state == CoroutineState_Active); - Assert(me->sys == other->sys); - - me->state = my_new_state; - other->state = CoroutineState_Active; - me->sys->active = other; - system_signal_cv(&other->cv, &me->sys->lock); - if (do_sleep_loop){ - for (;me->state != CoroutineState_Active;){ - system_wait_cv(&me->cv, &me->sys->lock); - } - } -} - -internal -PLAT_THREAD_SIG(coroutine_main){ - Coroutine *me = (Coroutine*)ptr; - - // NOTE(allen): Init handshake - Assert(me->state == CoroutineState_Dead); - system_acquire_lock(&me->sys->lock); - me->sys->did_init = true; - system_signal_cv(&me->sys->init_cv, &me->sys->lock); - - for (;;){ - // NOTE(allen): Wait until someone wakes us up, then go into our procedure. - for (;me->state != CoroutineState_Active;){ - system_wait_cv(&me->cv, &me->sys->lock); - } - Assert(me->type != CoroutineType_Root); - Assert(me->yield_ctx != 0); - Assert(me->function != 0); - - me->function(&me->head); - - // NOTE(allen): Wake up the caller and set this coroutine back to being dead. - Coroutine *other = me->yield_ctx; - Assert(other != 0); - Assert(other->state == CoroutineState_Waiting); - - coroutine_internal_pass_control(me, other, CoroutineState_Dead, COROUTINE_INT_SKIP_SLEEP); - me->function = 0; - } -} - -internal void -init_coroutine_system(Coroutine *root, Coroutine_System *sys){ - system_init_lock(&sys->lock); - system_init_cv(&sys->init_cv); - sys->active = root; - - memset(root, 0, sizeof(*root)); - - root->sys = sys; - root->state = CoroutineState_Active; - root->type = CoroutineType_Root; - - system_init_cv(&root->cv); - - system_acquire_lock(&sys->lock); -} - -internal void -init_coroutine_sub(Coroutine *co, Coroutine_System *sys){ - memset(co, 0, sizeof(*co)); - - co->sys = sys; - co->state = CoroutineState_Dead; - co->type = CoroutineType_Sub; - - system_init_cv(&co->cv); - - sys->did_init = false; - system_init_and_launch_thread(&co->thread, coroutine_main, co); - for (;!sys->did_init;){ - system_wait_cv(&sys->init_cv, &sys->lock); - } -} - -// HACK(allen): I want to bundle this with launch! -internal void -coroutine_set_function(Coroutine *me, Coroutine_Function *function){ - Assert(me->state == CoroutineState_Dead); - me->function = function; -} - -internal void -coroutine_launch(Coroutine *me, Coroutine *other){ - Assert(me->sys == other->sys); - Assert(other->state == CoroutineState_Dead); - Assert(other->function != 0); - - other->yield_ctx = me; - coroutine_internal_pass_control(me, other, CoroutineState_Waiting); -} - -internal void -coroutine_yield(Coroutine *me){ - Coroutine *other = me->yield_ctx; - Assert(other != 0); - Assert(me->sys == other->sys); - Assert(other->state == CoroutineState_Waiting); - - coroutine_internal_pass_control(me, other, CoroutineState_Inactive); -} - -internal void -coroutine_resume(Coroutine *me, Coroutine *other){ - Assert(me->sys == other->sys); - Assert(other->state == CoroutineState_Inactive); - - other->yield_ctx = me; - coroutine_internal_pass_control(me, other, CoroutineState_Waiting); -} - -//////////////////////////////// - -struct Coroutine_Alloc_Block{ - Coroutine coroutine; - Coroutine_Alloc_Block *next; -}; - -#define COROUTINE_SLOT_SIZE sizeof(Coroutine_Alloc_Block) - -struct Coroutine_System_Auto_Alloc{ - Coroutine_System sys; - - Coroutine root; - Coroutine_Alloc_Block *head_free_uninit; - Coroutine_Alloc_Block *head_free_inited; -}; - -internal void -init_coroutine_system(Coroutine_System_Auto_Alloc *sys){ - init_coroutine_system(&sys->root, &sys->sys); - sys->head_free_uninit = 0; - sys->head_free_inited = 0; -} - -internal void -coroutine_system_provide_memory(Coroutine_System_Auto_Alloc *sys, void *memory, umem size){ - memset(memory, 0, size); - - Coroutine_Alloc_Block *blocks = (Coroutine_Alloc_Block*)memory; - umem count = (size / sizeof(*blocks)); - - Coroutine_Alloc_Block *old_head = sys->head_free_uninit; - sys->head_free_uninit = &blocks[0]; - Coroutine_Alloc_Block *block = blocks; - for (u32 i = 1; i < count; ++i, ++block){ - block->next = block + 1; - } - block->next = old_head; -} - -internal Coroutine_Alloc_Block* -coroutine_system_pop(Coroutine_Alloc_Block **head){ - Coroutine_Alloc_Block *result = *head; - if (result != 0){ - *head = result->next; - } - result->next = 0; - return(result); -} - -internal void -coroutine_system_push(Coroutine_Alloc_Block **head, Coroutine_Alloc_Block *block){ - block->next = *head; - *head = block; -} - -internal void -coroutine_system_force_init(Coroutine_System_Auto_Alloc *sys, u32 count){ - for (u32 i = 0; i < count; ++i){ - Coroutine_Alloc_Block *block = coroutine_system_pop(&sys->head_free_uninit); - if (block == 0){ - break; - } - init_coroutine_sub(&block->coroutine, &sys->sys); - coroutine_system_push(&sys->head_free_inited, block); - } -} - -internal Coroutine* -coroutine_system_alloc(Coroutine_System_Auto_Alloc *sys){ - Coroutine_Alloc_Block *block = coroutine_system_pop(&sys->head_free_inited); - if (block == 0){ - coroutine_system_force_init(sys, 1); - block = coroutine_system_pop(&sys->head_free_inited); - } - - Coroutine *result = 0; - if (block != 0){ - result = &block->coroutine; - } - return(result); -} - -internal void -coroutine_system_free(Coroutine_System_Auto_Alloc *sys, Coroutine *co){ - Coroutine_Alloc_Block *block = (Coroutine_Alloc_Block*)co; - coroutine_system_push(&sys->head_free_inited, block); -} - -// BOTTOM - diff --git a/platform_all/4ed_coroutine_functions.cpp b/platform_all/4ed_coroutine_functions.cpp deleted file mode 100644 index 154267cb..00000000 --- a/platform_all/4ed_coroutine_functions.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 10.09.2017 - * - * Mac C++ layer for 4coder - * - */ - -// TOP - -#if !defined(FRED_COROUTINE_FUNCTIONS_CPP) -#define FRED_COROUTINE_FUNCTIONS_CPP - -// -// Coroutine -// - -internal -Sys_Create_Coroutine_Sig(system_create_coroutine){ - Coroutine *coroutine = coroutine_system_alloc(&coroutines); - Coroutine_Head *result = 0; - if (coroutine != 0){ - coroutine_set_function(coroutine, func); - result = &coroutine->head; - } - return(result); -} - -internal -Sys_Launch_Coroutine_Sig(system_launch_coroutine){ - Coroutine *coroutine = (Coroutine*)head; - coroutine->head.in = in; - coroutine->head.out = out; - - Coroutine *active = coroutine->sys->active; - Assert(active != 0); - coroutine_launch(active, coroutine); - Assert(active == coroutine->sys->active); - - Coroutine_Head *result = &coroutine->head; - if (coroutine->state == CoroutineState_Dead){ - coroutine_system_free(&coroutines, coroutine); - result = 0; - } - return(result); -} - -Sys_Resume_Coroutine_Sig(system_resume_coroutine){ - Coroutine *coroutine = (Coroutine*)head; - coroutine->head.in = in; - coroutine->head.out = out; - - Coroutine *active = coroutine->sys->active; - Assert(active != 0); - coroutine_resume(active, coroutine); - Assert(active == coroutine->sys->active); - - Coroutine_Head *result = &coroutine->head; - if (coroutine->state == CoroutineState_Dead){ - coroutine_system_free(&coroutines, coroutine); - result = 0; - } - return(result); -} - -Sys_Yield_Coroutine_Sig(system_yield_coroutine){ - Coroutine *coroutine = (Coroutine*)head; - coroutine_yield(coroutine); -} - -#endif - -// BOTTOM - - diff --git a/platform_all/4ed_link_system_functions.cpp b/platform_all/4ed_link_system_functions.cpp index 658e72fa..f7eb7837 100644 --- a/platform_all/4ed_link_system_functions.cpp +++ b/platform_all/4ed_link_system_functions.cpp @@ -14,12 +14,9 @@ #define SYSLINK(name) sysfunc.name = system_##name internal void -link_system_code(){ +link_system_code(void){ SYSLINK(get_canonical); SYSLINK(get_file_list); - SYSLINK(add_listener); - SYSLINK(remove_listener); - SYSLINK(get_file_change); SYSLINK(quick_file_attributes); SYSLINK(load_handle); SYSLINK(load_attributes); @@ -34,11 +31,6 @@ link_system_code(){ SYSLINK(post_clipboard); - SYSLINK(create_coroutine); - SYSLINK(launch_coroutine); - SYSLINK(resume_coroutine); - SYSLINK(yield_coroutine); - SYSLINK(cli_call); SYSLINK(cli_begin_update); SYSLINK(cli_update_step); @@ -46,12 +38,17 @@ link_system_code(){ SYSLINK(open_color_picker); - SYSLINK(post_job); - SYSLINK(cancel_job); - SYSLINK(check_cancel); - SYSLINK(grow_thread_memory); - SYSLINK(acquire_lock); - SYSLINK(release_lock); + SYSLINK(thread_launch); + SYSLINK(thread_join); + SYSLINK(thread_free); + SYSLINK(mutex_make); + SYSLINK(mutex_acquire); + SYSLINK(mutex_release); + SYSLINK(mutex_free); + SYSLINK(condition_variable_make); + SYSLINK(condition_variable_wait); + SYSLINK(condition_variable_signal); + SYSLINK(condition_variable_free); SYSLINK(memory_allocate); SYSLINK(memory_set_protection); diff --git a/platform_all/4ed_shared_init_logic.cpp b/platform_all/4ed_shared_init_logic.cpp index 2ecd9d4e..959c993e 100644 --- a/platform_all/4ed_shared_init_logic.cpp +++ b/platform_all/4ed_shared_init_logic.cpp @@ -136,15 +136,5 @@ read_command_line(Arena *scratch, i32 argc, char **argv){ end_temp(temp); } -internal void -coroutines_init(){ - init_coroutine_system(&coroutines); - - umem size = COROUTINE_SLOT_SIZE*18; - void *mem = system_memory_allocate(size); - coroutine_system_provide_memory(&coroutines, mem, size); - coroutine_system_force_init(&coroutines, 4); -} - // BOTTOM diff --git a/platform_all/4ed_shared_thread_constants.h b/platform_all/4ed_shared_thread_constants.h deleted file mode 100644 index 8dbb7767..00000000 --- a/platform_all/4ed_shared_thread_constants.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 18.07.2017 - * - * Cross platform threading constants - * - */ - -// TOP - -#if !defined(FRED_SHARED_THREADING_CONSTANTS_H) -#define FRED_SHARED_THREADING_CONSTANTS_H - -#define CORE_COUNT 8 - -#define THREAD_TYPE_SIZE 32 -#define MUTEX_TYPE_SIZE 64 -#define CONDITION_VARIABLE_TYPE_SIZE 48 -#define SEMAPHORE_TYPE_SIZE 32 - -/* -fprintf(stdout, "%d VS %d\n", (i32)sizeof(Thread), THREAD_TYPE_SIZE); \ -fprintf(stdout, "%d VS %d\n", (i32)sizeof(Mutex), MUTEX_TYPE_SIZE); \ -fprintf(stdout, "%d VS %d\n", (i32)sizeof(Condition_Variable), CONDITION_VARIABLE_TYPE_SIZE); \ -fprintf(stdout, "%d VS %d\n", (i32)sizeof(Semaphore), SEMAPHORE_TYPE_SIZE); \ -*/ - -#define AssertThreadSizes() \ -Assert( sizeof(Thread) == THREAD_TYPE_SIZE ); \ -Assert( sizeof(Mutex) == MUTEX_TYPE_SIZE ); \ -Assert(sizeof(Condition_Variable) == CONDITION_VARIABLE_TYPE_SIZE); \ -Assert( sizeof(Semaphore) == SEMAPHORE_TYPE_SIZE ) - -#endif - -// BOTTOM - diff --git a/platform_all/4ed_work_queues.cpp b/platform_all/4ed_work_queues.cpp deleted file mode 100644 index 81601b94..00000000 --- a/platform_all/4ed_work_queues.cpp +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 18.07.2017 - * - * Cross platform logic for work queues. - * - */ - -// TOP - -enum CV_ID{ - CANCEL_CV0, - CANCEL_CV1, - CANCEL_CV2, - CANCEL_CV3, - CANCEL_CV4, - CANCEL_CV5, - CANCEL_CV6, - CANCEL_CV7, - CV_COUNT -}; - -struct Full_Job_Data{ - Job_Data job; - u32 running_thread; - u32 id; -}; - -struct Unbounded_Work_Queue{ - Full_Job_Data *jobs; - i32 count, max, skip; - u32 next_job_id; -}; - -struct Work_Queue{ - Full_Job_Data jobs[QUEUE_WRAP]; - Semaphore semaphore; - volatile u32 write_position; - volatile u32 read_position; -}; - -struct Thread_Context{ - u32 job_id; - b32 running; - b32 cancel; - - Work_Queue *queue; - u32 id; - u32 group_id; - u32 windows_id; - Thread thread; -}; - -struct Thread_Group{ - Thread_Context *threads; - i32 count; - - Unbounded_Work_Queue queue; - - i32 cancel_lock0; - i32 cancel_cv0; -}; - -struct Threading_Vars{ - Thread_Memory *thread_memory; - - Work_Queue queues[THREAD_GROUP_COUNT]; - Thread_Group groups[THREAD_GROUP_COUNT]; - Mutex locks[LOCK_COUNT]; - Condition_Variable conds[CV_COUNT]; -}; -global Threading_Vars threadvars; - -internal -Sys_Acquire_Lock_Sig(system_acquire_lock){ - system_acquire_lock(&threadvars.locks[id]); -} - -internal -Sys_Release_Lock_Sig(system_release_lock){ - system_release_lock(&threadvars.locks[id]); -} - -internal -PLAT_THREAD_SIG(job_thread_proc){ - Thread_Context *thread = (Thread_Context*)ptr; - - Work_Queue *queue = threadvars.queues + thread->group_id; - Thread_Group *group = threadvars.groups + thread->group_id; - - i32 thread_index = thread->id - 1; - Thread_Memory *thread_memory = threadvars.thread_memory + thread_index; - - i32 cancel_lock_id = group->cancel_lock0 + thread_index; - i32 cancel_cv_id = group->cancel_cv0 + thread_index; - Mutex *cancel_lock = &threadvars.locks[cancel_lock_id]; - Condition_Variable *cancel_cv = &threadvars.conds[cancel_cv_id]; - - if (thread_memory->size == 0){ - i32 new_size = KB(64); - thread_memory->data = system_memory_allocate(new_size); - thread_memory->size = new_size; - } - - for (;;){ - u32 read_index = queue->read_position; - u32 write_index = queue->write_position; - - if (read_index != write_index){ - u32 next_read_index = (read_index + 1) % QUEUE_WRAP; - u32 safe_read_index = InterlockedCompareExchange(&queue->read_position, next_read_index, read_index); - - if (safe_read_index == read_index){ - Full_Job_Data *full_job = queue->jobs + safe_read_index; - // NOTE(allen): This is interlocked so that it plays nice - // with the cancel job routine, which may try to cancel this job - // at the same time that we try to run it - - i32 safe_running_thread = InterlockedCompareExchange(&full_job->running_thread, thread->id, THREAD_NOT_ASSIGNED); - - if (safe_running_thread == THREAD_NOT_ASSIGNED){ - thread->job_id = full_job->id; - thread->running = true; - full_job->job.callback(&sysfunc, thread, thread_memory, full_job->job.data); - system_schedule_step(); - thread->running = false; - - system_acquire_lock(cancel_lock); - if (thread->cancel){ - thread->cancel = 0; - system_signal_cv(cancel_cv, cancel_lock); - } - system_release_lock(cancel_lock); - } - } - } - else{ - system_wait_on_semaphore(&queue->semaphore); - } - } -} - -internal void -initialize_unbounded_queue(Unbounded_Work_Queue *source_queue){ - i32 max = 512; - source_queue->jobs = (Full_Job_Data*)system_memory_allocate(max*sizeof(Full_Job_Data)); - source_queue->count = 0; - source_queue->max = max; - source_queue->skip = 0; -} - -internal i32 -get_work_queue_available_space(i32 write, i32 read){ - // NOTE(allen): The only time that queue->write_position == queue->read_position - // is allowed is when the queue is empty. Thus if (write_position+1 == read_position) - // the available space is zero. So these computations both end up leaving one slot unused. - - // TODO(allen): The only way I can think to easily eliminate this is to have read and write wrap - // at twice the size of the underlying array but modulo their values into the array then if write - // has caught up with read it still will not be equal... but lots of modulos... ehh. - - i32 available_space = 0; - if (write >= read){ - available_space = QUEUE_WRAP - (write - read) - 1; - } - else{ - available_space = (read - write) - 1; - } - - return(available_space); -} - -#define UNBOUNDED_SKIP_MAX 128 - -internal i32 -flush_thread_group(Thread_Group_ID group_id){ - Thread_Group *group = threadvars.groups + group_id; - Work_Queue *queue = threadvars.queues + group_id; - Unbounded_Work_Queue *source_queue = &group->queue; - i32 thread_count = group->count; - - // NOTE(allen): It is understood that read_position may be changed by other - // threads but it will only make more space in the queue if it is changed. - // Meanwhile write_position should not ever be changed by anything but the - // main thread in this system, so it will not be interlocked. - u32 read_position = queue->read_position; - u32 write_position = queue->write_position; - u32 available_space = get_work_queue_available_space(write_position, read_position); - u32 available_jobs = source_queue->count - source_queue->skip; - - u32 writable_count = Min(available_space, available_jobs); - - if (writable_count > 0){ - u32 count1 = writable_count; - - if (count1+write_position > QUEUE_WRAP){ - count1 = QUEUE_WRAP - write_position; - } - - u32 count2 = writable_count - count1; - - Full_Job_Data *job_src1 = source_queue->jobs + source_queue->skip; - Full_Job_Data *job_src2 = job_src1 + count1; - - Full_Job_Data *job_dst1 = queue->jobs + write_position; - Full_Job_Data *job_dst2 = queue->jobs; - - Assert((job_src1->id % QUEUE_WRAP) == write_position); - - memcpy(job_dst1, job_src1, sizeof(Full_Job_Data)*count1); - memcpy(job_dst2, job_src2, sizeof(Full_Job_Data)*count2); - queue->write_position = (write_position + writable_count) % QUEUE_WRAP; - - source_queue->skip += writable_count; - - if (source_queue->skip == source_queue->count){ - source_queue->skip = source_queue->count = 0; - } - else if (source_queue->skip > UNBOUNDED_SKIP_MAX){ - u32 left_over = source_queue->count - source_queue->skip; - memmove(source_queue->jobs, source_queue->jobs + source_queue->skip, - sizeof(Full_Job_Data)*left_over); - source_queue->count = left_over; - source_queue->skip = 0; - } - } - - i32 semaphore_release_count = writable_count; - if (semaphore_release_count > thread_count){ - semaphore_release_count = thread_count; - } - - for (i32 i = 0; i < semaphore_release_count; ++i){ - system_release_semaphore(&queue->semaphore); - } - - return(semaphore_release_count); -} - -// Note(allen): post_job puts the job on the unbounded queue. -// The unbounded queue is entirely managed by the main thread. -// The thread safe queue is bounded in size so the unbounded -// queue is periodically flushed into the direct work queue. -internal -Sys_Post_Job_Sig(system_post_job){ - Thread_Group *group = threadvars.groups + group_id; - Unbounded_Work_Queue *queue = &group->queue; - - u32 result = queue->next_job_id++; - - if (queue->count >= queue->max){ - u32 new_max = round_up_pot_u32(queue->count + 1); - Full_Job_Data *new_jobs = (Full_Job_Data*)system_memory_allocate(new_max*sizeof(Full_Job_Data)); - memcpy(new_jobs, queue->jobs, queue->count); - system_memory_free(queue->jobs, queue->max*sizeof(Full_Job_Data)); - queue->jobs = new_jobs; - queue->max = new_max; - } - - Full_Job_Data full_job = {}; - full_job.job = job; - full_job.running_thread = THREAD_NOT_ASSIGNED; - full_job.id = result; - - queue->jobs[queue->count++] = full_job; - flush_thread_group(group_id); - - return(result); -} - -internal -Sys_Cancel_Job_Sig(system_cancel_job){ - Thread_Group *group = threadvars.groups + group_id; - Work_Queue *queue = threadvars.queues + group_id; - - Unbounded_Work_Queue *source_queue = &group->queue; - - b32 handled_in_unbounded = false; - if (source_queue->skip < source_queue->count){ - Full_Job_Data *first_job = source_queue->jobs + source_queue->skip; - if (first_job->id <= job_id){ - u32 index = source_queue->skip + (job_id - first_job->id); - Full_Job_Data *job = source_queue->jobs + index; - job->running_thread = 0; - handled_in_unbounded = true; - } - } - - if (!handled_in_unbounded){ - Full_Job_Data *job = queue->jobs + (job_id % QUEUE_WRAP); - Assert(job->id == job_id); - - u32 thread_id = InterlockedCompareExchange(&job->running_thread, 0, THREAD_NOT_ASSIGNED); - - if (thread_id != THREAD_NOT_ASSIGNED && thread_id != 0){ - i32 thread_index = thread_id - 1; - - i32 cancel_lock_id = group->cancel_lock0 + thread_index; - i32 cancel_cv_id = group->cancel_cv0 + thread_index; - Mutex *cancel_lock = &threadvars.locks[cancel_lock_id]; - Condition_Variable *cancel_cv = &threadvars.conds[cancel_cv_id]; - - Thread_Context *thread = group->threads + thread_index; - - system_acquire_lock(cancel_lock); - thread->cancel = true; - system_release_lock(&threadvars.locks[FRAME_LOCK]); - - do{ - system_wait_cv(cancel_cv, cancel_lock); - }while (thread->cancel); - - system_acquire_lock(&threadvars.locks[FRAME_LOCK]); - system_release_lock(cancel_lock); - } - } -} - -internal -Sys_Check_Cancel_Sig(system_check_cancel){ - Thread_Group *group = threadvars.groups + thread->group_id; - - b32 result = false; - i32 thread_index = thread->id - 1; - i32 cancel_lock_id = group->cancel_lock0 + thread_index; - Mutex *cancel_lock = &threadvars.locks[cancel_lock_id]; - - system_acquire_lock(cancel_lock); - if (thread->cancel){ - result = true; - } - system_release_lock(cancel_lock); - return(result); -} - -internal -Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){ - Mutex *cancel_lock = &threadvars.locks[CANCEL_LOCK0 + memory->id - 1]; - - system_acquire_lock(cancel_lock); - void *old_data = memory->data; - i32 old_size = memory->size; - i32 new_size = round_up_i32(memory->size*2, KB(4)); - memory->data = system_memory_allocate(new_size); - memory->size = new_size; - if (old_data != 0){ - memcpy(memory->data, old_data, old_size); - system_memory_free(old_data, old_size); - } - system_release_lock(cancel_lock); -} - -internal void -work_system_init(){ - AssertThreadSizes(); - - u32 core_count = CORE_COUNT; - Arena thread_arena = make_arena_system(&sysfunc); - - for (i32 i = 0; i < LOCK_COUNT; ++i){ - system_init_lock(&threadvars.locks[i]); - } - - for (i32 i = 0; i < CV_COUNT; ++i){ - system_init_cv(&threadvars.conds[i]); - } - - threadvars.thread_memory = push_array(&thread_arena, Thread_Memory, core_count); - - for (u32 group_i = 0; group_i < THREAD_GROUP_COUNT; ++group_i){ - Thread_Context *threads = push_array(&thread_arena, Thread_Context, core_count); - threadvars.groups[group_i].threads = threads; - threadvars.groups[group_i].count = core_count; - threadvars.groups[group_i].cancel_lock0 = CANCEL_LOCK0; - threadvars.groups[group_i].cancel_cv0 = CANCEL_CV0; - - system_init_semaphore(&threadvars.queues[group_i].semaphore, core_count); - - for (u32 i = 0; i < core_count; ++i){ - Thread_Context *thread = threads + i; - thread->id = i + 1; - thread->group_id = group_i; - - Thread_Memory *memory = &threadvars.thread_memory[i]; - memset(memory, 0, sizeof(*memory)); - memory->id = thread->id; - - thread->queue = &threadvars.queues[group_i]; - system_init_and_launch_thread(&thread->thread, job_thread_proc, thread); - } - - initialize_unbounded_queue(&threadvars.groups[group_i].queue); - } -} - -// BOTTOM - diff --git a/platform_win32/win32_4ed.cpp b/platform_win32/win32_4ed.cpp index badfcb62..c2aa1fdb 100644 --- a/platform_win32/win32_4ed.cpp +++ b/platform_win32/win32_4ed.cpp @@ -71,9 +71,6 @@ win32_output_error_string(i32 error_string_type); #include "4ed_system_shared.h" -#include "4ed_shared_thread_constants.h" -#include "win32_threading_wrapper.h" - #define WM_4coder_ANIMATE (WM_USER + 0) struct Control_Keys{ @@ -119,7 +116,6 @@ global System_Functions sysfunc; #include "win32_library_wrapper.h" #include "4ed_standard_libraries.cpp" -#include "4ed_coroutine.cpp" #include "4ed_font_face.cpp" #include "4ed_mem.cpp" @@ -134,16 +130,25 @@ typedef i32 Win32_Object_Kind; enum{ Win32ObjectKind_ERROR = 0, Win32ObjectKind_Timer = 1, + Win32ObjectKind_Thread = 2, + Win32ObjectKind_Mutex = 3, + Win32ObjectKind_CV = 4, }; struct Win32_Object{ Node node; Win32_Object_Kind kind; union{ - // NOTE(allen): Timer object struct{ UINT_PTR id; } timer; + struct{ + HANDLE thread; + Thread_Function *proc; + void *ptr; + } thread; + CRITICAL_SECTION mutex; + CONDITION_VARIABLE cv; }; }; @@ -187,6 +192,10 @@ struct Win32_Vars{ Node timer_objects; UINT_PTR timer_counter; + CRITICAL_SECTION thread_launch_mutex; + CONDITION_VARIABLE thread_launch_cv; + b32 waiting_for_launch; + u32 log_position; }; @@ -201,8 +210,6 @@ global Libraries libraries; global App_Functions app; global Custom_API custom_api; -global Coroutine_System_Auto_Alloc coroutines; - //////////////////////////////// #include "win32_error_box.cpp" @@ -269,10 +276,6 @@ system_schedule_step(){ //////////////////////////////// -#include "4ed_work_queues.cpp" - -//////////////////////////////// - internal void win32_toggle_fullscreen(){ HWND win = win32vars.window_handle; @@ -324,655 +327,8 @@ Sys_Is_Fullscreen_Sig(system_is_fullscreen){ return(result); } -#include "4ed_coroutine_functions.cpp" - #include "4ed_system_shared.cpp" -// -// File Change Listener -// - -union Directory_Track_Node{ - struct{ - Directory_Track_Node *next; - Directory_Track_Node *prev; - }; - struct{ - OVERLAPPED overlapped; - HANDLE dir_handle; - char buffer[(32 << 10) + 12]; - String_Const_u8 dir_name; - i32 ref_count; - }; -}; - -union File_Track_Node{ - struct{ - File_Track_Node *next; - File_Track_Node *prev; - }; - struct{ - String_Const_u8 file_name; - i32 ref_count; - Directory_Track_Node *parent_dir; - }; -}; -#if !defined(CString_Key_Reference_GAURD) -#define CString_Key_Reference_GAURD -struct CString_Key_Reference{ - char*key; - i32 size; -}; -#endif -struct CString_Ptr_Lookup_Result{ - b32 success; - void **val; -}; -struct CString_Ptr_Table{ - void *mem; - u64 *hashes; - CString_Key_Reference*keys; - void **vals; - i32 count; - i32 dirty_slot_count; - i32 max; -}; - -typedef i32 File_Track_Instruction; -enum{ - FileTrackInstruction_None, - FileTrackInstruction_BeginTracking, - FileTrackInstruction_Cancel, -}; - -union File_Track_Instruction_Node{ - struct{ - File_Track_Instruction instruction; - Directory_Track_Node *dir_node; - }; - struct{ - File_Track_Instruction_Node *next; - File_Track_Instruction_Node *prev; - }; -}; - -struct File_Track_Note_Node{ - File_Track_Note_Node *next; - File_Track_Note_Node *prev; - String_Const_u8 file_name; -}; - -Heap file_track_heap = {}; -Arena file_track_scratch = {}; - -CString_Ptr_Table file_track_dir_table = {}; -Directory_Track_Node *file_track_dir_free_first = 0; -Directory_Track_Node *file_track_dir_free_last = 0; -CString_Ptr_Table file_track_table = {}; -File_Track_Node *file_track_free_first = 0; -File_Track_Node *file_track_free_last = 0; -File_Track_Instruction_Node *file_track_ins_free_first = 0; -File_Track_Instruction_Node *file_track_ins_free_last = 0; -File_Track_Note_Node *file_track_note_first = 0; -File_Track_Note_Node *file_track_note_last = 0; -File_Track_Note_Node *file_track_note_free_first = 0; -File_Track_Note_Node *file_track_note_free_last = 0; - -CRITICAL_SECTION file_track_critical_section; -HANDLE file_track_iocp; -HANDLE file_track_thread; - -global_const u32 file_track_flags = 0 -|FILE_NOTIFY_CHANGE_FILE_NAME -|FILE_NOTIFY_CHANGE_DIR_NAME -|FILE_NOTIFY_CHANGE_ATTRIBUTES -|FILE_NOTIFY_CHANGE_SIZE -|FILE_NOTIFY_CHANGE_LAST_WRITE -|FILE_NOTIFY_CHANGE_CREATION -|FILE_NOTIFY_CHANGE_SECURITY -; - -//////////////////////////////// - -internal CString_Ptr_Table -make_CString_Ptr_table(void *mem, umem size){ - CString_Ptr_Table table = {}; - i32 max = (i32)(size/32ULL); - if (max > 0){ - table.mem = mem; - u8 *cursor = (u8*)mem; - table.hashes = (u64*)cursor; - cursor += 8*max; - table.keys = (CString_Key_Reference*)cursor; - cursor += 16*max; - table.vals = (void **)cursor; - table.count = 0; - table.max = max; - block_fill_ones(table.hashes, sizeof(*table.hashes)*max); - } - return(table); -} - -internal i32 -max_to_memsize_CString_Ptr_table(i32 max){ - return(max*32ULL); -} - -internal b32 -at_max_CString_Ptr_table(CString_Ptr_Table *table){ - if (table->max > 0 && (table->count + 1)*8 <= table->max*7){ - return(false); - } - return(true); -} - -internal b32 -insert_CString_Ptr_table(CString_Ptr_Table *table, char*key, i32 key_size, void **val){ - i32 max = table->max; - if (max > 0){ - i32 count = table->count; - if ((count + 1)*8 <= max*7){ - u64 hash = table_hash_u8((u8*)key, key_size); - if (hash >= 18446744073709551614ULL){ hash += 2; } - i32 first_index = hash%max; - i32 index = first_index; - u64 *hashes = table->hashes; - for (;;){ - if (hashes[index] == 18446744073709551615ULL){ - table->dirty_slot_count += 1; - } - if (hashes[index] == 18446744073709551615ULL || hashes[index] == 18446744073709551614ULL){ - hashes[index] = hash; - CString_Key_Reference new_key = {key, key_size}; - table->keys[index] = new_key; - table->vals[index] = *val; - table->count += 1; - return(true); - } - if (hashes[index] == hash) return(false); - index = (index + 1)%max; - if (index == first_index) return(false); - } - } - } - return(false); -} - -internal CString_Ptr_Lookup_Result -lookup_CString_Ptr_table(CString_Ptr_Table *table, char*key, i32 key_size){ - CString_Ptr_Lookup_Result result = {}; - i32 max = table->max; - if (max > 0){ - u64 hash = table_hash_u8((u8*)key, key_size); - if (hash >= 18446744073709551614ULL){ hash += 2; } - i32 first_index = hash%max; - i32 index = first_index; - u64 *hashes = table->hashes; - for (;;){ - if (hashes[index] == 18446744073709551615ULL) break; - if (hashes[index] == hash){ - CString_Key_Reference *key_check = &table->keys[index]; - b32 key_match = (key_size == key_check->size && block_compare(key, key_check->key, key_size*sizeof(*key)) == 0); - if (key_match){ - result.success = true; - result.val = &table->vals[index]; - return(result); - } - } - index = (index + 1)%max; - if (index == first_index) break; - } - } - return(result); -} - -internal b32 -erase_CString_Ptr_table(CString_Ptr_Table *table, char*key, i32 key_size){ - i32 max = table->max; - if (max > 0 && table->count > 0){ - u64 hash = table_hash_u8((u8*)key, key_size); - if (hash >= 18446744073709551614ULL){ hash += 2; } - i32 first_index = hash%max; - i32 index = first_index; - u64 *hashes = table->hashes; - for (;;){ - if (hashes[index] == 18446744073709551615ULL) break; - if (hashes[index] == hash){ - CString_Key_Reference *key_check = &table->keys[index]; - b32 key_match = (key_size == key_check->size && block_compare(key, key_check->key, key_size*sizeof(*key)) == 0); - if (key_match){ - hashes[index] = 18446744073709551614ULL; - table->count -= 1; - return(true); - } - } - index = (index + 1)%max; - if (index == first_index) break; - } - } - return(false); -} - -internal b32 -move_CString_Ptr_table(CString_Ptr_Table *dst_table, CString_Ptr_Table *src_table){ - if ((src_table->count + dst_table->count)*8 <= dst_table->max*7){ - i32 max = src_table->max; - u64 *hashes = src_table->hashes; - for (i32 index = 0; index < max; index += 1){ - if (hashes[index] != 18446744073709551615ULL && hashes[index] != 18446744073709551614ULL){ - char*key = src_table->keys[index].key; - i32 key_size = src_table->keys[index].size; - void **val = &src_table->vals[index]; - insert_CString_Ptr_table(dst_table, key, key_size, val); - } - } - return(true); - } - return(false); -} - -internal b32 -lookup_CString_Ptr_table(CString_Ptr_Table *table, char *key, i32 key_size, void * *val_out){ - CString_Ptr_Lookup_Result result = lookup_CString_Ptr_table(table, key, key_size); - if (result.success){ - *val_out = *result.val; - } - return(result.success); -} - -internal b32 -insert_CString_Ptr_table(CString_Ptr_Table *table, char*key, i32 key_size, void * val){ - return(insert_CString_Ptr_table(table, key, key_size, &val)); -} - -internal b32 -alloc_insert_CString_Ptr_table(CString_Ptr_Table *table, char*key, i32 key_size, void *val){ - if (at_max_CString_Ptr_table(table)){ - i32 new_max = (table->max + 1)*2; - i32 new_size = max_to_memsize_CString_Ptr_table(new_max); - void *new_mem = system_memory_allocate(new_size); - CString_Ptr_Table new_table = make_CString_Ptr_table(new_mem, new_size); - if (table->mem != 0){ - i32 old_size = max_to_memsize_CString_Ptr_table(table->max); - system_memory_free(table->mem, old_size); - } - *table = new_table; - } - return(insert_CString_Ptr_table(table, key, key_size, val)); -} - -//////////////////////////////// - -internal String_Const_u8 -file_track_store_string_copy(String_Const_u8 string){ - i32 alloc_size = (i32)string.size + 1; - alloc_size = round_up_i32(alloc_size, 16); - char *buffer = (char*)heap_allocate(&file_track_heap, alloc_size); - if (buffer == 0){ - i32 size = MB(1); - void *new_block = system_memory_allocate(size); - heap_extend(&file_track_heap, new_block, size); - buffer = (char*)heap_allocate(&file_track_heap, alloc_size); - } - Assert(buffer != 0); - memcpy(buffer, string.str, string.size); - buffer[string.size] = 0; - return(SCu8(buffer, string.size)); -} - -internal void -file_track_free_string(String_Const_u8 string){ - Assert(string.str != 0); - heap_free(&file_track_heap, string.str); -} - -internal Directory_Track_Node* -file_track_store_new_dir_node(String_Const_u8 dir_name_string, HANDLE dir_handle){ - if (file_track_dir_free_first == 0){ - u32 size = MB(1); - void *new_block = system_memory_allocate(size); - u32 count = size/sizeof(Directory_Track_Node); - Directory_Track_Node *nodes = (Directory_Track_Node*)new_block; - Directory_Track_Node *node = nodes; - node->next = node + 1; - node->prev = 0; - node += 1; - for (u32 i = 1; i < count - 1; i += 1, node += 1){ - node->next = node + 1; - node->prev = node - 1; - } - node->next = 0; - node->prev = node - 1; - file_track_dir_free_first = nodes; - file_track_dir_free_last = node; - } - Directory_Track_Node *new_node = file_track_dir_free_first; - zdll_remove(file_track_dir_free_first, file_track_dir_free_last, new_node); - alloc_insert_CString_Ptr_table(&file_track_dir_table, (char*)dir_name_string.str, (i32)dir_name_string.size, new_node); - memset(&new_node->overlapped, 0, sizeof(new_node->overlapped)); - new_node->dir_handle = dir_handle; - new_node->dir_name = file_track_store_string_copy(dir_name_string); - new_node->ref_count = 0; - return(new_node); -} - -internal void -file_track_free_dir_node(Directory_Track_Node *node){ - erase_CString_Ptr_table(&file_track_dir_table, (char*)node->dir_name.str, (i32)node->dir_name.size); - file_track_free_string(node->dir_name); - memset(&node->dir_name, 0, sizeof(node->dir_name)); - zdll_push_back(file_track_dir_free_first, file_track_dir_free_last, node); -} - -internal File_Track_Node* -file_track_store_new_file_node(String_Const_u8 file_name_string, Directory_Track_Node *existing_dir_node){ - if (file_track_free_first == 0){ - u32 size = KB(16); - void *new_block = system_memory_allocate(size); - u32 count = size/sizeof(File_Track_Node); - File_Track_Node *nodes = (File_Track_Node*)new_block; - File_Track_Node *node = nodes; - node->next = node + 1; - node->prev = 0; - node += 1; - for (u32 i = 1; i < count - 1; i += 1, node += 1){ - node->next = node + 1; - node->prev = node - 1; - } - node->next = 0; - node->prev = node - 1; - file_track_free_first = nodes; - file_track_free_last = node; - } - File_Track_Node *new_node = file_track_free_first; - zdll_remove(file_track_free_first, file_track_free_last, new_node); - alloc_insert_CString_Ptr_table(&file_track_table, (char*)file_name_string.str, (i32)file_name_string.size, new_node); - new_node->file_name = file_track_store_string_copy(file_name_string); - new_node->ref_count = 1; - new_node->parent_dir = existing_dir_node; - existing_dir_node->ref_count += 1; - return(new_node); -} - -internal void -file_track_free_file_node(File_Track_Node *node){ - erase_CString_Ptr_table(&file_track_table, (char*)node->file_name.str, (i32)node->file_name.size); - file_track_free_string(node->file_name); - memset(&node->file_name, 0, sizeof(node->file_name)); - zdll_push_back(file_track_free_first, file_track_free_last, node); -} - -internal File_Track_Note_Node* -file_track_store_new_note_node(String_Const_u8 file_name){ - if (file_track_note_free_first == 0){ - u32 size = KB(16); - void *new_block = system_memory_allocate(size); - u32 count = size/sizeof(File_Track_Note_Node); - File_Track_Note_Node *nodes = (File_Track_Note_Node*)new_block; - File_Track_Note_Node *node = nodes; - node->next = node + 1; - node->prev = 0; - node += 1; - for (u32 i = 1; i < count - 1; i += 1, node += 1){ - node->next = node + 1; - node->prev = node - 1; - } - node->next = 0; - node->prev = node - 1; - file_track_note_free_first = nodes; - file_track_note_free_last = node; - } - File_Track_Note_Node *new_node = file_track_note_free_first; - zdll_remove(file_track_note_free_first, file_track_note_free_last, new_node); - zdll_push_back(file_track_note_first, file_track_note_last, new_node); - new_node->file_name = file_track_store_string_copy(file_name); - return(new_node); -} - -internal void -file_track_free_note_node(File_Track_Note_Node *node){ - file_track_free_string(node->file_name); - memset(&node->file_name, 0, sizeof(node->file_name)); - zdll_remove(file_track_note_first, file_track_note_last, node); - zdll_push_back(file_track_note_free_first, file_track_note_free_last, node); -} - -internal File_Track_Instruction_Node* -file_track_new_instruction_node(){ - if (file_track_ins_free_first == 0){ - u32 size = KB(16); - void *new_block = system_memory_allocate(size); - u32 count = size/sizeof(File_Track_Instruction_Node); - File_Track_Instruction_Node *nodes = (File_Track_Instruction_Node*)new_block; - File_Track_Instruction_Node *node = nodes; - node->next = node + 1; - node->prev = 0; - node += 1; - for (u32 i = 1; i < count - 1; i += 1, node += 1){ - node->next = node + 1; - node->prev = node - 1; - } - node->next = 0; - node->prev = node - 1; - file_track_ins_free_first = nodes; - file_track_ins_free_last = node; - } - File_Track_Instruction_Node *new_node = file_track_ins_free_first; - zdll_remove(file_track_ins_free_first, file_track_ins_free_last, new_node); - return(new_node); -} - -internal void -file_track_free_instruction_node(File_Track_Instruction_Node *node){ - zdll_push_back(file_track_ins_free_first, file_track_ins_free_last, node); -} - -internal Directory_Track_Node* -file_track_dir_lookup(String_Const_u8 dir_name_string){ - void *ptr = 0; - lookup_CString_Ptr_table(&file_track_dir_table, (char*)dir_name_string.str, (i32)dir_name_string.size, &ptr); - return((Directory_Track_Node*)ptr); -} - -internal File_Track_Node* -file_track_file_lookup(String_Const_u8 file_name_string){ - void *ptr = 0; - lookup_CString_Ptr_table(&file_track_table, (char*)file_name_string.str, (i32)file_name_string.size, &ptr); - return((File_Track_Node*)ptr); -} - -internal DWORD CALL_CONVENTION -file_track_worker(void*){ - for (;;){ - DWORD number_of_bytes = 0; - ULONG_PTR key = 0; - OVERLAPPED *overlapped = 0; - if (GetQueuedCompletionStatus(file_track_iocp, &number_of_bytes, &key, &overlapped, INFINITE)){ - EnterCriticalSection(&file_track_critical_section); - if (number_of_bytes == 0 && key == 0){ - File_Track_Instruction_Node *instruction = (File_Track_Instruction_Node*)overlapped; - switch (instruction->instruction){ - case FileTrackInstruction_None: - {}break; - case FileTrackInstruction_BeginTracking: - { - Directory_Track_Node *dir_node = instruction->dir_node; - CreateIoCompletionPort(dir_node->dir_handle, file_track_iocp, (ULONG_PTR)&dir_node->overlapped, 1); - ReadDirectoryChangesW(dir_node->dir_handle, dir_node->buffer, sizeof(dir_node->buffer), FALSE, - file_track_flags, 0, &dir_node->overlapped, 0); - }break; - case FileTrackInstruction_Cancel: - { - Directory_Track_Node *dir_node = instruction->dir_node; - CancelIo(dir_node->dir_handle); - CloseHandle(dir_node->dir_handle); - file_track_free_dir_node(dir_node); - }break; - } - file_track_free_instruction_node(instruction); - } - else if (number_of_bytes != 0 && key != 0){ - Directory_Track_Node *dir_node = (Directory_Track_Node*)overlapped; - Directory_Track_Node node_copy = *dir_node; - memset(&dir_node->overlapped, 0, sizeof(dir_node->overlapped)); - ReadDirectoryChangesW(dir_node->dir_handle, dir_node->buffer, sizeof(dir_node->buffer), FALSE, - file_track_flags, 0, &dir_node->overlapped, 0); - - FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION*)node_copy.buffer; - - i32 len = info->FileNameLength/2; - i32 dir_len = GetFinalPathNameByHandle_utf8(&file_track_scratch, dir_node->dir_handle, 0, 0, FILE_NAME_NORMALIZED); - - i32 req_size = dir_len + (len + 1)*2 + 4; - - Temp_Memory temp = begin_temp(&file_track_scratch); - u8 *buffer = push_array(&file_track_scratch, u8, req_size); - - if (buffer != 0){ - u32 path_pos = GetFinalPathNameByHandle_utf8(&file_track_scratch, dir_node->dir_handle, buffer, req_size, FILE_NAME_NORMALIZED); - buffer[path_pos] = '\\'; - path_pos += 1; - - u32 name_max = req_size - path_pos; - u8 *name_buffer = buffer + path_pos; - - b32 convert_error = false; - u32 name_pos = (u32)utf16_to_utf8_minimal_checking(name_buffer, name_max, (u16*)info->FileName, len, &convert_error); - if (name_pos < name_max && !convert_error){ - u32 pos = path_pos + name_pos; - if (buffer[0] == '\\'){ - for (u32 i = 0; i + 4 < pos; i += 1){ - buffer[i] = buffer[i + 4]; - } - pos -= 4; - } - String_Const_u8 file_name = SCu8(buffer, pos); - file_track_store_new_note_node(file_name); - - system_schedule_step(); - } - } - - end_temp(temp); - } - LeaveCriticalSection(&file_track_critical_section); - } - } -} - -internal void -file_track_init(){ - heap_init(&file_track_heap); - file_track_scratch = make_arena_system(&sysfunc); - InitializeCriticalSection(&file_track_critical_section); - file_track_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1); - file_track_thread = CreateThread(0, 0, file_track_worker, 0, 0, 0); -} - -internal -Sys_Add_Listener_Sig(system_add_listener){ - b32 added_new_listener = false; - - EnterCriticalSection(&file_track_critical_section); - - String_Const_u8 file_name_string = SCu8(filename); - File_Track_Node *existing_file_node = file_track_file_lookup(file_name_string); - - if (existing_file_node != 0){ - existing_file_node->ref_count += 1; - added_new_listener = true; - } - else{ - String_Const_u8 dir_name_string = string_remove_last_folder(file_name_string); - Directory_Track_Node *existing_dir_node = file_track_dir_lookup(dir_name_string); - - if (existing_dir_node == 0){ - Temp_Memory temp = begin_temp(&file_track_scratch); - String_Const_u8 dir_name_string_terminated = push_string_copy(&file_track_scratch, dir_name_string); - HANDLE dir_handle = CreateFile_utf8(&file_track_scratch, (u8*)dir_name_string_terminated.str, - FILE_LIST_DIRECTORY, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, 0); - - if (dir_handle != 0 && dir_handle != INVALID_HANDLE_VALUE){ - Directory_Track_Node *new_node = file_track_store_new_dir_node(dir_name_string, dir_handle); - File_Track_Instruction_Node *instruction_node = file_track_new_instruction_node(); - instruction_node->instruction = FileTrackInstruction_BeginTracking; - instruction_node->dir_node = new_node; - PostQueuedCompletionStatus(file_track_iocp, 0, 0, (LPOVERLAPPED)instruction_node); - existing_dir_node = new_node; - } - - end_temp(temp); - } - - if (existing_dir_node != 0){ - file_track_store_new_file_node(file_name_string, existing_dir_node); - added_new_listener = true; - } - } - - LeaveCriticalSection(&file_track_critical_section); - - return(added_new_listener); -} - -internal -Sys_Remove_Listener_Sig(system_remove_listener){ - b32 removed_listener = false; - - EnterCriticalSection(&file_track_critical_section); - - String_Const_u8 file_name_string = SCu8(filename); - File_Track_Node *existing_file_node = file_track_file_lookup(file_name_string); - - if (existing_file_node != 0){ - existing_file_node->ref_count -= 1; - if (existing_file_node->ref_count == 0){ - Directory_Track_Node *existing_dir_node = existing_file_node->parent_dir; - existing_dir_node->ref_count -= 1; - if (existing_dir_node->ref_count == 0){ - File_Track_Instruction_Node *instruction_node = file_track_new_instruction_node(); - instruction_node->instruction = FileTrackInstruction_Cancel; - instruction_node->dir_node = existing_dir_node; - PostQueuedCompletionStatus(file_track_iocp, 0, 0, (LPOVERLAPPED)instruction_node); - } - file_track_free_file_node(existing_file_node); - } - removed_listener = true; - } - - LeaveCriticalSection(&file_track_critical_section); - - return(removed_listener); -} - -internal -Sys_Get_File_Change_Sig(system_get_file_change){ - b32 has_or_got_a_change = false; - - EnterCriticalSection(&file_track_critical_section); - - if (file_track_note_first != 0){ - has_or_got_a_change = true; - File_Track_Note_Node *node = file_track_note_first; - *required_size = (i32)node->file_name.size + 1; - if (node->file_name.size < max){ - memcpy(buffer, node->file_name.str, node->file_name.size); - buffer[node->file_name.size] = 0; - file_track_free_note_node(node); - } - else{ - *mem_too_small = true; - } - } - - LeaveCriticalSection(&file_track_critical_section); - - return(has_or_got_a_change); -} - // // Clipboard // @@ -1468,7 +824,7 @@ Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ } internal Win32_Object* -win32_alloc_object(void){ +win32_alloc_object(Win32_Object_Kind kind){ Win32_Object *result = 0; if (win32vars.free_win32_objects.next != &win32vars.free_win32_objects){ result = CastFromMember(Win32_Object, node, win32vars.free_win32_objects.next); @@ -1488,6 +844,8 @@ win32_alloc_object(void){ } Assert(result != 0); dll_remove(&result->node); + block_zero_struct(result); + result->kind = kind; return(result); } @@ -1499,6 +857,8 @@ win32_free_object(Win32_Object *object){ dll_insert(&win32vars.free_win32_objects, &object->node); } +//////////////////////////////// + internal Sys_Now_Time_Sig(system_now_time){ u64 result = 0; @@ -1511,10 +871,8 @@ Sys_Now_Time_Sig(system_now_time){ internal Sys_Wake_Up_Timer_Create_Sig(system_wake_up_timer_create){ - Win32_Object *object = win32_alloc_object(); - block_zero_struct(object); + Win32_Object *object = win32_alloc_object(Win32ObjectKind_Timer); dll_insert(&win32vars.timer_objects, &object->node); - object->kind = Win32ObjectKind_Timer; object->timer.id = ++win32vars.timer_counter; return(handle_type(object)); } @@ -1536,6 +894,118 @@ Sys_Wake_Up_Timer_Set_Sig(system_wake_up_timer_set){ } } +//////////////////////////////// + +internal DWORD +win32_thread_wrapper(void *ptr){ + Win32_Object *object = (Win32_Object*)ptr; + Thread_Function *proc = object->thread.proc; + void *object_ptr = object->thread.ptr; + win32vars.waiting_for_launch = false; + WakeConditionVariable(&win32vars.thread_launch_cv); + proc(object_ptr); + return(0); +} + +internal +Sys_Thread_Launch_Sig(system_thread_launch){ + Win32_Object *object = win32_alloc_object(Win32ObjectKind_Thread); + object->thread.proc = proc; + object->thread.ptr = ptr; + EnterCriticalSection(&win32vars.thread_launch_mutex); + win32vars.waiting_for_launch = true; + object->thread.thread = CreateThread(0, 0, win32_thread_wrapper, object, 0, 0); + for (;win32vars.waiting_for_launch;){ + SleepConditionVariableCS(&win32vars.thread_launch_cv, &win32vars.thread_launch_mutex, INFINITE); + } + LeaveCriticalSection(&win32vars.thread_launch_mutex); + return(handle_type(object)); +} + +internal +Sys_Thread_Join_Sig(system_thread_join){ + Win32_Object *object = (Win32_Object*)handle_type_ptr(thread); + if (object->kind == Win32ObjectKind_Thread){ + WaitForSingleObject(object->thread.thread, INFINITE); + } +} + +internal +Sys_Thread_Free_Sig(system_thread_free){ + Win32_Object *object = (Win32_Object*)handle_type_ptr(thread); + if (object->kind == Win32ObjectKind_Thread){ + CloseHandle(object->thread.thread); + win32_free_object(object); + } +} + +internal +Sys_Mutex_Make_Sig(system_mutex_make){ + Win32_Object *object = win32_alloc_object(Win32ObjectKind_Mutex); + InitializeCriticalSection(&object->mutex); + return(handle_type(object)); +} + +internal +Sys_Mutex_Acquire_Sig(system_mutex_acquire){ + Win32_Object *object = (Win32_Object*)handle_type_ptr(mutex); + if (object->kind == Win32ObjectKind_Mutex){ + EnterCriticalSection(&object->mutex); + } +} + +internal +Sys_Mutex_Release_Sig(system_mutex_release){ + Win32_Object *object = (Win32_Object*)handle_type_ptr(mutex); + if (object->kind == Win32ObjectKind_Mutex){ + LeaveCriticalSection(&object->mutex); + } +} + +internal +Sys_Mutex_Free_Sig(system_mutex_free){ + Win32_Object *object = (Win32_Object*)handle_type_ptr(mutex); + if (object->kind == Win32ObjectKind_Mutex){ + DeleteCriticalSection(&object->mutex); + win32_free_object(object); + } +} + +internal +Sys_Condition_Variable_Make_Sig(system_condition_variable_make){ + Win32_Object *object = win32_alloc_object(Win32ObjectKind_CV); + InitializeConditionVariable(&object->cv); + return(handle_type(object)); +} + +internal +Sys_Condition_Variable_Wait_Sig(system_condition_variable_wait){ + Win32_Object *object_cv = (Win32_Object*)handle_type_ptr(cv); + Win32_Object *object_mutex = (Win32_Object*)handle_type_ptr(mutex); + if (object_cv->kind == Win32ObjectKind_CV && + object_mutex->kind == Win32ObjectKind_Mutex){ + SleepConditionVariableCS(&object_cv->cv, &object_mutex->mutex, INFINITE); + } +} + +internal +Sys_Condition_Variable_Signal_Sig(system_condition_variable_signal){ + Win32_Object *object = (Win32_Object*)handle_type_ptr(cv); + if (object->kind == Win32ObjectKind_CV){ + WakeConditionVariable(&object->cv); + } +} + +internal +Sys_Condition_Variable_Free_Sig(system_condition_variable_free){ + Win32_Object *object = (Win32_Object*)handle_type_ptr(cv); + if (object->kind == Win32ObjectKind_CV){ + win32_free_object(object); + } +} + +//////////////////////////////// + internal LRESULT win32_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ LRESULT result = 0; @@ -2065,6 +1535,9 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS dll_init_sentinel(&win32vars.free_win32_objects); dll_init_sentinel(&win32vars.timer_objects); + InitializeCriticalSection(&win32vars.thread_launch_mutex); + InitializeConditionVariable(&win32vars.thread_launch_cv); + // // HACK(allen): // Previously zipped stuff is here, it should be zipped in the new pattern now. @@ -2072,11 +1545,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS init_shared_vars(); - // - // Init Filetrack - // - file_track_init(); - // // Load Core Code // @@ -2097,18 +1565,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS custom_api.get_bindings = get_bindings; #endif - // - // Threads - // - - work_system_init(); - - // - // Coroutines - // - - coroutines_init(); - // // Window and GL Initialization // @@ -2132,54 +1588,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS window_style |= WS_MAXIMIZE; } -#if 0 - WNDCLASS window_class = {}; - window_class.style = CS_HREDRAW|CS_VREDRAW; - window_class.lpfnWndProc = (WNDPROC)(win32_proc); - window_class.hInstance = hInstance; - window_class.lpszClassName = L"4coder-win32-wndclass"; - window_class.hIcon = LoadIcon(hInstance, L"main"); - - if (!RegisterClass(&window_class)){ - exit(1); - } - - i32 window_x = CW_USEDEFAULT; - i32 window_y = CW_USEDEFAULT; - - if (plat_settings.set_window_pos){ - window_x = plat_settings.window_x; - window_y = plat_settings.window_y; - //LOGF("Setting window position (%d, %d)\n", window_x, window_y); - } - - //LOG("Creating window... "); - win32vars.window_handle = CreateWindowEx(0, window_class.lpszClassName, L_WINDOW_NAME, window_style, window_x, window_y, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, 0, 0, hInstance, 0); - - if (win32vars.window_handle == 0){ - //LOG("Failed\n"); - exit(1); - } - else{ - //LOG("Success\n"); - } - - { - HDC hdc = GetDC(win32vars.window_handle); - - // TODO(allen): not Windows XP compatible, how do I handle that? - SetProcessDPIAware(); - win32vars.dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); - win32vars.dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); - - GetClientRect(win32vars.window_handle, &window_rect); - - win32_init_gl(hdc); - - ReleaseDC(win32vars.window_handle, hdc); - } -#endif - HGLRC window_opengl_context = 0; if (!win32_gl_create_window(&win32vars.window_handle, &window_opengl_context, window_style, window_rect)){ //LOG("Window creation failed\n"); @@ -2266,7 +1674,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS //LOG("Beginning main loop\n"); u64 timer_start = system_now_time(); - system_acquire_lock(FRAME_LOCK); MSG msg; for (;keep_running;){ // TODO(allen): Find a good way to wait on a pipe @@ -2274,8 +1681,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS // NOTE(allen): Looks like we can ReadFile with a // size of zero in an IOCP for this effect. if (!win32vars.first){ - system_release_lock(FRAME_LOCK); - if (win32vars.running_cli == 0){ win32vars.got_useful_event = false; } @@ -2354,8 +1759,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS } } }while (get_more_messages); - - system_acquire_lock(FRAME_LOCK); } // NOTE(allen): Mouse Out of Window Detection @@ -2520,12 +1923,9 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS } // NOTE(allen): sleep a bit to cool off :) - flush_thread_group(BACKGROUND_THREADS); - u64 timer_end = system_now_time(); u64 end_target = timer_start + frame_useconds; - system_release_lock(FRAME_LOCK); for (;timer_end < end_target;){ DWORD samount = (DWORD)((end_target - timer_end)/1000); if (samount > 0){ @@ -2533,7 +1933,6 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS } timer_end = system_now_time(); } - system_acquire_lock(FRAME_LOCK); timer_start = system_now_time(); win32vars.first = false; diff --git a/platform_win32/win32_threading_wrapper.h b/platform_win32/win32_threading_wrapper.h deleted file mode 100644 index 7a319aaa..00000000 --- a/platform_win32/win32_threading_wrapper.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 18.07.2017 - * - * Win32 threading wrapper - * - */ - -// TOP - -#if !defined(WIN32_THREADING_WRAPPER) -#define WIN32_THREADING_WRAPPER - -#define PLAT_THREAD_SIG(n) DWORD CALL_CONVENTION n(LPVOID ptr) -typedef PLAT_THREAD_SIG(Thread_Function); - -union Thread{ - HANDLE t; - FixSize(THREAD_TYPE_SIZE); -}; - -union Mutex{ - CRITICAL_SECTION crit; - FixSize(MUTEX_TYPE_SIZE); -}; - -union Condition_Variable{ - CONDITION_VARIABLE cv; - FixSize(CONDITION_VARIABLE_TYPE_SIZE); -}; - -union Semaphore{ - HANDLE s; - FixSize(SEMAPHORE_TYPE_SIZE); -}; - - -internal void -system_init_and_launch_thread(Thread *t, Thread_Function *proc, void *ptr){ - t->t = CreateThread(0, 0, proc, ptr, 0, 0); -} - -internal void -system_init_lock(Mutex *m){ - InitializeCriticalSection(&m->crit); -} - -internal void -system_acquire_lock(Mutex *m){ - EnterCriticalSection(&m->crit); -} - -internal void -system_release_lock(Mutex *m){ - LeaveCriticalSection(&m->crit); -} - -internal void -system_init_cv(Condition_Variable *cv){ - InitializeConditionVariable(&cv->cv); -} - -internal void -system_wait_cv(Condition_Variable *cv, Mutex *lock){ - SleepConditionVariableCS(&cv->cv, &lock->crit, INFINITE); -} - -internal void -system_signal_cv(Condition_Variable *cv, Mutex *lock){ - WakeConditionVariable(&cv->cv); -} - -internal void -system_init_semaphore(Semaphore *s, u32 max){ - s->s = CreateSemaphore(0, 0, max, 0); -} - -internal void -system_wait_on_semaphore(Semaphore *s){ - WaitForSingleObject(s->s, INFINITE); -} - -internal void -system_release_semaphore(Semaphore *s){ - ReleaseSemaphore(s->s, 1, 0); -} - -#endif - -// BOTTOM -