zipped a lot of linux and windows code together related to multithreading and the system code linking
This commit is contained in:
parent
c97e82524e
commit
122cecb6ff
|
@ -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
|
||||||
|
|
|
@ -92,7 +92,7 @@ get_work_queue_available_space(i32 write, i32 read){
|
||||||
#define UNBOUNDED_SKIP_MAX 128
|
#define UNBOUNDED_SKIP_MAX 128
|
||||||
|
|
||||||
internal i32
|
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
|
// 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.
|
// 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
|
// 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;
|
semaphore_release_count = thread_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i32 i = 0; i < semaphore_release_count; ++i){
|
||||||
|
system_release_semaphore(queue->semaphore);
|
||||||
|
}
|
||||||
|
|
||||||
return(semaphore_release_count);
|
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
|
// BOTTOM
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,14 @@ struct Thread_Group{
|
||||||
i32 cancel_cv0;
|
i32 cancel_cv0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Mutex{
|
||||||
|
pthread_mutex_t crit;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Condition_Variable{
|
||||||
|
pthread_cond_t cv;
|
||||||
|
};
|
||||||
|
|
||||||
struct Linux_Vars{
|
struct Linux_Vars{
|
||||||
Display *XDisplay;
|
Display *XDisplay;
|
||||||
Window XWindow;
|
Window XWindow;
|
||||||
|
@ -185,8 +193,8 @@ struct Linux_Vars{
|
||||||
Thread_Memory *thread_memory;
|
Thread_Memory *thread_memory;
|
||||||
Thread_Group groups[THREAD_GROUP_COUNT];
|
Thread_Group groups[THREAD_GROUP_COUNT];
|
||||||
Work_Queue queues[THREAD_GROUP_COUNT];
|
Work_Queue queues[THREAD_GROUP_COUNT];
|
||||||
pthread_mutex_t locks[LOCK_COUNT];
|
Mutex locks[LOCK_COUNT];
|
||||||
pthread_cond_t conds[8];
|
Condition_Variable conds[8];
|
||||||
sem_t thread_semaphore;
|
sem_t thread_semaphore;
|
||||||
|
|
||||||
i32 dpi_x, dpi_y;
|
i32 dpi_x, dpi_y;
|
||||||
|
@ -483,14 +491,24 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
|
||||||
// Threads
|
// 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
|
internal
|
||||||
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
||||||
pthread_mutex_lock(linuxvars.locks + id);
|
system_internal_acquire_lock(&linuxvars.locks[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Release_Lock_Sig(system_release_lock){
|
Sys_Release_Lock_Sig(system_release_lock){
|
||||||
pthread_mutex_unlock(linuxvars.locks + id);
|
system_internal_release_lock(&linuxvars.locks[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -514,6 +532,11 @@ system_wait_on(Plat_Handle handle){
|
||||||
sem_wait(LinuxHandleToSem(handle));
|
sem_wait(LinuxHandleToSem(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
system_release_semaphore(Plat_Handle handle){
|
||||||
|
sem_post(LinuxHandleToSem(handle));
|
||||||
|
}
|
||||||
|
|
||||||
#include "4ed_work_queues.cpp"
|
#include "4ed_work_queues.cpp"
|
||||||
|
|
||||||
internal void*
|
internal void*
|
||||||
|
@ -528,22 +551,6 @@ JobThreadProc(void* lpParameter){
|
||||||
return(0);
|
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.
|
// Note(allen): post_job puts the job on the unbounded queue.
|
||||||
// The unbounded queue is entirely managed by the main thread.
|
// The unbounded queue is entirely managed by the main thread.
|
||||||
// The thread safe queue is bounded in size so the unbounded
|
// The thread safe queue is bounded in size so the unbounded
|
||||||
|
@ -551,152 +558,36 @@ flush_thread_group(i32 group_id){
|
||||||
internal
|
internal
|
||||||
Sys_Post_Job_Sig(system_post_job){
|
Sys_Post_Job_Sig(system_post_job){
|
||||||
Thread_Group *group = linuxvars.groups + group_id;
|
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;
|
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);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Cancel_Job_Sig(system_cancel_job){
|
Sys_Cancel_Job_Sig(system_cancel_job){
|
||||||
Thread_Group *group = linuxvars.groups + group_id;
|
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;
|
Work_Queue *queue = linuxvars.queues + group_id;
|
||||||
Full_Job_Data *job = queue->jobs + (job_id % QUEUE_WRAP);
|
cancel_job(group, queue, job_id);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Check_Cancel_Sig(system_check_cancel){
|
Sys_Check_Cancel_Sig(system_check_cancel){
|
||||||
b32 result = false;
|
|
||||||
|
|
||||||
Thread_Group *group = linuxvars.groups + thread->group_id;
|
Thread_Group *group = linuxvars.groups + thread->group_id;
|
||||||
i32 thread_index = thread->id - 1;
|
b32 result = check_cancel_status(group, thread);
|
||||||
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);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
||||||
system_acquire_lock(CANCEL_LOCK0 + memory->id - 1);
|
grow_thread_memory(memory);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Debug
|
|
||||||
//
|
|
||||||
|
|
||||||
#if FRED_INTERNAL
|
|
||||||
|
|
||||||
#if defined(OLD_JOB_QUEUE)
|
|
||||||
internal
|
internal
|
||||||
INTERNAL_Sys_Get_Thread_States_Sig(internal_get_thread_states){
|
INTERNAL_Sys_Get_Thread_States_Sig(system_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);
|
|
||||||
|
|
||||||
Thread_Group *group = linuxvars.groups + id;
|
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;
|
Work_Queue *queue = linuxvars.queues + id;
|
||||||
u32 write = queue->write_position;
|
dbg_get_thread_states(group, queue, running, pending);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Linux rendering/font system functions
|
// Linux rendering/font system functions
|
||||||
|
@ -738,63 +629,11 @@ LinuxLoadAppCode(String* base_dir){
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "4ed_link_system_functions.cpp"
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
LinuxLoadSystemCode(){
|
LinuxLoadSystemCode(){
|
||||||
// files
|
link_system_code(&linuxvars.system);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
|
|
@ -86,6 +86,55 @@
|
||||||
|
|
||||||
#define WM_4coder_ANIMATE (WM_USER + 0)
|
#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{
|
struct Thread_Context{
|
||||||
u32 job_id;
|
u32 job_id;
|
||||||
b32 running;
|
b32 running;
|
||||||
|
@ -108,53 +157,12 @@ struct Thread_Group{
|
||||||
i32 cancel_cv0;
|
i32 cancel_cv0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Control_Keys{
|
struct Mutex{
|
||||||
b8 l_ctrl;
|
CRITICAL_SECTION crit;
|
||||||
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];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Win32_Input_Chunk{
|
struct Condition_Variable{
|
||||||
Win32_Input_Chunk_Transient trans;
|
CONDITION_VARIABLE cv;
|
||||||
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 Win32_Vars{
|
struct Win32_Vars{
|
||||||
|
@ -165,16 +173,15 @@ struct Win32_Vars{
|
||||||
HMODULE custom;
|
HMODULE custom;
|
||||||
Plat_Settings settings;
|
Plat_Settings settings;
|
||||||
|
|
||||||
|
Thread_Memory *thread_memory;
|
||||||
Work_Queue queues[THREAD_GROUP_COUNT];
|
Work_Queue queues[THREAD_GROUP_COUNT];
|
||||||
Thread_Group groups[THREAD_GROUP_COUNT];
|
Thread_Group groups[THREAD_GROUP_COUNT];
|
||||||
CRITICAL_SECTION locks[LOCK_COUNT];
|
Mutex locks[LOCK_COUNT];
|
||||||
CONDITION_VARIABLE condition_vars[CV_COUNT];
|
Condition_Variable condition_vars[CV_COUNT];
|
||||||
Thread_Memory *thread_memory;
|
|
||||||
Win32_Coroutine coroutine_data[18];
|
Win32_Coroutine coroutine_data[18];
|
||||||
Win32_Coroutine *coroutine_free;
|
Win32_Coroutine *coroutine_free;
|
||||||
|
|
||||||
|
|
||||||
Win32_Input_Chunk input_chunk;
|
Win32_Input_Chunk input_chunk;
|
||||||
b32 lctrl_lalt_is_altgr;
|
b32 lctrl_lalt_is_altgr;
|
||||||
b32 got_useful_event;
|
b32 got_useful_event;
|
||||||
|
@ -336,25 +343,34 @@ Sys_Memory_Free_Sig(system_memory_free){
|
||||||
// Multithreading
|
// Multithreading
|
||||||
//
|
//
|
||||||
|
|
||||||
|
internal void
|
||||||
|
system_internal_acquire_lock(Mutex *m){
|
||||||
|
EnterCriticalSection(&m->crit);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
system_internal_release_lock(Mutex *m){
|
||||||
|
LeaveCriticalSection(&m->crit);
|
||||||
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
||||||
EnterCriticalSection(&win32vars.locks[id]);
|
system_internal_acquire_lock(&win32vars.locks[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Release_Lock_Sig(system_release_lock){
|
Sys_Release_Lock_Sig(system_release_lock){
|
||||||
LeaveCriticalSection(&win32vars.locks[id]);
|
system_internal_release_lock(&win32vars.locks[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
system_wait_cv(i32 crit_id, i32 cv_id){
|
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
|
internal void
|
||||||
system_signal_cv(i32 crit_id, i32 cv_id){
|
system_signal_cv(i32 crit_id, i32 cv_id){
|
||||||
AllowLocal(crit_id);
|
WakeConditionVariable(&win32vars.condition_vars[cv_id].cv);
|
||||||
WakeConditionVariable(win32vars.condition_vars + cv_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -367,6 +383,11 @@ system_wait_on(Plat_Handle handle){
|
||||||
WaitForSingleObject(Win32Handle(handle), INFINITE);
|
WaitForSingleObject(Win32Handle(handle), INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
system_release_semaphore(Plat_Handle handle){
|
||||||
|
ReleaseSemaphore(Win32Handle(handle), 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#include "4ed_work_queues.cpp"
|
#include "4ed_work_queues.cpp"
|
||||||
|
|
||||||
internal DWORD CALL_CONVENTION
|
internal DWORD CALL_CONVENTION
|
||||||
|
@ -381,14 +402,6 @@ JobThreadProc(LPVOID lpParameter){
|
||||||
return(0);
|
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
|
internal void
|
||||||
flush_thread_group(i32 group_id){
|
flush_thread_group(i32 group_id){
|
||||||
Thread_Group *group = win32vars.groups + 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);
|
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
|
internal
|
||||||
Sys_Post_Job_Sig(system_post_job){
|
Sys_Post_Job_Sig(system_post_job){
|
||||||
Thread_Group *group = win32vars.groups + group_id;
|
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;
|
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);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Cancel_Job_Sig(system_cancel_job){
|
Sys_Cancel_Job_Sig(system_cancel_job){
|
||||||
Thread_Group *group = win32vars.groups + group_id;
|
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;
|
Work_Queue *queue = win32vars.queues + group_id;
|
||||||
Full_Job_Data *job = queue->jobs + (job_id % QUEUE_WRAP);
|
cancel_job(group, queue, job_id);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Check_Cancel_Sig(system_check_cancel){
|
Sys_Check_Cancel_Sig(system_check_cancel){
|
||||||
b32 result = 0;
|
|
||||||
|
|
||||||
Thread_Group *group = win32vars.groups + thread->group_id;
|
Thread_Group *group = win32vars.groups + thread->group_id;
|
||||||
i32 thread_index = thread->id - 1;
|
b32 result = check_cancel_status(group, thread);
|
||||||
i32 cancel_lock = group->cancel_lock0 + thread_index;
|
|
||||||
|
|
||||||
system_acquire_lock(cancel_lock);
|
|
||||||
if (thread->cancel){
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
system_release_lock(cancel_lock);
|
|
||||||
|
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
||||||
system_acquire_lock(CANCEL_LOCK0 + memory->id - 1);
|
grow_thread_memory(memory);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FRED_INTERNAL
|
internal
|
||||||
internal void
|
INTERNAL_Sys_Get_Thread_States_Sig(system_internal_get_thread_states){
|
||||||
INTERNAL_get_thread_states(Thread_Group_ID id, b8 *running, i32 *pending){
|
|
||||||
Thread_Group *group = win32vars.groups + id;
|
Thread_Group *group = win32vars.groups + id;
|
||||||
Unbounded_Work_Queue *source_queue = &group->queue;
|
|
||||||
Work_Queue *queue = win32vars.queues + id;
|
Work_Queue *queue = win32vars.queues + id;
|
||||||
u32 write = queue->write_position;
|
dbg_get_thread_states(group, queue, running, pending);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Coroutines
|
// Coroutines
|
||||||
|
@ -1309,54 +1220,11 @@ Win32LoadAppCode(){
|
||||||
#include "4ed_font_data.h"
|
#include "4ed_font_data.h"
|
||||||
#include "4ed_system_shared.cpp"
|
#include "4ed_system_shared.cpp"
|
||||||
|
|
||||||
|
#include "4ed_link_system_functions.cpp"
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
Win32LoadSystemCode(){
|
Win32LoadSystemCode(){
|
||||||
win32vars.system.set_file_list = system_set_file_list;
|
link_system_code(&win32vars.system);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -1859,11 +1727,11 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
|
||||||
//
|
//
|
||||||
|
|
||||||
for (i32 i = 0; i < LOCK_COUNT; ++i){
|
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){
|
for (i32 i = 0; i < CV_COUNT; ++i){
|
||||||
InitializeConditionVariable(&win32vars.condition_vars[i]);
|
InitializeConditionVariable(&win32vars.condition_vars[i].cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread_Context background[4];
|
Thread_Context background[4];
|
||||||
|
|
Loading…
Reference in New Issue