From 122cecb6ff7d58dd2ac08e68671899333fef2de8 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 18 Jul 2017 12:41:40 -0400 Subject: [PATCH] zipped a lot of linux and windows code together related to multithreading and the system code linking --- platform_all/4ed_link_system_functions.cpp | 68 +++++ platform_all/4ed_work_queues.cpp | 121 +++++++- platform_linux/linux_4ed.cpp | 235 +++------------- platform_win32/win32_4ed.cpp | 310 ++++++--------------- 4 files changed, 314 insertions(+), 420 deletions(-) create mode 100644 platform_all/4ed_link_system_functions.cpp diff --git a/platform_all/4ed_link_system_functions.cpp b/platform_all/4ed_link_system_functions.cpp new file mode 100644 index 00000000..0444ee8b --- /dev/null +++ b/platform_all/4ed_link_system_functions.cpp @@ -0,0 +1,68 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 18.07.2017 + * + * Code to link system functions using a name convention + * + */ + +// TOP + +// TODO(allen): Should auto-gen this! + +#define SYSLINK(name) system->name = system_##name + +internal void +link_system_code(System_Functions *system){ + SYSLINK(set_file_list); + SYSLINK(get_canonical); + SYSLINK(add_listener); + SYSLINK(remove_listener); + SYSLINK(get_file_change); + SYSLINK(load_handle); + SYSLINK(load_size); + SYSLINK(load_file); + SYSLINK(load_close); + SYSLINK(save_file); + + SYSLINK(now_time); + + 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); + SYSLINK(cli_end_update); + + SYSLINK(post_job); + SYSLINK(cancel_job); + SYSLINK(check_cancel); + SYSLINK(grow_thread_memory); + SYSLINK(acquire_lock); + SYSLINK(release_lock); + + SYSLINK(memory_allocate); + SYSLINK(memory_set_protection); + SYSLINK(memory_free); + SYSLINK(file_exists); + SYSLINK(directory_cd); + SYSLINK(get_4ed_path); + SYSLINK(toggle_fullscreen); + SYSLINK(is_fullscreen); + SYSLINK(show_mouse_cursor); + SYSLINK(send_exit_signal); + + SYSLINK(log); +#if FRED_INTERNAL + SYSLINK(internal_get_thread_states); +#endif +} + +// BOTTOM + diff --git a/platform_all/4ed_work_queues.cpp b/platform_all/4ed_work_queues.cpp index 9918a883..e890ad5c 100644 --- a/platform_all/4ed_work_queues.cpp +++ b/platform_all/4ed_work_queues.cpp @@ -92,7 +92,7 @@ get_work_queue_available_space(i32 write, i32 read){ #define UNBOUNDED_SKIP_MAX 128 internal i32 -flush_unbounded_queue_to_main(Unbounded_Work_Queue *source_queue, Work_Queue *queue, i32 thread_count){ +flush_to_direct_queue(Unbounded_Work_Queue *source_queue, Work_Queue *queue, i32 thread_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 @@ -144,8 +144,127 @@ flush_unbounded_queue_to_main(Unbounded_Work_Queue *source_queue, Work_Queue *qu 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 u32 +post_job(Thread_Group *group, Work_Queue *direct_queue, Job_Data job){ + 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 = {0}; + full_job.job = job; + full_job.running_thread = THREAD_NOT_ASSIGNED; + full_job.id = result; + + queue->jobs[queue->count++] = full_job; + flush_to_direct_queue(queue, direct_queue, group->count); + + return(result); +} + +internal void +cancel_job(Thread_Group *group, Work_Queue *queue, u32 job_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 = group->cancel_lock0 + thread_index; + i32 cancel_cv = group->cancel_cv0 + thread_index; + Thread_Context *thread = group->threads + thread_index; + + system_acquire_lock(cancel_lock); + thread->cancel = true; + system_release_lock(FRAME_LOCK); + + do{ + system_wait_cv(cancel_lock, cancel_cv); + }while (thread->cancel); + + system_acquire_lock(FRAME_LOCK); + system_release_lock(cancel_lock); + } + } +} + +internal b32 +check_cancel_status(Thread_Group *group, Thread_Context *thread){ + b32 result = false; + i32 thread_index = thread->id - 1; + i32 cancel_lock = group->cancel_lock0 + thread_index; + system_acquire_lock(cancel_lock); + if (thread->cancel){ + result = true; + } + system_release_lock(cancel_lock); + return(result); +} + +internal void +grow_thread_memory(Thread_Memory *memory){ + system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); + void *old_data = memory->data; + i32 old_size = memory->size; + i32 new_size = l_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_LOCK0 + memory->id - 1); +} + +internal void +dbg_get_thread_states(Thread_Group *group, Work_Queue *queue, b8 *running, i32 *pending){ + Unbounded_Work_Queue *source_queue = &group->queue; + u32 write = queue->write_position; + u32 read = queue->read_position; + if (write < read){ + write += QUEUE_WRAP; + } + *pending = (i32)(write - read) + source_queue->count - source_queue->skip; + + for (i32 i = 0; i < group->count; ++i){ + running[i] = (group->threads[i].running != 0); + } +} + // BOTTOM diff --git a/platform_linux/linux_4ed.cpp b/platform_linux/linux_4ed.cpp index dd9bf491..f2cd2e7f 100644 --- a/platform_linux/linux_4ed.cpp +++ b/platform_linux/linux_4ed.cpp @@ -133,6 +133,14 @@ struct Thread_Group{ i32 cancel_cv0; }; +struct Mutex{ + pthread_mutex_t crit; +}; + +struct Condition_Variable{ + pthread_cond_t cv; +}; + struct Linux_Vars{ Display *XDisplay; Window XWindow; @@ -185,8 +193,8 @@ struct Linux_Vars{ Thread_Memory *thread_memory; Thread_Group groups[THREAD_GROUP_COUNT]; Work_Queue queues[THREAD_GROUP_COUNT]; - pthread_mutex_t locks[LOCK_COUNT]; - pthread_cond_t conds[8]; + Mutex locks[LOCK_COUNT]; + Condition_Variable conds[8]; sem_t thread_semaphore; i32 dpi_x, dpi_y; @@ -483,14 +491,24 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ // Threads // +internal void +system_internal_acquire_lock(Mutex *m){ + pthread_mutex_lock(m->crit); +} + +internal void +system_internal_release_lock(Mutex *m){ + pthread_mutex_unlock(m->crit); +} + internal Sys_Acquire_Lock_Sig(system_acquire_lock){ - pthread_mutex_lock(linuxvars.locks + id); + system_internal_acquire_lock(&linuxvars.locks[id]); } internal Sys_Release_Lock_Sig(system_release_lock){ - pthread_mutex_unlock(linuxvars.locks + id); + system_internal_release_lock(&linuxvars.locks[id]); } internal void @@ -514,6 +532,11 @@ system_wait_on(Plat_Handle handle){ sem_wait(LinuxHandleToSem(handle)); } +internal void +system_release_semaphore(Plat_Handle handle){ + sem_post(LinuxHandleToSem(handle)); +} + #include "4ed_work_queues.cpp" internal void* @@ -528,22 +551,6 @@ JobThreadProc(void* lpParameter){ return(0); } -internal void -flush_to_direct_queue(Unbounded_Work_Queue *source_queue, Work_Queue *queue, i32 thread_count){ - i32 semaphore_release_count = flush_to_direct_queue(source_queue, queue, thread_count); - for (i32 i = 0; i < semaphore_release_count; ++i){ - sem_post(LinuxHandleToSem(queue->semaphore)); - } -} - -internal void -flush_thread_group(i32 group_id){ - Thread_Group *group = linuxvars.groups + group_id; - Work_Queue *queue = linuxvars.queues + group_id; - Unbounded_Work_Queue *source_queue = &group->queue; - flush_to_direct_queue(source_queue, queue, group->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 @@ -551,152 +558,36 @@ flush_thread_group(i32 group_id){ internal Sys_Post_Job_Sig(system_post_job){ Thread_Group *group = linuxvars.groups + group_id; - Unbounded_Work_Queue *queue = &group->queue; - - u32 result = queue->next_job_id++; - - while (queue->count >= queue->max){ - i32 new_max = queue->max*2; - u32 job_size = sizeof(Full_Job_Data); - Full_Job_Data *new_jobs = (Full_Job_Data*)system_memory_allocate(new_max*job_size); - - memcpy(new_jobs, queue->jobs, queue->count); - - system_memory_free(queue->jobs, queue->max*job_size); - - 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; - Work_Queue *direct_queue = linuxvars.queues + group_id; - flush_to_direct_queue(queue, direct_queue, group->count); - + u32 result = post_job(group, direct_queue, job); return(result); } internal Sys_Cancel_Job_Sig(system_cancel_job){ Thread_Group *group = linuxvars.groups + 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){ - Work_Queue *queue = linuxvars.queues + group_id; - 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 = group->cancel_lock0 + thread_index; - i32 cancel_cv = group->cancel_cv0 + thread_index; - Thread_Context *thread = group->threads + thread_index; - - system_acquire_lock(cancel_lock); - - thread->cancel = 1; - - system_release_lock(FRAME_LOCK); - do{ - system_wait_cv(cancel_lock, cancel_cv); - }while (thread->cancel == 1); - system_acquire_lock(FRAME_LOCK); - - system_release_lock(cancel_lock); - } - } + Work_Queue *queue = linuxvars.queues + group_id; + cancel_job(group, queue, job_id); } internal Sys_Check_Cancel_Sig(system_check_cancel){ - b32 result = false; - Thread_Group *group = linuxvars.groups + thread->group_id; - i32 thread_index = thread->id - 1; - i32 cancel_lock = group->cancel_lock0 + thread_index; - - system_acquire_lock(cancel_lock); - if (thread->cancel){ - result = true; - } - system_release_lock(cancel_lock); - + b32 result = check_cancel_status(group, thread); return(result); } internal Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){ - system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); - void *old_data = memory->data; - i32 old_size = memory->size; - i32 new_size = l_round_up_i32(memory->size*2, KB(4)); - memory->data = system_memory_allocate(new_size); - memory->size = new_size; - if (old_data){ - memcpy(memory->data, old_data, old_size); - system_memory_free(old_data, old_size); - } - system_release_lock(CANCEL_LOCK0 + memory->id - 1); + grow_thread_memory(memory); } -// -// Debug -// - -#if FRED_INTERNAL - -#if defined(OLD_JOB_QUEUE) internal -INTERNAL_Sys_Get_Thread_States_Sig(internal_get_thread_states){ - Work_Queue *queue = linuxvars.queues + id; - u32 write = queue->write_position; - u32 read = queue->read_position; - if (write < read) write += QUEUE_WRAP; - *pending = (i32)(write - read); - +INTERNAL_Sys_Get_Thread_States_Sig(system_internal_get_thread_states){ Thread_Group *group = linuxvars.groups + id; - for (i32 i = 0; i < group->count; ++i){ - running[i] = (group->threads[i].running != 0); - } -} -#else -internal -INTERNAL_Sys_Get_Thread_States_Sig(internal_get_thread_states){ - Thread_Group *group = linuxvars.groups + id; - Unbounded_Work_Queue *source_queue = &group->queue; Work_Queue *queue = linuxvars.queues + id; - u32 write = queue->write_position; - u32 read = queue->read_position; - if (write < read) write += QUEUE_WRAP; - *pending = (i32)(write - read) + source_queue->count - source_queue->skip; - - for (i32 i = 0; i < group->count; ++i){ - running[i] = (group->threads[i].running != 0); - } + dbg_get_thread_states(group, queue, running, pending); } -#endif - -#endif // // Linux rendering/font system functions @@ -738,63 +629,11 @@ LinuxLoadAppCode(String* base_dir){ return(result); } +#include "4ed_link_system_functions.cpp" + internal void LinuxLoadSystemCode(){ - // files - linuxvars.system.set_file_list = system_set_file_list; - linuxvars.system.get_canonical = system_get_canonical; - linuxvars.system.add_listener = system_add_listener; - linuxvars.system.remove_listener = system_remove_listener; - linuxvars.system.get_file_change = system_get_file_change; - linuxvars.system.load_handle = system_load_handle; - linuxvars.system.load_size = system_load_size; - linuxvars.system.load_file = system_load_file; - linuxvars.system.load_close = system_load_close; - linuxvars.system.save_file = system_save_file; - - // time - linuxvars.system.now_time = system_now_time; - - // custom.h - linuxvars.system.memory_allocate = system_memory_allocate; - linuxvars.system.memory_set_protection = system_memory_set_protection; - linuxvars.system.memory_free = system_memory_free; - linuxvars.system.file_exists = system_file_exists; - linuxvars.system.directory_cd = system_directory_cd; - linuxvars.system.get_4ed_path = system_get_4ed_path; - linuxvars.system.show_mouse_cursor = system_show_mouse_cursor; - linuxvars.system.toggle_fullscreen = system_toggle_fullscreen; - linuxvars.system.is_fullscreen = system_is_fullscreen; - linuxvars.system.send_exit_signal = system_send_exit_signal; - - // clipboard - linuxvars.system.post_clipboard = system_post_clipboard; - - // coroutine - linuxvars.system.create_coroutine = system_create_coroutine; - linuxvars.system.launch_coroutine = system_launch_coroutine; - linuxvars.system.resume_coroutine = system_resume_coroutine; - linuxvars.system.yield_coroutine = system_yield_coroutine; - - // cli - linuxvars.system.cli_call = system_cli_call; - linuxvars.system.cli_begin_update = system_cli_begin_update; - linuxvars.system.cli_update_step = system_cli_update_step; - linuxvars.system.cli_end_update = system_cli_end_update; - - // threads - linuxvars.system.post_job = system_post_job; - linuxvars.system.cancel_job = system_cancel_job; - linuxvars.system.check_cancel = system_check_cancel; - linuxvars.system.grow_thread_memory = system_grow_thread_memory; - linuxvars.system.acquire_lock = system_acquire_lock; - linuxvars.system.release_lock = system_release_lock; - - // debug - linuxvars.system.log = system_log; -#if FRED_INTERNAL - linuxvars.system.internal_get_thread_states = internal_get_thread_states; -#endif + link_system_code(&linuxvars.system); } internal void diff --git a/platform_win32/win32_4ed.cpp b/platform_win32/win32_4ed.cpp index 5567f632..b83e58d1 100644 --- a/platform_win32/win32_4ed.cpp +++ b/platform_win32/win32_4ed.cpp @@ -86,6 +86,55 @@ #define WM_4coder_ANIMATE (WM_USER + 0) +struct Control_Keys{ + b8 l_ctrl; + b8 r_ctrl; + b8 l_alt; + b8 r_alt; +}; +global Control_Keys null_control_keys = {0}; + +struct Win32_Input_Chunk_Transient{ + Key_Input_Data key_data; + b8 mouse_l_press, mouse_l_release; + b8 mouse_r_press, mouse_r_release; + b8 out_of_window; + i8 mouse_wheel; + b8 trying_to_kill; +}; +global Win32_Input_Chunk_Transient null_input_chunk_transient = {0}; + +struct Win32_Input_Chunk_Persistent{ + i32 mouse_x, mouse_y; + b8 mouse_l, mouse_r; + + Control_Keys controls; + b8 control_keys[MDFR_INDEX_COUNT]; +}; + +struct Win32_Input_Chunk{ + Win32_Input_Chunk_Transient trans; + Win32_Input_Chunk_Persistent pers; +}; + +struct Win32_Coroutine{ + Coroutine coroutine; + Win32_Coroutine *next; + i32 done; +}; + +enum CV_ID{ + CANCEL_CV0, + CANCEL_CV1, + CANCEL_CV2, + CANCEL_CV3, + CANCEL_CV4, + CANCEL_CV5, + CANCEL_CV6, + CANCEL_CV7, + CV_COUNT +}; + struct Thread_Context{ u32 job_id; b32 running; @@ -108,53 +157,12 @@ struct Thread_Group{ i32 cancel_cv0; }; -struct Control_Keys{ - b8 l_ctrl; - b8 r_ctrl; - b8 l_alt; - b8 r_alt; -}; -static Control_Keys null_control_keys = {0}; - -struct Win32_Input_Chunk_Transient{ - Key_Input_Data key_data; - b8 mouse_l_press, mouse_l_release; - b8 mouse_r_press, mouse_r_release; - b8 out_of_window; - i8 mouse_wheel; - b8 trying_to_kill; -}; -static Win32_Input_Chunk_Transient null_input_chunk_transient = {0}; - -struct Win32_Input_Chunk_Persistent{ - i32 mouse_x, mouse_y; - b8 mouse_l, mouse_r; - - Control_Keys controls; - b8 control_keys[MDFR_INDEX_COUNT]; +struct Mutex{ + CRITICAL_SECTION crit; }; -typedef struct Win32_Input_Chunk{ - Win32_Input_Chunk_Transient trans; - Win32_Input_Chunk_Persistent pers; -} Win32_Input_Chunk; - -typedef struct Win32_Coroutine{ - Coroutine coroutine; - Win32_Coroutine *next; - i32 done; -} Win32_Coroutine; - -enum CV_ID{ - CANCEL_CV0, - CANCEL_CV1, - CANCEL_CV2, - CANCEL_CV3, - CANCEL_CV4, - CANCEL_CV5, - CANCEL_CV6, - CANCEL_CV7, - CV_COUNT +struct Condition_Variable{ + CONDITION_VARIABLE cv; }; struct Win32_Vars{ @@ -165,16 +173,15 @@ struct Win32_Vars{ HMODULE custom; Plat_Settings settings; - + Thread_Memory *thread_memory; Work_Queue queues[THREAD_GROUP_COUNT]; Thread_Group groups[THREAD_GROUP_COUNT]; - CRITICAL_SECTION locks[LOCK_COUNT]; - CONDITION_VARIABLE condition_vars[CV_COUNT]; - Thread_Memory *thread_memory; + Mutex locks[LOCK_COUNT]; + Condition_Variable condition_vars[CV_COUNT]; + Win32_Coroutine coroutine_data[18]; Win32_Coroutine *coroutine_free; - Win32_Input_Chunk input_chunk; b32 lctrl_lalt_is_altgr; b32 got_useful_event; @@ -336,25 +343,34 @@ Sys_Memory_Free_Sig(system_memory_free){ // Multithreading // +internal void +system_internal_acquire_lock(Mutex *m){ + EnterCriticalSection(&m->crit); +} + +internal void +system_internal_release_lock(Mutex *m){ + LeaveCriticalSection(&m->crit); +} + internal Sys_Acquire_Lock_Sig(system_acquire_lock){ - EnterCriticalSection(&win32vars.locks[id]); + system_internal_acquire_lock(&win32vars.locks[id]); } internal Sys_Release_Lock_Sig(system_release_lock){ - LeaveCriticalSection(&win32vars.locks[id]); + system_internal_release_lock(&win32vars.locks[id]); } internal void system_wait_cv(i32 crit_id, i32 cv_id){ - SleepConditionVariableCS(win32vars.condition_vars + cv_id, win32vars.locks + crit_id, INFINITE); + SleepConditionVariableCS(&win32vars.condition_vars[cv_id].cv, &win32vars.locks[crit_id].crit, INFINITE); } internal void system_signal_cv(i32 crit_id, i32 cv_id){ - AllowLocal(crit_id); - WakeConditionVariable(win32vars.condition_vars + cv_id); + WakeConditionVariable(&win32vars.condition_vars[cv_id].cv); } internal void @@ -367,6 +383,11 @@ system_wait_on(Plat_Handle handle){ WaitForSingleObject(Win32Handle(handle), INFINITE); } +internal void +system_release_semaphore(Plat_Handle handle){ + ReleaseSemaphore(Win32Handle(handle), 1, 0); +} + #include "4ed_work_queues.cpp" internal DWORD CALL_CONVENTION @@ -381,14 +402,6 @@ JobThreadProc(LPVOID lpParameter){ return(0); } -internal void -flush_to_direct_queue(Unbounded_Work_Queue *source_queue, Work_Queue *queue, i32 thread_count){ - i32 semaphore_release_count = flush_unbounded_queue_to_main(source_queue, queue, thread_count); - for (i32 i = 0; i < semaphore_release_count; ++i){ - ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0); - } -} - internal void flush_thread_group(i32 group_id){ Thread_Group *group = win32vars.groups + group_id; @@ -397,141 +410,39 @@ flush_thread_group(i32 group_id){ flush_to_direct_queue(source_queue, queue, group->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 = win32vars.groups + group_id; - Unbounded_Work_Queue *queue = &group->queue; - - u32 result = queue->next_job_id++; - - while (queue->count >= queue->max){ - u32 new_max = queue->max*2; - 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, 0); - - 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; - Work_Queue *direct_queue = win32vars.queues + group_id; - flush_to_direct_queue(queue, direct_queue, group->count); - + u32 result = post_job(group, direct_queue, job); return(result); } internal Sys_Cancel_Job_Sig(system_cancel_job){ Thread_Group *group = win32vars.groups + 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){ - Work_Queue *queue = win32vars.queues + group_id; - 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 = group->cancel_lock0 + thread_index; - i32 cancel_cv = group->cancel_cv0 + thread_index; - Thread_Context *thread = group->threads + thread_index; - - system_acquire_lock(cancel_lock); - - thread->cancel = 1; - - system_release_lock(FRAME_LOCK); - do{ - system_wait_cv(cancel_lock, cancel_cv); - }while (thread->cancel == 1); - system_acquire_lock(FRAME_LOCK); - - system_release_lock(cancel_lock); - } - } + Work_Queue *queue = win32vars.queues + group_id; + cancel_job(group, queue, job_id); } internal Sys_Check_Cancel_Sig(system_check_cancel){ - b32 result = 0; - Thread_Group *group = win32vars.groups + thread->group_id; - i32 thread_index = thread->id - 1; - i32 cancel_lock = group->cancel_lock0 + thread_index; - - system_acquire_lock(cancel_lock); - if (thread->cancel){ - result = 1; - } - system_release_lock(cancel_lock); - + b32 result = check_cancel_status(group, thread); return(result); } internal Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){ - system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); - void *old_data = memory->data; - i32 old_size = memory->size; - i32 new_size = l_round_up_i32(memory->size*2, KB(4)); - memory->data = system_memory_allocate(new_size); - memory->size = new_size; - if (old_data){ - memcpy(memory->data, old_data, old_size); - system_memory_free(old_data, 0); - } - system_release_lock(CANCEL_LOCK0 + memory->id - 1); + grow_thread_memory(memory); } -#if FRED_INTERNAL -internal void -INTERNAL_get_thread_states(Thread_Group_ID id, b8 *running, i32 *pending){ +internal +INTERNAL_Sys_Get_Thread_States_Sig(system_internal_get_thread_states){ Thread_Group *group = win32vars.groups + id; - Unbounded_Work_Queue *source_queue = &group->queue; Work_Queue *queue = win32vars.queues + id; - u32 write = queue->write_position; - u32 read = queue->read_position; - if (write < read){ - write += QUEUE_WRAP; - } - *pending = (i32)(write - read) + source_queue->count - source_queue->skip; - - for (i32 i = 0; i < group->count; ++i){ - running[i] = (group->threads[i].running != 0); - } + dbg_get_thread_states(group, queue, running, pending); } -#endif - // // Coroutines @@ -1309,54 +1220,11 @@ Win32LoadAppCode(){ #include "4ed_font_data.h" #include "4ed_system_shared.cpp" +#include "4ed_link_system_functions.cpp" + internal void Win32LoadSystemCode(){ - win32vars.system.set_file_list = system_set_file_list; - win32vars.system.get_canonical = system_get_canonical; - win32vars.system.add_listener = system_add_listener; - win32vars.system.remove_listener = system_remove_listener; - win32vars.system.get_file_change = system_get_file_change; - win32vars.system.load_handle = system_load_handle; - win32vars.system.load_size = system_load_size; - win32vars.system.load_file = system_load_file; - win32vars.system.load_close = system_load_close; - win32vars.system.save_file = system_save_file; - - win32vars.system.now_time = system_now_time; - - win32vars.system.post_clipboard = system_post_clipboard; - - win32vars.system.create_coroutine = system_create_coroutine; - win32vars.system.launch_coroutine = system_launch_coroutine; - win32vars.system.resume_coroutine = system_resume_coroutine; - win32vars.system.yield_coroutine = system_yield_coroutine; - - win32vars.system.cli_call = system_cli_call; - win32vars.system.cli_begin_update = system_cli_begin_update; - win32vars.system.cli_update_step = system_cli_update_step; - win32vars.system.cli_end_update = system_cli_end_update; - - win32vars.system.post_job = system_post_job; - win32vars.system.cancel_job = system_cancel_job; - win32vars.system.check_cancel = system_check_cancel; - win32vars.system.grow_thread_memory = system_grow_thread_memory; - win32vars.system.acquire_lock = system_acquire_lock; - win32vars.system.release_lock = system_release_lock; - - win32vars.system.memory_allocate = system_memory_allocate; - win32vars.system.memory_set_protection = system_memory_set_protection; - win32vars.system.memory_free = system_memory_free; - win32vars.system.file_exists = system_file_exists; - win32vars.system.directory_cd = system_directory_cd; - win32vars.system.get_4ed_path = system_get_4ed_path; - win32vars.system.toggle_fullscreen = system_toggle_fullscreen; - win32vars.system.is_fullscreen = system_is_fullscreen;win32vars.system.show_mouse_cursor = system_show_mouse_cursor; - win32vars.system.send_exit_signal = system_send_exit_signal; - - win32vars.system.log = system_log; -#if FRED_INTERNAL - win32vars.system.internal_get_thread_states = INTERNAL_get_thread_states; -#endif + link_system_code(&win32vars.system); } internal void @@ -1859,11 +1727,11 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS // for (i32 i = 0; i < LOCK_COUNT; ++i){ - InitializeCriticalSection(&win32vars.locks[i]); + InitializeCriticalSection(&win32vars.locks[i].crit); } for (i32 i = 0; i < CV_COUNT; ++i){ - InitializeConditionVariable(&win32vars.condition_vars[i]); + InitializeConditionVariable(&win32vars.condition_vars[i].cv); } Thread_Context background[4];