From e4a46080070346583a8c1828f2d8734a4b50d090 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Wed, 19 Jul 2017 16:07:50 -0400 Subject: [PATCH] almost finished with a generalized coroutine solution --- 4ed.cpp | 64 ++--- 4ed.h | 10 +- 4ed_api_implementation.cpp | 4 +- 4ed_app_models.h | 2 +- 4ed_system.h | 18 +- 4ed_view.cpp | 2 +- meta/4ed_file_moving.h | 65 ++--- platform_all/4ed_coroutine.cpp | 253 ++++++++++++++++++++ platform_all/4ed_shared_init_logic.cpp | 22 +- platform_all/4ed_shared_library_constants.h | 3 +- platform_all/4ed_work_queues.cpp | 2 +- platform_linux/linux_4ed.cpp | 159 ++++-------- platform_win32/win32_4ed.cpp | 188 ++++++--------- platform_win32/win32_4ed_functions.cpp | 6 + 14 files changed, 477 insertions(+), 321 deletions(-) create mode 100644 platform_all/4ed_coroutine.cpp diff --git a/4ed.cpp b/4ed.cpp index d3f2bf3c..cd00f144 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -304,9 +304,9 @@ restore_state(Application_Links *app, App_Coroutine_State state){ app->type_coroutine = state.type; } -inline Coroutine* -app_launch_coroutine(System_Functions *system, Application_Links *app, Coroutine_Type type, Coroutine *co, void *in, void *out){ - Coroutine* result = 0; +inline Coroutine_Head* +app_launch_coroutine(System_Functions *system, Application_Links *app, Coroutine_Type type, Coroutine_Head *co, void *in, void *out){ + Coroutine_Head *result = 0; App_Coroutine_State prev_state = get_state(app); @@ -318,9 +318,9 @@ app_launch_coroutine(System_Functions *system, Application_Links *app, Coroutine return(result); } -inline Coroutine* -app_resume_coroutine(System_Functions *system, Application_Links *app, Coroutine_Type type, Coroutine *co, void *in, void *out){ - Coroutine* result = 0; +inline Coroutine_Head* +app_resume_coroutine(System_Functions *system, Application_Links *app, Coroutine_Type type, Coroutine_Head *co, void *in, void *out){ + Coroutine_Head *result = 0; App_Coroutine_State prev_state = get_state(app); @@ -614,7 +614,7 @@ struct Command_In{ }; internal void -command_caller(Coroutine *coroutine){ +command_caller(Coroutine_Head *coroutine){ Command_In *cmd_in = (Command_In*)coroutine->in; Command_Data *command = cmd_in->cmd; Models *models = command->models; @@ -778,19 +778,19 @@ enum Command_Line_Mode{ }; internal void -init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, Command_Line_Parameters clparams){ +init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, i32 argc, char **argv){ char *arg = 0; Command_Line_Mode mode = CLMode_App; Command_Line_Action action = CLAct_Nothing; b32 strict = false; settings->init_files_max = ArrayCount(settings->init_files); - for (i32 i = 1; i <= clparams.argc; ++i){ - if (i == clparams.argc){ + for (i32 i = 1; i <= argc; ++i){ + if (i == argc){ arg = ""; } else{ - arg = clparams.argv[i]; + arg = argv[i]; } if (arg[0] == '-' && arg[1] == '-'){ @@ -838,27 +838,27 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, case CLAct_CustomDLL: { plat_settings->custom_dll_is_strict = (b8)strict; - if (i < clparams.argc){ - plat_settings->custom_dll = clparams.argv[i]; + if (i < argc){ + plat_settings->custom_dll = argv[i]; } action = CLAct_Nothing; }break; case CLAct_InitialFilePosition: { - if (i < clparams.argc){ - settings->initial_line = str_to_int_c(clparams.argv[i]); + if (i < argc){ + settings->initial_line = str_to_int_c(argv[i]); } action = CLAct_Nothing; }break; case CLAct_WindowSize: { - if (i + 1 < clparams.argc){ + if (i + 1 < argc){ plat_settings->set_window_size = true; - i32 w = str_to_int_c(clparams.argv[i]); - i32 h = str_to_int_c(clparams.argv[i+1]); + i32 w = str_to_int_c(argv[i]); + i32 h = str_to_int_c(argv[i+1]); if (w > 0){ plat_settings->window_w = w; } @@ -880,11 +880,11 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, case CLAct_WindowPosition: { - if (i + 1 < clparams.argc){ + if (i + 1 < argc){ plat_settings->set_window_pos = true; - i32 x = str_to_int_c(clparams.argv[i]); - i32 y = str_to_int_c(clparams.argv[i+1]); + i32 x = str_to_int_c(argv[i]); + i32 y = str_to_int_c(argv[i+1]); if (x > 0){ plat_settings->window_x = x; } @@ -906,8 +906,8 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, case CLAct_FontSize: { - if (i < clparams.argc){ - plat_settings->font_size = str_to_int_c(clparams.argv[i]); + if (i < argc){ + plat_settings->font_size = str_to_int_c(argv[i]); plat_settings->font_size = clamp_bottom(8, plat_settings->font_size); } action = CLAct_Nothing; @@ -935,9 +935,9 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, case CLMode_Custom: { - settings->custom_flags = clparams.argv + i; - settings->custom_flags_count = clparams.argc - i; - i = clparams.argc; + settings->custom_flags = argv + i; + settings->custom_flags_count = argc - i; + i = argc; mode = CLMode_App; }break; } @@ -969,8 +969,8 @@ App_Read_Command_Line_Sig(app_read_command_line){ *settings = null_app_settings; plat_settings->font_size = 16; - if (clparams.argc > 1){ - init_command_line_settings(&vars->models.settings, plat_settings, clparams); + if (argc > 1){ + init_command_line_settings(&vars->models.settings, plat_settings, argc, argv); } *files = vars->models.settings.init_files; @@ -1623,11 +1623,11 @@ App_Step_Sig(app_step){ } if (there_is_unsaved){ - Coroutine *command_coroutine = models->command_coroutine; + Coroutine_Head *command_coroutine = models->command_coroutine; Command_Data *command = cmd; USE_VIEW(view); - for (i32 i = 0; i < 128 && command_coroutine; ++i){ + for (i32 i = 0; i < 128 && command_coroutine != 0; ++i){ User_Input user_in = {0}; user_in.abort = true; @@ -1686,7 +1686,7 @@ App_Step_Sig(app_step){ // NOTE(allen): Keyboard and Mouse input to command coroutine. if (models->command_coroutine != 0){ - Coroutine *command_coroutine = models->command_coroutine; + Coroutine_Head *command_coroutine = models->command_coroutine; u32 get_flags = models->command_coroutine_flags[0]; u32 abort_flags = models->command_coroutine_flags[1]; @@ -1969,7 +1969,7 @@ App_Step_Sig(app_step){ } Assert(models->command_coroutine == 0); - Coroutine *command_coroutine = system->create_coroutine(command_caller); + Coroutine_Head *command_coroutine = system->create_coroutine(command_caller); models->command_coroutine = command_coroutine; Command_In cmd_in; diff --git a/4ed.h b/4ed.h index c3fd1dc3..f1841801 100644 --- a/4ed.h +++ b/4ed.h @@ -46,11 +46,6 @@ struct Input_Summary{ f32 dt; }; -struct Command_Line_Parameters{ - char **argv; - int32_t argc; -}; - typedef u8 Log_To_Type; enum{ LogTo_Nothing, @@ -77,7 +72,7 @@ struct Plat_Settings{ }; #define App_Read_Command_Line_Sig(name) \ -i32 name(System_Functions *system, Application_Memory *memory, String current_directory, Plat_Settings *plat_settings, char ***files, i32 **file_count, Command_Line_Parameters clparams) +i32 name(System_Functions *system, Application_Memory *memory, String current_directory, Plat_Settings *plat_settings, char ***files, i32 **file_count, i32 argc, char **argv) typedef App_Read_Command_Line_Sig(App_Read_Command_Line); @@ -123,8 +118,7 @@ name(System_Functions *system, \ Render_Target *target, \ Application_Memory *memory, \ Application_Step_Input *input, \ -Application_Step_Result *app_result_, \ -Command_Line_Parameters params) +Application_Step_Result *app_result_) typedef App_Step_Sig(App_Step); diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index 0c85a9ce..59ee4a44 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -2069,11 +2069,11 @@ DOC_SEE(User_Input) */{ Command_Data *cmd = (Command_Data*)app->cmd_context; System_Functions *system = cmd->system; - Coroutine *coroutine = (Coroutine*)app->current_coroutine; + Coroutine_Head *coroutine = (Coroutine_Head*)app->current_coroutine; User_Input result = {0}; if (app->type_coroutine == Co_Command){ - Assert(coroutine); + Assert(coroutine != 0); *((u32*)coroutine->out+0) = get_type; *((u32*)coroutine->out+1) = abort_type; system->yield_coroutine(coroutine); diff --git a/4ed_app_models.h b/4ed_app_models.h index baf051b2..d349bae8 100644 --- a/4ed_app_models.h +++ b/4ed_app_models.h @@ -57,7 +57,7 @@ struct Models{ Command_Binding prev_command; - Coroutine *command_coroutine; + Coroutine_Head *command_coroutine; u32 command_coroutine_flags[2]; Hook_Function *hooks[hook_type_count]; diff --git a/4ed_system.h b/4ed_system.h index e87cf336..db5a9e37 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -90,27 +90,25 @@ typedef Sys_CLI_Update_Step_Sig(System_CLI_Update_Step); typedef Sys_CLI_End_Update_Sig(System_CLI_End_Update); // coroutine -#define Coroutine_Function_Sig(name) void name(struct Coroutine *coroutine) -typedef Coroutine_Function_Sig(Coroutine_Function); -struct Coroutine{ - Plat_Handle plat_handle; - Coroutine_Function *func; - void *yield_handle; +struct Coroutine_Head{ void *in; void *out; }; -#define Sys_Create_Coroutine_Sig(name) Coroutine *name(Coroutine_Function *func) +#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 *name(Coroutine *coroutine, void *in, void *out) +#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 *name(Coroutine *coroutine, void *in, void *out) +#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 *coroutine) +#define Sys_Yield_Coroutine_Sig(name) void name(Coroutine_Head *head) typedef Sys_Yield_Coroutine_Sig(System_Yield_Coroutine); // thread diff --git a/4ed_view.cpp b/4ed_view.cpp index 4ba8c0f5..ef2fd89d 100644 --- a/4ed_view.cpp +++ b/4ed_view.cpp @@ -14,7 +14,7 @@ struct View_Persistent{ i32 id; - Coroutine *coroutine; + Coroutine_Head *coroutine; Event_Message message_passing_slot; }; diff --git a/meta/4ed_file_moving.h b/meta/4ed_file_moving.h index 8b7a1389..a2222a60 100644 --- a/meta/4ed_file_moving.h +++ b/meta/4ed_file_moving.h @@ -1,8 +1,11 @@ /* -4tech_file_moving.h - Code for moving files around on the file system. -By Allen Webster -21.01.2017 (dd.mm.yyyy) -*/ + * Mr. 4th Dimention - Allen Webster + * + * 21.01.2017 + * + * Moving files around on the file system. + * + */ // TOP @@ -302,9 +305,9 @@ extern "C"{ #define FILE_ATTRIBUTE_NORMAL 0x00000080 #define FILE_ATTRIBUTE_TEMPORARY 0x00000100 -static u64 perf_frequency; +global u64 perf_frequency; -static void +internal void fm_init_system(){ LARGE_INTEGER lint; if (QueryPerformanceFrequency(&lint)){ @@ -313,7 +316,7 @@ fm_init_system(){ fm__init_memory(); } -static Temp_Dir +internal Temp_Dir fm_pushdir(char *dir){ Temp_Dir temp = {0}; GetCurrentDirectoryA(sizeof(temp.dir), temp.dir); @@ -321,12 +324,12 @@ fm_pushdir(char *dir){ return(temp); } -static void +internal void fm_popdir(Temp_Dir temp){ SetCurrentDirectoryA(temp.dir); } -static u64 +internal u64 fm_get_time(){ u64 time = 0; LARGE_INTEGER lint; @@ -337,13 +340,13 @@ fm_get_time(){ return(time); } -static i32 +internal i32 fm_get_current_directory(char *buffer, i32 max){ i32 result = GetCurrentDirectoryA(max, buffer); return(result); } -static void +internal void fm_execute_in_dir(char *dir, char *str, char *args){ if (dir){ Temp_Dir temp = fm_pushdir(dir); @@ -365,7 +368,7 @@ fm_execute_in_dir(char *dir, char *str, char *args){ } } -static void +internal void fm_slash_fix(char *path){ if (path != 0){ for (i32 i = 0; path[i]; ++i){ @@ -374,7 +377,7 @@ fm_slash_fix(char *path){ } } -static void +internal void fm_make_folder_if_missing(char *dir){ char *path = fm_str(dir); char *p = path; @@ -388,23 +391,23 @@ fm_make_folder_if_missing(char *dir){ CreateDirectoryA(path, 0); } -static void +internal void fm_clear_folder(char *folder){ fprintf(stdout, "clearing folder %s\n", folder); systemf("del /S /Q /F %s\\* > nul & rmdir /S /Q %s > nul & mkdir %s > nul", folder, folder, folder); } -static void +internal void fm_delete_file(char *file){ systemf("del %s", file); } -static void +internal void fm_copy_file(char *file, char *newname){ CopyFileA(file, newname, 0); } -static void +internal void fm_copy_all(char *source, char *tag, char *folder){ if (source){ fprintf(stdout, "copy %s\\%s to %s\n", source, tag, folder); @@ -433,7 +436,7 @@ fm_write_file(char *file_name, char *data, u32 size){ } } -static void +internal void fm_zip(char *parent, char *folder, char *dest){ char cdir[512]; fm_get_current_directory(cdir, sizeof(cdir)); @@ -454,7 +457,7 @@ fm_zip(char *parent, char *folder, char *dest){ #include #include -static Temp_Dir +internal Temp_Dir fm_pushdir(char *dir){ Temp_Dir temp; char *result = getcwd(temp.dir, sizeof(temp.dir)); @@ -467,17 +470,17 @@ fm_pushdir(char *dir){ return(temp); } -static void +internal void fm_popdir(Temp_Dir temp){ chdir(temp.dir); } -static void +internal void fm_init_system(){ fm__init_memory(); } -static u64 +internal u64 fm_get_time(){ struct timespec spec; u64 result; @@ -486,7 +489,7 @@ fm_get_time(){ return(result); } -static i32 +internal i32 fm_get_current_directory(char *buffer, i32 max){ i32 result = 0; char *d = getcwd(buffer, max); @@ -496,7 +499,7 @@ fm_get_current_directory(char *buffer, i32 max){ return(result); } -static void +internal void fm_execute_in_dir(char *dir, char *str, char *args){ if (dir){ if (args){ @@ -520,31 +523,31 @@ fm_execute_in_dir(char *dir, char *str, char *args){ } } -static void +internal void fm_slash_fix(char *path){} -static void +internal void fm_make_folder_if_missing(char *dir){ systemf("mkdir -p %s", dir); } -static void +internal void fm_clear_folder(char *folder){ fprintf(stdout, "clearing folder %s\n", folder); systemf("rm -rf %s* > /dev/null", folder); } -static void +internal void fm_delete_file(char *file){ systemf("rm %s", file); } -static void +internal void fm_copy_file(char *file, char *newname){ systemf("cp %s %s", file, newname); } -static void +internal void fm_copy_all(char *source, char *tag, char *folder){ if (source){ fprintf(stdout, "copy %s/%s to %s\n", source, tag, folder); @@ -566,7 +569,7 @@ fm_write_file(char *file_name, char *data, u32 size){ } } -static void +internal void fm_zip(char *parent, char *folder, char *file){ Temp_Dir temp = fm_pushdir(parent); printf("PARENT DIR: %s\n", parent); diff --git a/platform_all/4ed_coroutine.cpp b/platform_all/4ed_coroutine.cpp new file mode 100644 index 00000000..f9012344 --- /dev/null +++ b/platform_all/4ed_coroutine.cpp @@ -0,0 +1,253 @@ +/* + * 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); +} + +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_shared_init_logic.cpp b/platform_all/4ed_shared_init_logic.cpp index 84f0517d..e2755902 100644 --- a/platform_all/4ed_shared_init_logic.cpp +++ b/platform_all/4ed_shared_init_logic.cpp @@ -10,7 +10,7 @@ // TOP internal void -system_memory_init(){ +memory_init(){ #if defined(FRED_INTERNAL) # if defined(FTECH_64_BIT) void *bases[] = { (void*)TB(1), (void*)TB(2), }; @@ -120,5 +120,25 @@ load_custom_code(){ LOGF("Loaded custom file: %s\n", success_file); } +internal void +read_command_line(i32 argc, char **argv){ + LOG("Reading command line\n"); + char cwd[4096]; + u32 size = sysfunc.get_current_path(cwd, sizeof(cwd)); + if (size == 0 || size >= sizeof(cwd)){ + system_error_box("Could not get current directory at launch."); + } + + String curdir = make_string_cap(cwd, size, sizeof(cwd)); + terminate_with_null(&curdir); + replace_char(&curdir, '\\', '/'); + + char **files = 0; + i32 *file_count = 0; + app.read_command_line(&sysfunc, &memory_vars, curdir, &plat_settings, &files, &file_count, argc, argv); + sysshared_filter_real_files(files, file_count); + LOG("Read command line.\n"); +} + // BOTTOM diff --git a/platform_all/4ed_shared_library_constants.h b/platform_all/4ed_shared_library_constants.h index 95194bcd..0b4b07f5 100644 --- a/platform_all/4ed_shared_library_constants.h +++ b/platform_all/4ed_shared_library_constants.h @@ -85,7 +85,8 @@ system_load_library(Library *library, char *name, Load_Library_Location location internal b32 system_load_library(Library *library, char *name, Load_Library_Location location){ - system_load_library(library, name, location, 0, 0); + b32 result = system_load_library(library, name, location, 0, 0); + return(result); } #endif diff --git a/platform_all/4ed_work_queues.cpp b/platform_all/4ed_work_queues.cpp index 85f61d65..75540681 100644 --- a/platform_all/4ed_work_queues.cpp +++ b/platform_all/4ed_work_queues.cpp @@ -369,7 +369,7 @@ INTERNAL_Sys_Get_Thread_States_Sig(system_internal_get_thread_states){ } internal void -system_init_threaded_work_system(){ +work_system_init(){ AssertThreadSizes(); u32 core_count = CORE_COUNT; diff --git a/platform_linux/linux_4ed.cpp b/platform_linux/linux_4ed.cpp index f652ea00..4285390a 100644 --- a/platform_linux/linux_4ed.cpp +++ b/platform_linux/linux_4ed.cpp @@ -105,14 +105,6 @@ enum { LINUX_4ED_EVENT_CLI = (UINT64_C(5) << 32), }; -struct Linux_Coroutine { - Coroutine coroutine; - Linux_Coroutine *next; - ucontext_t ctx, yield_ctx; - stack_t stack; - b32 done; -}; - // // Linux forward declarations // @@ -129,6 +121,8 @@ global System_Functions sysfunc; #include "linux_library_wrapper.h" #include "4ed_standard_libraries.cpp" +#include "4ed_coroutine.cpp" + //////////////////////////////// struct Linux_Vars{ @@ -183,9 +177,6 @@ struct Linux_Vars{ i32 dpi_x, dpi_y; b32 vsync; - - Linux_Coroutine coroutine_data[18]; - Linux_Coroutine *coroutine_free; }; //////////////////////////////// @@ -199,6 +190,8 @@ global Libraries libraries; global App_Functions app; global Custom_API custom_api; +global Coroutine_System_Auto_Alloc coroutines; + //////////////////////////////// #include "linux_icon.h" @@ -326,91 +319,57 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){ // Coroutine // -internal Linux_Coroutine* -LinuxAllocCoroutine(){ - Linux_Coroutine *result = linuxvars.coroutine_free; - Assert(result != 0); - if (getcontext(&result->ctx) == -1){ - perror("getcontext"); - } - result->ctx.uc_stack = result->stack; - linuxvars.coroutine_free = result->next; - return(result); -} - -internal void -LinuxFreeCoroutine(Linux_Coroutine *data){ - data->next = linuxvars.coroutine_free; - linuxvars.coroutine_free = data; -} - -internal void -LinuxCoroutineMain(void *arg_){ - Linux_Coroutine *c = (Linux_Coroutine*)arg_; - c->coroutine.func(&c->coroutine); - c->done = 1; - LinuxFreeCoroutine(c); - setcontext((ucontext_t*)c->coroutine.yield_handle); -} - internal Sys_Create_Coroutine_Sig(system_create_coroutine){ - Linux_Coroutine *c = LinuxAllocCoroutine(); - c->done = 0; - - makecontext(&c->ctx, (void (*)())LinuxCoroutineMain, 1, &c->coroutine); - - *(ucontext_t**)&c->coroutine.plat_handle = &c->ctx; - c->coroutine.func = func; - - return(&c->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){ - Linux_Coroutine *c = (Linux_Coroutine*)coroutine; - ucontext_t* ctx = *(ucontext**)&coroutine->plat_handle; + Coroutine *coroutine = (Coroutine*)head; + coroutine->head.in = in; + coroutine->head.out = out; - coroutine->yield_handle = &c->yield_ctx; - coroutine->in = in; - coroutine->out = out; + Coroutine *active = coroutine->sys->active; + Assert(active != 0); + coroutine_launch(active, coroutine); + Assert(active == coroutine->sys->active); - swapcontext(&c->yield_ctx, ctx); - - if (c->done){ - LinuxFreeCoroutine(c); - coroutine = 0; + Coroutine_Head *result = &coroutine->head; + if (coroutine->state == CoroutineState_Dead){ + coroutine_system_free(&coroutines, coroutine); + result = 0; } - - return(coroutine); + return(result); } -internal Sys_Resume_Coroutine_Sig(system_resume_coroutine){ - Linux_Coroutine *c = (Linux_Coroutine*)coroutine; - void *fiber; + Coroutine *coroutine = (Coroutine*)head; + coroutine->head.in = in; + coroutine->head.out = out; - Assert(!c->done); + Coroutine *active = coroutine->sys->active; + Assert(active != 0); + coroutine_resume(active, coroutine); + Assert(active == coroutine->sys->active); - coroutine->yield_handle = &c->yield_ctx; - coroutine->in = in; - coroutine->out = out; - - ucontext *ctx = *(ucontext**)&coroutine->plat_handle; - - swapcontext(&c->yield_ctx, ctx); - - if (c->done){ - LinuxFreeCoroutine(c); - coroutine = 0; + Coroutine_Head *result = &coroutine->head; + if (coroutine->state == CoroutineState_Dead){ + coroutine_system_free(&coroutines, coroutine); + result = 0; } - - return(coroutine); + return(result); } -internal Sys_Yield_Coroutine_Sig(system_yield_coroutine){ - swapcontext(*(ucontext_t**)&coroutine->plat_handle, (ucontext*)coroutine->yield_handle); + Coroutine *coroutine = (Coroutine*)head; + coroutine_yield(coroutine); } // @@ -1652,39 +1611,19 @@ main(int argc, char **argv){ // Memory init // - system_memory_init(); + memory_init(); // // Read command line // - char* cwd = get_current_dir_name(); - if (!cwd){ - char buf[1024]; - snprintf(buf, sizeof(buf), "Call to get_current_dir_name failed: %s", strerror(errno)); - system_error_box(buf); - } + read_command_line(argc, argv); - String current_directory = make_string_slowly(cwd); + // + // Threads + // - Command_Line_Parameters clparams; - clparams.argv = argv; - clparams.argc = argc; - - char **files; - i32 *file_count; - i32 output_size; - - output_size = app.read_command_line(&sysfunc, &memory_vars, current_directory, &plat_settings, &files, &file_count, clparams); - - if (output_size > 0){ - LOGF("%.*s", output_size, (char*)memory_vars.target_memory); - } - if (output_size != 0){ - system_error_box("Error reading command-line arguments."); - } - - sysshared_filter_real_files(files, file_count); + work_system_init(); // // Coroutines @@ -1692,7 +1631,7 @@ main(int argc, char **argv){ linuxvars.coroutine_free = linuxvars.coroutine_data; for (i32 i = 0; i+1 < ArrayCount(linuxvars.coroutine_data); ++i){ - linuxvars.coroutine_data[i].next = linuxvars.coroutine_data + i + 1; + linuxvars.coroutine_data[i].next = &linuxvars.coroutine_data[i + 1]; } const size_t stack_size = MB(2); @@ -1701,12 +1640,6 @@ main(int argc, char **argv){ linuxvars.coroutine_data[i].stack.ss_sp = system_memory_allocate(stack_size); } - // - // Threads - // - - system_init_threaded_work_system(); - // // X11 init // @@ -1715,7 +1648,7 @@ main(int argc, char **argv){ if (!linuxvars.XDisplay){ // NOTE(inso): probably not worth trying the popup in this case... LOG("Can't open display!\n"); - return(1); + exit(1); } #define LOAD_ATOM(x) linuxvars.atom_##x = XInternAtom(linuxvars.XDisplay, #x, False); @@ -1930,7 +1863,7 @@ main(int argc, char **argv){ b32 keep_running = linuxvars.keep_running; - app.step(&sysfunc, &target, &memory_vars, &linuxvars.input, &result, clparams); + app.step(&sysfunc, &target, &memory_vars, &linuxvars.input, &result); if (result.perform_kill){ break; diff --git a/platform_win32/win32_4ed.cpp b/platform_win32/win32_4ed.cpp index 2700cef4..44ef21ec 100644 --- a/platform_win32/win32_4ed.cpp +++ b/platform_win32/win32_4ed.cpp @@ -105,12 +105,6 @@ struct Win32_Input_Chunk{ Win32_Input_Chunk_Persistent pers; }; -struct Win32_Coroutine{ - Coroutine coroutine; - Win32_Coroutine *next; - i32 done; -}; - //////////////////////////////// #define SLASH '\\' @@ -121,14 +115,11 @@ global System_Functions sysfunc; #include "win32_library_wrapper.h" #include "4ed_standard_libraries.cpp" +#include "4ed_coroutine.cpp" + //////////////////////////////// struct Win32_Vars{ - Custom_API custom_api; - - Win32_Coroutine coroutine_data[18]; - Win32_Coroutine *coroutine_free; - Win32_Input_Chunk input_chunk; b32 lctrl_lalt_is_altgr; b32 got_useful_event; @@ -168,6 +159,9 @@ global Plat_Settings plat_settings; global Libraries libraries; global App_Functions app; +global Custom_API custom_api; + +global Coroutine_System_Auto_Alloc coroutines; //////////////////////////////// @@ -272,94 +266,57 @@ Sys_Send_Exit_Signal_Sig(system_send_exit_signal){ // Coroutines // -internal Win32_Coroutine* -Win32AllocCoroutine(){ - Win32_Coroutine *result = win32vars.coroutine_free; - Assert(result != 0); - win32vars.coroutine_free = result->next; - return(result); -} - -internal void -Win32FreeCoroutine(Win32_Coroutine *data){ - data->next = win32vars.coroutine_free; - win32vars.coroutine_free = data; -} - -internal void CALL_CONVENTION -Win32CoroutineMain(void *arg_){ - Win32_Coroutine *c = (Win32_Coroutine*)arg_; - c->coroutine.func(&c->coroutine); - c->done = 1; - Win32FreeCoroutine(c); - SwitchToFiber(c->coroutine.yield_handle); -} - internal Sys_Create_Coroutine_Sig(system_create_coroutine){ - Win32_Coroutine *c; - Coroutine *coroutine; - void *fiber; - - c = Win32AllocCoroutine(); - c->done = 0; - - coroutine = &c->coroutine; - - fiber = CreateFiber(0, Win32CoroutineMain, coroutine); - - coroutine->plat_handle = handle_type(fiber); - coroutine->func = func; - - return(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){ - Win32_Coroutine *c = (Win32_Coroutine*)coroutine; - void *fiber; + Coroutine *coroutine = (Coroutine*)head; + coroutine->head.in = in; + coroutine->head.out = out; - fiber = handle_type(coroutine->plat_handle); - coroutine->yield_handle = GetCurrentFiber(); - coroutine->in = in; - coroutine->out = out; + Coroutine *active = coroutine->sys->active; + Assert(active != 0); + coroutine_launch(active, coroutine); + Assert(active == coroutine->sys->active); - SwitchToFiber(fiber); - - if (c->done){ - DeleteFiber(fiber); - Win32FreeCoroutine(c); - coroutine = 0; + Coroutine_Head *result = &coroutine->head; + if (coroutine->state == CoroutineState_Dead){ + coroutine_system_free(&coroutines, coroutine); + result = 0; } - - return(coroutine); + return(result); } Sys_Resume_Coroutine_Sig(system_resume_coroutine){ - Win32_Coroutine *c = (Win32_Coroutine*)coroutine; - void *fiber; + Coroutine *coroutine = (Coroutine*)head; + coroutine->head.in = in; + coroutine->head.out = out; - Assert(c->done == 0); + Coroutine *active = coroutine->sys->active; + Assert(active != 0); + coroutine_resume(active, coroutine); + Assert(active == coroutine->sys->active); - coroutine->yield_handle = GetCurrentFiber(); - coroutine->in = in; - coroutine->out = out; - - fiber = handle_type(coroutine->plat_handle); - - SwitchToFiber(fiber); - - if (c->done){ - DeleteFiber(fiber); - Win32FreeCoroutine(c); - coroutine = 0; + Coroutine_Head *result = &coroutine->head; + if (coroutine->state == CoroutineState_Dead){ + coroutine_system_free(&coroutines, coroutine); + result = 0; } - - return(coroutine); + return(result); } Sys_Yield_Coroutine_Sig(system_yield_coroutine){ - SwitchToFiber(coroutine->yield_handle); + Coroutine *coroutine = (Coroutine*)head; + coroutine_yield(coroutine); } // @@ -1062,7 +1019,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS i32 argc = __argc; char **argv = __argv; - memset(&linuxvars, 0, sizeof(linuxvars)); + memset(&win32vars, 0, sizeof(win32vars)); memset(&target, 0, sizeof(target)); memset(&memory_vars, 0, sizeof(memory_vars)); memset(&plat_settings, 0, sizeof(plat_settings)); @@ -1087,51 +1044,35 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS #endif // - // Memory Initialization + // Memory init // - system_memory_init(); - - // - // Threads - // - - system_init_threaded_work_system(); - - // - // Coroutines - // - - ConvertThreadToFiber(0); - win32vars.coroutine_free = win32vars.coroutine_data; - for (i32 i = 0; i+1 < ArrayCount(win32vars.coroutine_data); ++i){ - win32vars.coroutine_data[i].next = &win32vars.coroutine_data[i + 1]; - } + memory_init(); // // Read Command Line // - LOG("Reading command line\n"); - DWORD required = (GetCurrentDirectory(0, 0)*4) + 1; - u8 *current_directory_mem = (u8*)system_memory_allocate(required); - DWORD written = GetCurrentDirectory_utf8(required, current_directory_mem); + read_command_line(argc, argv); - String current_directory = make_string_cap(current_directory_mem, written, required); - terminate_with_null(¤t_directory); - replace_char(¤t_directory, '\\', '/'); + // + // Threads + // - Command_Line_Parameters clparams; - clparams.argv = argv; - clparams.argc = argc; + work_system_init(); - char **files = 0; - i32 *file_count = 0; + // + // Coroutines + // - app.read_command_line(&sysfunc, &memory_vars, current_directory, &plat_settings, &files, &file_count, clparams); - - sysshared_filter_real_files(files, file_count); - LOG("Loaded system code, read command line.\n"); + { + 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); + } // // Window and GL Initialization @@ -1254,10 +1195,17 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS // Main Loop // - LOG("Initializing application variables\n"); - app.init(&sysfunc, &target, &memory_vars, win32vars.clipboard_contents, current_directory, win32vars.custom_api); + char cwd[4096]; + u32 size = sysfunc.get_current_path(cwd, sizeof(cwd)); + if (size == 0 || size >= sizeof(cwd)){ + system_error_box("Could not get current directory at launch."); + } + String curdir = make_string(cwd, size); + terminate_with_null(&curdir); + replace_char(&curdir, '\\', '/'); - system_memory_free(current_directory.str, 0); + LOG("Initializing application variables\n"); + app.init(&sysfunc, &target, &memory_vars, win32vars.clipboard_contents, curdir, custom_api); b32 keep_running = true; win32vars.first = true; @@ -1450,7 +1398,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS win32vars.send_exit_signal = false; } - app.step(&sysfunc, &target, &memory_vars, &input, &result, clparams); + app.step(&sysfunc, &target, &memory_vars, &input, &result); if (result.perform_kill){ keep_running = false; diff --git a/platform_win32/win32_4ed_functions.cpp b/platform_win32/win32_4ed_functions.cpp index 35371350..a31c8ae6 100644 --- a/platform_win32/win32_4ed_functions.cpp +++ b/platform_win32/win32_4ed_functions.cpp @@ -13,6 +13,12 @@ // 4ed path // +internal +Sys_Get_Current_Path_Sig(system_get_current_path){ + i32 result = GetCurrentDirectory_utf8(capacity, (u8*)out); + return(result); +} + internal Sys_Get_4ed_Path_Sig(system_get_4ed_path){ i32 size = GetModuleFileName_utf8(0, (u8*)out, capacity);