switched to condition-variable based cancelation

master
Allen Webster 2016-05-31 14:32:58 -04:00
parent 43f65dd5ef
commit a09851af12
3 changed files with 5754 additions and 5634 deletions

View File

@ -809,14 +809,32 @@ Job_Callback_Sig(job_full_lex){
tokens.max_count = memory->size / sizeof(Cpp_Token);
tokens.count = 0;
Cpp_Lex_Data status = cpp_lex_file_nonalloc(cpp_file, &tokens);
Cpp_Lex_Data status = {};
while (!status.complete){
system->grow_thread_memory(memory);
tokens.tokens = (Cpp_Token*)memory->data;
tokens.max_count = memory->size / sizeof(Cpp_Token);
status = cpp_lex_file_nonalloc(cpp_file, &tokens, status);
}
do{
for (i32 r = 2048; r > 0 && status.pos < cpp_file.size; --r){
Cpp_Lex_Data prev_lex = status;
Cpp_Read_Result step_result = cpp_lex_step(cpp_file, &status);
if (step_result.has_result){
if (!cpp_push_token_nonalloc(&tokens, step_result.token)){
status = prev_lex;
system->grow_thread_memory(memory);
tokens.tokens = (Cpp_Token*)memory->data;
tokens.max_count = memory->size / sizeof(Cpp_Token);
}
}
}
if (status.pos >= cpp_file.size){
status.complete = 1;
}
else{
if (system->check_cancel(thread)){
return;
}
}
} while(!status.complete);
i32 new_max = LargeRoundUp(tokens.count+1, Kbytes(1));
@ -835,11 +853,13 @@ Job_Callback_Sig(job_full_lex){
system->acquire_lock(FRAME_LOCK);
{
file->state.token_stack.count = tokens.count;
file->state.token_stack.max_count = new_max;
if (file->state.token_stack.tokens)
general_memory_free(general, file->state.token_stack.tokens);
file->state.token_stack.tokens = file->state.swap_stack.tokens;
Cpp_Token_Stack *file_stack = &file->state.token_stack;
file_stack->count = tokens.count;
file_stack->max_count = new_max;
if (file_stack->tokens){
general_memory_free(general, file_stack->tokens);
}
file_stack->tokens = file->state.swap_stack.tokens;
file->state.swap_stack.tokens = 0;
}
system->release_lock(FRAME_LOCK);
@ -1498,6 +1518,22 @@ file_view_nullify_file(View *view){
view->file_data = file_viewing_data_zero();
}
inline f32
view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){
f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f;
max_target_y = clamp_bottom(0.f, max_target_y);
return(max_target_y);
}
internal f32
view_compute_max_target_y(View *view){
i32 lowest_line = view_compute_lowest_line(view);
i32 line_height = view->font_height;
f32 view_height = view_file_height(view);
f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height);
return(max_target_y);
}
internal void
view_set_file(View *view, Editing_File *file, Models *models){
Font_Info *fnt_info;
@ -1534,10 +1570,7 @@ view_set_file(View *view, Editing_File *file, Models *models){
if (file_is_ready(file)){
view_measure_wraps(&models->mem.general, view);
view->recent->cursor = view_compute_cursor_from_pos(view, view->recent->cursor.pos);
#if 0
view->recent->scroll.max_y = 1000000000.f;
#endif
view->recent->scroll.max_y = view_compute_max_target_y(view);
view_move_view_to_cursor(view, &view->recent->scroll);
}
@ -1554,10 +1587,7 @@ view_set_file(View *view, Editing_File *file, Models *models){
if (file_is_ready(file)){
view_measure_wraps(&models->mem.general, view);
view->recent->cursor = view_compute_cursor_from_pos(view, file->state.cursor_pos);
#if 0
view->recent->scroll.max_y = 1000000000.f;
#endif
view->recent->scroll.max_y = view_compute_max_target_y(view);
view_move_view_to_cursor(view, &view->recent->scroll);
view->reinit_scrolling = 1;
@ -2938,22 +2968,6 @@ style_get_color(Style *style, Cpp_Token token){
return result;
}
inline f32
view_compute_max_target_y(i32 lowest_line, i32 line_height, f32 view_height){
f32 max_target_y = ((lowest_line+.5f)*line_height) - view_height*.5f;
max_target_y = clamp_bottom(0.f, max_target_y);
return(max_target_y);
}
internal f32
view_compute_max_target_y(View *view){
i32 lowest_line = view_compute_lowest_line(view);
i32 line_height = view->font_height;
f32 view_height = view_file_height(view);
f32 max_target_y = view_compute_max_target_y(lowest_line, line_height, view_height);
return(max_target_y);
}
internal void
remeasure_file_view(System_Functions *system, View *view){
if (file_is_ready(view->file_data.file)){
@ -3108,9 +3122,21 @@ view_open_file(System_Functions *system, Models *models,
File_Loading loading = system->file_load_begin(filename.str);
if (loading.exists){
b32 in_general_mem = 0;
Temp_Memory temp = begin_temp_memory(part);
char *buffer = push_array(part, char, loading.size);
// TODO(allen): How will we get temporary space for large
// buffers? The main partition isn't always big enough
// but getting a general block this large and copying it
// then freeing it is *super* dumb!
if (buffer == 0){
buffer = (char*)general_memory_allocate(general, loading.size);
if (buffer != 0){
in_general_mem = 1;
}
}
if (system->file_load_end(loading, buffer)){
file = working_set_alloc_always(working_set, general);
if (file){
@ -3123,6 +3149,10 @@ view_open_file(System_Functions *system, Models *models,
}
}
if (in_general_mem){
general_memory_free(general, buffer);
}
end_temp_memory(temp);
}
}

View File

@ -197,6 +197,9 @@ typedef Sys_Post_Job_Sig(System_Post_Job);
#define Sys_Cancel_Job_Sig(name) void name(Thread_Group_ID group_id, u32 job_id)
typedef Sys_Cancel_Job_Sig(System_Cancel_Job);
#define Sys_Check_Cancel_Sig(name) b32 name(Thread_Context *thread)
typedef Sys_Check_Cancel_Sig(System_Check_Cancel);
#define Sys_Grow_Thread_Memory_Sig(name) void name(Thread_Memory *memory)
typedef Sys_Grow_Thread_Memory_Sig(System_Grow_Thread_Memory);
@ -248,9 +251,10 @@ struct System_Functions{
System_CLI_Update_Step *cli_update_step;
System_CLI_End_Update *cli_end_update;
// threads: 5
// threads: 7
System_Post_Job *post_job;
System_Cancel_Job *cancel_job;
System_Check_Cancel *check_cancel;
System_Grow_Thread_Memory *grow_thread_memory;
System_Acquire_Lock *acquire_lock;
System_Release_Lock *release_lock;

View File

@ -40,9 +40,11 @@
struct Thread_Context{
u32 job_id;
b32 running;
b32 cancel;
Work_Queue *queue;
u32 id;
u32 group_id;
u32 windows_id;
HANDLE handle;
};
@ -50,6 +52,9 @@ struct Thread_Context{
struct Thread_Group{
Thread_Context *threads;
i32 count;
i32 cancel_lock0;
i32 cancel_cv0;
};
#define UseWinDll 1
@ -111,6 +116,18 @@ struct Sys_Bubble : public Bubble{
};
#endif
enum CV_ID{
CANCEL_CV0,
CANCEL_CV1,
CANCEL_CV2,
CANCEL_CV3,
CANCEL_CV4,
CANCEL_CV5,
CANCEL_CV6,
CANCEL_CV7,
CV_COUNT
};
struct Win32_Vars{
System_Functions system;
App_Functions app;
@ -128,6 +145,7 @@ struct Win32_Vars{
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;
Win32_Coroutine coroutine_data[18];
Win32_Coroutine *coroutine_free;
@ -277,10 +295,29 @@ Sys_Release_Lock_Sig(system_release_lock){
LeaveCriticalSection(&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);
}
internal void
system_signal_cv(i32 crit_id, i32 cv_id){
AllowLocal(crit_id);
WakeConditionVariable(win32vars.condition_vars + cv_id);
}
internal DWORD
JobThreadProc(LPVOID lpParameter){
Thread_Context *thread = (Thread_Context*)lpParameter;
Work_Queue *queue = thread->queue;
Work_Queue *queue = win32vars.queues + thread->group_id;
Thread_Group *group = win32vars.groups + thread->group_id;
i32 thread_index = thread->id - 1;
i32 cancel_lock = group->cancel_lock0 + thread_index;
i32 cancel_cv = group->cancel_cv0 + thread_index;
for (;;){
u32 read_index = queue->read_position;
@ -324,6 +361,13 @@ JobThreadProc(LPVOID lpParameter){
PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0);
full_job->running_thread = 0;
thread->running = 0;
system_acquire_lock(cancel_lock);
if (thread->cancel){
thread->cancel = 0;
system_signal_cv(cancel_lock, cancel_cv);
}
system_release_lock(cancel_lock);
}
}
}
@ -362,8 +406,18 @@ Sys_Post_Job_Sig(system_post_job){
return result;
}
// TODO(allen): I would like to get rid of job canceling
// but I still don't know what exactly I would do without it.
// NOTE(allen): New job cancelling system:
//
// Jobs are expected to periodically check their cancelation
// state, especially if they are taking a while.
//
// When the main thread asks to cancel a job it sets the cancel
// state and does not resume until the thread running the job
// signals that it is okay.
//
// Don't hold the frame lock while sleeping, as this can dead-lock
// the job thread and the main thread, and since main is sleeping
// they won't collide anyway.
internal
Sys_Cancel_Job_Sig(system_cancel_job){
Work_Queue *queue = win32vars.queues + group_id;
@ -372,7 +426,6 @@ Sys_Cancel_Job_Sig(system_cancel_job){
u32 job_index;
u32 thread_id;
Full_Job_Data *full_job;
Thread_Context *thread;
job_index = job_id % QUEUE_WRAP;
full_job = queue->jobs + job_index;
@ -382,19 +435,47 @@ Sys_Cancel_Job_Sig(system_cancel_job){
InterlockedCompareExchange(&full_job->running_thread,
0, THREAD_NOT_ASSIGNED);
if (thread_id != THREAD_NOT_ASSIGNED){
system_acquire_lock(CANCEL_LOCK0 + thread_id - 1);
thread = group->threads + thread_id - 1;
TerminateThread(thread->handle, 0);
u32 creation_flag = 0;
thread->handle = CreateThread(0, 0, JobThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id);
system_release_lock(CANCEL_LOCK0 + thread_id - 1);
thread->running = 0;
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 void
system_grow_thread_memory(Thread_Memory *memory){
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);
return(result);
}
internal
Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
void *old_data;
i32 old_size, new_size;
@ -1178,6 +1259,7 @@ Win32LoadSystemCode(){
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;
@ -1621,18 +1703,22 @@ WinMain(HINSTANCE hInstance,
memset(background, 0, sizeof(background));
win32vars.groups[BACKGROUND_THREADS].threads = background;
win32vars.groups[BACKGROUND_THREADS].count = ArrayCount(background);
win32vars.groups[BACKGROUND_THREADS].cancel_lock0 = CANCEL_LOCK0;
win32vars.groups[BACKGROUND_THREADS].cancel_cv0 = CANCEL_CV0;
Thread_Memory thread_memory[ArrayCount(background)];
win32vars.thread_memory = thread_memory;
win32vars.queues[BACKGROUND_THREADS].semaphore =
Win32Handle(CreateSemaphore(0, 0,
win32vars.groups[BACKGROUND_THREADS].count, 0));
win32vars.groups[BACKGROUND_THREADS].count,
0));
u32 creation_flag = 0;
for (i32 i = 0; i < win32vars.groups[BACKGROUND_THREADS].count; ++i){
Thread_Context *thread = win32vars.groups[BACKGROUND_THREADS].threads + i;
thread->id = i + 1;
thread->group_id = BACKGROUND_THREADS;
Thread_Memory *memory = win32vars.thread_memory + i;
*memory = thread_memory_zero();