switched to condition-variable based cancelation
This commit is contained in:
parent
43f65dd5ef
commit
a09851af12
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
116
win32_4ed.cpp
116
win32_4ed.cpp
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue