Eliminated old file change notification system; replaced OS layer job system with OS layer thread wrappers; moved coroutine implementation from OS layer to core

master
Allen Webster 2019-08-03 22:36:13 -07:00
parent d4db77b3fb
commit 2f6b9744bd
23 changed files with 484 additions and 2171 deletions

54
4ed.cpp
View File

@ -26,16 +26,16 @@ restore_state(Application_Links *app, App_Coroutine_State state){
app->type_coroutine = state.type;
}
internal Coroutine_Head*
app_coroutine_handle_request(Models *models, Coroutine_Head *co, u32 *vals){
Coroutine_Head *result = 0;
internal Coroutine*
app_coroutine_handle_request(Models *models, Coroutine *co, u32 *vals){
Coroutine *result = 0;
System_Functions *system = models->system;
switch (vals[2]){
case AppCoroutineRequest_NewFontFace:
{
Face_Description *description = ((Face_Description**)vals)[0];
Face_ID face_id = font_set_new_face(&models->font_set, description);
result = system->resume_coroutine(co, &face_id, vals);
result = coroutine_run(&models->coroutines, co, &face_id, vals);
}break;
case AppCoroutineRequest_ModifyFace:
@ -43,36 +43,22 @@ app_coroutine_handle_request(Models *models, Coroutine_Head *co, u32 *vals){
Face_Description *description = ((Face_Description**)vals)[0];
Face_ID face_id = ((Face_ID*)vals)[3];
b32 success = alter_font_and_update_files(system, models, face_id, description);
result = system->resume_coroutine(co, &success, vals);
result = coroutine_run(&models->coroutines, co, &success, vals);
}break;
}
return(result);
}
internal Coroutine_Head*
app_launch_coroutine(System_Functions *system, Application_Links *app, Coroutine_Type type, Coroutine_Head *co, void *in, u32 *out){
internal Coroutine*
app_coroutine_run(Models *models, App_Coroutine_Purpose purpose, Coroutine *co, void *in, u32 *out){
Application_Links *app = &models->app_links;
App_Coroutine_State prev_state = get_state(app);
app->current_coroutine = co;
app->type_coroutine = type;
app->type_coroutine = purpose;
u32 coroutine_out[4] = {};
Coroutine_Head *result = system->launch_coroutine(co, in, coroutine_out);
Coroutine *result = coroutine_run(&models->coroutines, co, in, coroutine_out);
for (;result != 0 && coroutine_out[2] != 0;){
result = app_coroutine_handle_request((Models*)app->cmd_context, result, coroutine_out);
}
block_copy(out, coroutine_out, sizeof(*out)*2);
restore_state(app, prev_state);
return(result);
}
internal Coroutine_Head*
app_resume_coroutine(System_Functions *system, Application_Links *app, Coroutine_Type type, Coroutine_Head *co, void *in, u32 *out){
App_Coroutine_State prev_state = get_state(app);
app->current_coroutine = co;
app->type_coroutine = type;
u32 coroutine_out[4] = {};
Coroutine_Head *result = system->resume_coroutine(co, in, coroutine_out);
for (;result != 0 && coroutine_out[2] != 0;){
result = app_coroutine_handle_request((Models*)app->cmd_context, co, coroutine_out);
result = app_coroutine_handle_request(models, result, coroutine_out);
}
block_copy(out, coroutine_out, sizeof(*out)*2);
restore_state(app, prev_state);
@ -475,7 +461,7 @@ interpret_binding_buffer(Models *models, void *buffer, i32 size){
#include "4ed_api_implementation.cpp"
internal void
command_caller(Coroutine_Head *coroutine){
command_caller(Coroutine *coroutine){
Command_In *cmd_in = (Command_In*)coroutine->in;
Models *models = cmd_in->models;
if (models->command_caller != 0){
@ -795,7 +781,7 @@ force_abort_coroutine(System_Functions *system, Models *models, View *view){
User_Input user_in = {};
user_in.abort = true;
for (u32 j = 0; j < 10 && models->command_coroutine != 0; ++j){
models->command_coroutine = app_resume_coroutine(system, &models->app_links, Co_Command, models->command_coroutine, &user_in, models->command_coroutine_flags);
models->command_coroutine = app_coroutine_run(models, Co_Command, models->command_coroutine, &user_in, models->command_coroutine_flags);
}
if (models->command_coroutine != 0){
// TODO(allen): post grave warning
@ -813,14 +799,14 @@ launch_command_via_event(System_Functions *system, Models *models, View *view, K
if (cmd_bind.custom != 0){
Assert(models->command_coroutine == 0);
Coroutine_Head *command_coroutine = system->create_coroutine(command_caller);
Coroutine *command_coroutine = coroutine_create(&models->coroutines, command_caller);
models->command_coroutine = command_coroutine;
Command_In cmd_in = {};
cmd_in.models = models;
cmd_in.bind = cmd_bind;
models->command_coroutine = app_launch_coroutine(system, &models->app_links, Co_Command, models->command_coroutine, &cmd_in, models->command_coroutine_flags);
models->command_coroutine = app_coroutine_run(models, Co_Command, models->command_coroutine, &cmd_in, models->command_coroutine_flags);
models->prev_command = cmd_bind;
if (event.keycode != key_animate){
@ -863,6 +849,9 @@ App_Init_Sig(app_init){
Arena *arena = &models->mem.arena;
// NOTE(allen): coroutines
coroutine_system_init(system, &models->coroutines);
// NOTE(allen): font set
font_set_init(system, &models->font_set);
@ -1010,6 +999,7 @@ App_Step_Sig(app_step){
}
}
#if 0
// NOTE(allen): check files are up to date
{
b32 mem_too_small = 0;
@ -1051,6 +1041,7 @@ App_Step_Sig(app_step){
end_temp(temp);
}
#endif
// NOTE(allen): reorganizing panels on screen
Vec2_i32 prev_dim = layout_get_root_size(&models->layout);
@ -1262,12 +1253,11 @@ App_Step_Sig(app_step){
case EventConsume_Command:
{
// NOTE(allen): update command coroutine
if (models->command_coroutine != 0){
models->key = *key_ptr;
Coroutine_Head *command_coroutine = models->command_coroutine;
Coroutine *command_coroutine = models->command_coroutine;
u32 abort_flags = models->command_coroutine_flags[1];
u32 get_flags = models->command_coroutine_flags[0] | abort_flags;
@ -1280,7 +1270,7 @@ App_Step_Sig(app_step){
user_in.key = *key_ptr;
user_in.command.command = cmd_bind.custom;
user_in.abort = ((abort_flags & event_flags) != 0);
models->command_coroutine = app_resume_coroutine(system, &models->app_links, Co_Command, command_coroutine, &user_in, models->command_coroutine_flags);
models->command_coroutine = app_coroutine_run(models, Co_Command, command_coroutine, &user_in, models->command_coroutine_flags);
if (user_in.key.keycode != key_animate){
models->animate_next_frame = true;

View File

@ -30,7 +30,7 @@ api_check_buffer(Editing_File *file){
internal b32
api_check_buffer_and_tokens(Editing_File *file){
return(api_check_buffer(file) && file->state.token_array.tokens != 0 && file->state.tokens_complete);
return(api_check_buffer(file) && file->state.token_array.tokens != 0);
}
internal b32
@ -856,14 +856,9 @@ DOC_SEE(Buffer_Setting_ID)
if (!file->settings.tokens_exist){
file_first_lex_serial(system, models, file);
}
if (!file->state.still_lexing){
file->settings.virtual_white = true;
full_remeasure = true;
}
else{
result = false;
}
}
}
else{
if (file->settings.virtual_white){
@ -2583,11 +2578,11 @@ DOC_SEE(User_Input)
System_Functions *system = models->system;
User_Input result = {};
if (app->type_coroutine == Co_Command){
Coroutine_Head *coroutine = (Coroutine_Head*)app->current_coroutine;
Coroutine *coroutine = (Coroutine*)app->current_coroutine;
Assert(coroutine != 0);
((u32*)coroutine->out)[0] = get_type;
((u32*)coroutine->out)[1] = abort_type;
system->yield_coroutine(coroutine);
coroutine_yield(coroutine);
result = *(User_Input*)coroutine->in;
}
return(result);
@ -3027,11 +3022,11 @@ DOC_SEE(Face_Description)
Face_ID result = 0;
if (is_running_coroutine(app)){
System_Functions *system = models->system;
Coroutine_Head *coroutine = (Coroutine_Head*)app->current_coroutine;
Coroutine *coroutine = (Coroutine*)app->current_coroutine;
Assert(coroutine != 0);
((Face_Description**)coroutine->out)[0] = description;
((u32*)coroutine->out)[2] = AppCoroutineRequest_NewFontFace;
system->yield_coroutine(coroutine);
coroutine_yield(coroutine);
result = *(Face_ID*)(coroutine->in);
}
else{
@ -3058,12 +3053,12 @@ DOC_SEE(try_create_new_face)
b32 result = false;
if (is_running_coroutine(app)){
System_Functions *system = models->system;
Coroutine_Head *coroutine = (Coroutine_Head*)app->current_coroutine;
Coroutine *coroutine = (Coroutine*)app->current_coroutine;
Assert(coroutine != 0);
((Face_Description**)coroutine->out)[0] = description;
((u32*)coroutine->out)[2] = AppCoroutineRequest_ModifyFace;
((u32*)coroutine->out)[3] = id;
system->yield_coroutine(coroutine);
coroutine_yield(coroutine);
result = *(b32*)(coroutine->in);
}
else{

View File

@ -38,7 +38,8 @@ struct Models{
Mapping mapping;
Command_Binding prev_command;
Coroutine_Head *command_coroutine;
Coroutine_Group coroutines;
Coroutine *command_coroutine;
u32 command_coroutine_flags[2];
Child_Process_Container child_processes;
@ -176,7 +177,8 @@ struct App_Vars{
App_State state;
};
enum Coroutine_Type{
typedef i32 App_Coroutine_Purpose;
enum{
Co_View,
Co_Command,
};

View File

@ -44,6 +44,7 @@ struct Mem_Options{
#include "4ed_render_target.h"
#include "4ed.h"
#include "4ed_buffer_model.h"
#include "4ed_coroutine.h"
#define FCPP_FORBID_MALLOC
#include "4coder_lib/4cpp_lexer.h"
@ -72,6 +73,7 @@ struct Mem_Options{
#include "4ed_font_set.h"
#include "4ed_app_models.h"
#include "4ed_coroutine.cpp"
#include "4ed_mem.cpp"
#include "4ed_ptr_check.cpp"
#include "4ed_memory_bank.cpp"

View File

@ -483,7 +483,7 @@ file_measure_wraps(System_Functions *system, Mem_Options *mem, Editing_File *fil
Potential_Wrap_Indent_Pair *potential_marks = 0;
i32 max_wrap_indent_mark = Million(1);
if (params.virtual_white && file->state.tokens_complete && !file->state.still_lexing){
if (params.virtual_white && file->state.token_array.tokens != 0){
wrap_state_init(&wrap_state, file, face);
use_tokens = true;

162
4ed_coroutine.cpp Normal file
View File

@ -0,0 +1,162 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 19.07.2017
*
* Coroutine implementation from thread+mutex+cv
*
*/
// TOP
internal void
coroutine__pass_control(Coroutine *me, Coroutine *other,
Coroutine_State my_new_state, Coroutine_Pass_Control control){
Assert(me->state == CoroutineState_Active);
Assert(me->sys == other->sys);
System_Functions *system = me->system;
me->state = my_new_state;
other->state = CoroutineState_Active;
me->sys->active = other;
system->condition_variable_signal(other->cv);
if (control == CoroutinePassControl_BlockMe){
for (;me->state != CoroutineState_Active;){
system->condition_variable_wait(me->cv, me->sys->lock);
}
}
}
internal void
coroutine_main(void *ptr){
Coroutine *me = (Coroutine*)ptr;
System_Functions *system = me->system;
// NOTE(allen): Init handshake
Assert(me->state == CoroutineState_Dead);
system->mutex_acquire(me->sys->lock);
me->sys->did_init = true;
system->condition_variable_signal(me->sys->init_cv);
for (;;){
// NOTE(allen): Wait until someone wakes us up, then go into our procedure.
for (;me->state != CoroutineState_Active;){
system->condition_variable_wait(me->cv, me->sys->lock);
}
Assert(me->type != CoroutineType_Root);
Assert(me->yield_ctx != 0);
Assert(me->function != 0);
me->function(me);
// NOTE(allen): Wake up the caller and set this coroutine back to being dead.
Coroutine *other = me->yield_ctx;
Assert(other != 0);
Assert(other->state == CoroutineState_Waiting);
coroutine__pass_control(me, other, CoroutineState_Dead, CoroutinePassControl_ExitMe);
me->function = 0;
}
}
internal void
coroutine_sub_init(Coroutine *co, Coroutine_Group *sys){
System_Functions *system = sys->system;
block_zero_struct(co);
co->system = system;
co->sys = sys;
co->state = CoroutineState_Dead;
co->type = CoroutineType_Sub;
co->cv = system->condition_variable_make();
sys->did_init = false;
co->thread = system->thread_launch(coroutine_main, co);
for (;!sys->did_init;){
system->condition_variable_wait(sys->init_cv, sys->lock);
}
}
internal void
coroutine_system_init(System_Functions *system, Coroutine_Group *sys){
sys->arena = make_arena_system(system);
sys->system = system;
Coroutine *root = &sys->root;
sys->lock = system->mutex_make();
sys->init_cv = system->condition_variable_make();
sys->active = root;
block_zero_struct(root);
root->system = system;
root->sys = sys;
root->state = CoroutineState_Active;
root->type = CoroutineType_Root;
root->cv = system->condition_variable_make();
sys->unused = 0;
system->mutex_acquire(sys->lock);
}
internal Coroutine*
coroutine_system_alloc(Coroutine_Group *sys){
Coroutine *result = sys->unused;
if (result != 0){
sll_stack_pop(sys->unused);
}
else{
result = push_array(&sys->arena, Coroutine, 1);
coroutine_sub_init(result, sys);
}
result->next = 0;
return(result);
}
internal void
coroutine_system_free(Coroutine_Group *sys, Coroutine *coroutine){
sll_stack_push(sys->unused, coroutine);
}
////////////////////////////////
internal Coroutine*
coroutine_create(Coroutine_Group *coroutines, Coroutine_Function *func){
Coroutine *result = coroutine_system_alloc(coroutines);
Assert(result->state == CoroutineState_Dead);
result->function = func;
return(result);
}
internal Coroutine*
coroutine_run(Coroutine_Group *sys, Coroutine *other, void *in, void *out_arena){
other->in = in;
other->out = out;
Coroutine *me = other->sys->active;
Assert(me != 0);
Assert(me->sys == other->sys);
Assert(other->state == CoroutineState_Dead || other->state == CoroutineState_Inactive);
other->yield_ctx = me;
coroutine__pass_control(me, other, CoroutineState_Waiting, CoroutinePassControl_BlockMe);
Assert(me == other->sys->active);
Coroutine *result = other;
if (other->state == CoroutineState_Dead){
coroutine_system_free(sys, other);
result = 0;
}
return(result);
}
internal void
coroutine_yield(Coroutine *me){
Coroutine *other = me->yield_ctx;
Assert(other != 0);
Assert(me->sys == other->sys);
Assert(other->state == CoroutineState_Waiting);
coroutine__pass_control(me, other, CoroutineState_Inactive, CoroutinePassControl_BlockMe);
}
// BOTTOM

67
4ed_coroutine.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 03.08.2019
*
* Coroutine implementation from thread+mutex+cv
*
*/
// TOP
#if !defined(FRED_COROUTINE_H)
#define FRED_COROUTINE_H
typedef void Coroutine_Function(struct Coroutine *head);
typedef u32 Coroutine_State;
enum{
CoroutineState_Dead,
CoroutineState_Active,
CoroutineState_Inactive,
CoroutineState_Waiting,
};
typedef u32 Coroutine_Type;
enum{
CoroutineType_Uninitialized,
CoroutineType_Root,
CoroutineType_Sub,
};
struct Coroutine{
Coroutine *next;
void *in;
void *out;
System_Functions *system;
System_Thread thread;
System_Condition_Variable cv;
struct Coroutine_Group *sys;
Coroutine_Function *function;
Coroutine *yield_ctx;
Coroutine_State state;
Coroutine_Type type;
};
struct Coroutine_Group{
Arena arena;
System_Functions *system;
System_Mutex lock;
System_Condition_Variable init_cv;
b32 did_init;
Coroutine *active;
Coroutine *unused;
Coroutine root;
};
////////////////////////////////
typedef i32 Coroutine_Pass_Control;
enum{
CoroutinePassControl_ExitMe,
CoroutinePassControl_BlockMe,
};
#endif
// BOTTOM

View File

@ -12,14 +12,6 @@
internal void
edit_pre_state_change(Models *models, Heap *heap, Editing_File *file){
System_Functions *system = models->system;
if (file->state.still_lexing){
system->cancel_job(BACKGROUND_THREADS, file->state.lex_job);
if (file->state.swap_array.tokens){
heap_free(heap, file->state.swap_array.tokens);
file->state.swap_array.tokens = 0;
}
file->state.still_lexing = 0;
}
file_add_dirty_flag(file, DirtyState_UnsavedChanges);
file_unmark_edit_finished(&models->working_set, file);
Layout *layout = &models->layout;

View File

@ -485,13 +485,6 @@ file_create_from_string(System_Functions *system, Models *models, Editing_File *
internal void
file_free(System_Functions *system, Heap *heap, Lifetime_Allocator *lifetime_allocator, Working_Set *working_set, Editing_File *file){
if (file->state.still_lexing){
system->cancel_job(BACKGROUND_THREADS, file->state.lex_job);
if (file->state.swap_array.tokens){
heap_free(heap, file->state.swap_array.tokens);
file->state.swap_array.tokens = 0;
}
}
if (file->state.token_array.tokens){
heap_free(heap, file->state.token_array.tokens);
}
@ -522,7 +515,7 @@ file_get_current_record_index(Editing_File *file){
internal b32
file_tokens_are_ready(Editing_File *file){
return(file->state.token_array.tokens != 0 && file->state.tokens_complete && !file->state.still_lexing);
return(file->state.token_array.tokens != 0);
}
internal Managed_Scope

View File

@ -78,11 +78,7 @@ struct Editing_File_State{
i32 current_record_index;
Cpp_Token_Array token_array;
Cpp_Token_Array swap_array;
u32 lex_job;
b8 tokens_complete;
b8 still_lexing;
b8 in_edit_handler;
b32 in_edit_handler;
Text_Effect paste_effect;

View File

@ -9,159 +9,13 @@
// TOP
// TODO(allen): this needs a rewrite _BAD_
internal void
job_full_lex(System_Functions *system, Thread_Context *thread, Thread_Memory *memory, void *data[4]){
Editing_File *file = (Editing_File*)data[0];
Heap *heap = (Heap*)data[1];
Models *models = (Models*)data[2];
Parse_Context parse_context = parse_context_get(&models->parse_context_memory, file->settings.parse_context_id, memory->data, memory->size);
if (!parse_context.valid){
return;
}
Gap_Buffer *buffer = &file->state.buffer;
i32 text_size = buffer_size(buffer);
u32 aligned_buffer_size = (text_size + 3)&(~3);
for (;memory->size < aligned_buffer_size + parse_context.memory_size;){
void *old_base = memory->data;
system->grow_thread_memory(memory);
parse_context_rebase(&parse_context, old_base, memory->data);
}
u8 *data_ptr = (u8*)memory->data;
umem data_size = memory->size;
data_ptr += parse_context.memory_size;
data_size -= parse_context.memory_size;
Cpp_Token_Array tokens = {};
tokens.tokens = (Cpp_Token*)(data_ptr);
tokens.max_count = (u32)(data_size / sizeof(Cpp_Token));
tokens.count = 0;
b32 still_lexing = true;
Cpp_Lex_Data lex = cpp_lex_data_init(file->settings.tokens_without_strings, parse_context.kw_table, parse_context.pp_table);
String_Const_u8 chunk_space[3];
Cursor chunk_cursor = make_cursor(chunk_space, sizeof(chunk_space));
String_Const_u8_Array chunks = buffer_get_chunks(&chunk_cursor, buffer);
i32 chunk_index = 0;
do{
u8 *chunk = chunks.vals[chunk_index].str;
umem chunk_size = chunks.vals[chunk_index].size;
i32 result = cpp_lex_step(&lex, (char*)chunk, (i32)chunk_size, text_size, &tokens, 2048);
switch (result){
case LexResult_NeedChunk:
{
++chunk_index;
Assert(chunk_index < chunks.count);
}break;
case LexResult_NeedTokenMemory:
{
if (system->check_cancel(thread)){
return;
}
void *old_base = memory->data;
system->grow_thread_memory(memory);
cpp_rebase_tables(&lex, old_base, memory->data);
data_ptr = (u8*)memory->data;
data_size = memory->size;
data_ptr += parse_context.memory_size;
data_size -= parse_context.memory_size;
tokens.tokens = (Cpp_Token*)(data_ptr);
tokens.max_count = (u32)(data_size / sizeof(Cpp_Token));
}break;
case LexResult_HitTokenLimit:
{
if (system->check_cancel(thread)){
return;
}
}break;
case LexResult_Finished:
{
still_lexing = false;
}break;
}
}while(still_lexing);
i32 new_max = round_up_i32(tokens.count + 1, KB(1));
system->acquire_lock(FRAME_LOCK);
{
Assert(file->state.swap_array.tokens == 0);
file->state.swap_array.tokens = heap_array(heap, Cpp_Token, new_max);
}
system->release_lock(FRAME_LOCK);
u8 *dest = (u8*)file->state.swap_array.tokens;
u8 *src = (u8*)tokens.tokens;
memcpy(dest, src, tokens.count*sizeof(Cpp_Token));
system->acquire_lock(FRAME_LOCK);
{
Cpp_Token_Array *file_token_array = &file->state.token_array;
file_token_array->count = tokens.count;
file_token_array->max_count = new_max;
if (file_token_array->tokens){
heap_free(heap, file_token_array->tokens);
}
file_token_array->tokens = file->state.swap_array.tokens;
file->state.swap_array.tokens = 0;
}
file->state.tokens_complete = true;
file->state.still_lexing = false;
file_mark_edit_finished(&models->working_set, file);
system->release_lock(FRAME_LOCK);
}
internal void
file_kill_tokens(System_Functions *system, Heap *heap, Editing_File *file){
file->settings.tokens_exist = false;
if (file->state.still_lexing){
system->cancel_job(BACKGROUND_THREADS, file->state.lex_job);
if (file->state.swap_array.tokens){
heap_free(heap, file->state.swap_array.tokens);
file->state.swap_array.tokens = 0;
}
}
if (file->state.token_array.tokens){
if (file->state.token_array.tokens != 0){
heap_free(heap, file->state.token_array.tokens);
}
file->state.tokens_complete = false;
file->state.token_array = null_cpp_token_array;
}
internal void
file_first_lex_parallel(System_Functions *system, Models *models, Editing_File *file){
Heap *heap = &models->mem.heap;
file->settings.tokens_exist = true;
if (!file->is_loading && !file->state.still_lexing){
Assert(file->state.token_array.tokens == 0);
file->state.tokens_complete = false;
file->state.still_lexing = true;
Job_Data job;
job.callback = job_full_lex;
job.data[0] = file;
job.data[1] = heap;
job.data[2] = models;
file->state.lex_job = system->post_job(BACKGROUND_THREADS, job);
}
block_zero_struct(&file->state.token_array);
}
internal void
@ -171,8 +25,6 @@ file_first_lex_serial(System_Functions *system, Models *models, Editing_File *fi
Heap *heap = &mem->heap;
file->settings.tokens_exist = true;
Assert(!file->state.still_lexing);
if (file->is_loading == 0){
Assert(file->state.token_array.tokens == 0);
@ -200,7 +52,7 @@ file_first_lex_serial(System_Functions *system, Models *models, Editing_File *fi
i32 chunk_index = 0;
Cpp_Token_Array *swap_array = &file->state.swap_array;
Cpp_Token_Array new_array = {};
do{
u8 *chunk = chunks.vals[chunk_index].str;
@ -218,22 +70,22 @@ file_first_lex_serial(System_Functions *system, Models *models, Editing_File *fi
case LexResult_Finished:
case LexResult_NeedTokenMemory:
{
u32 new_max = round_up_u32(swap_array->count + new_tokens.count + 1, KB(1));
if (swap_array->tokens == 0){
swap_array->tokens = heap_array(heap, Cpp_Token, new_max);
u32 new_max = round_up_u32(new_array.count + new_tokens.count + 1, KB(1));
if (new_array.tokens == 0){
new_array.tokens = heap_array(heap, Cpp_Token, new_max);
}
else{
u32 old_count = swap_array->count;
u32 old_count = new_array.count;
Cpp_Token *new_token_mem = heap_array(heap, Cpp_Token, new_max);
memcpy(new_token_mem, swap_array->tokens, sizeof(*new_token_mem)*old_count);
heap_free(heap, swap_array->tokens);
swap_array->tokens = new_token_mem;
memcpy(new_token_mem, new_array.tokens, sizeof(*new_token_mem)*old_count);
heap_free(heap, new_array.tokens);
new_array.tokens = new_token_mem;
}
swap_array->max_count = new_max;
new_array.max_count = new_max;
Assert(swap_array->count + new_tokens.count <= swap_array->max_count);
memcpy(swap_array->tokens + swap_array->count, new_tokens.tokens, new_tokens.count*sizeof(Cpp_Token));
swap_array->count += new_tokens.count;
Assert(new_array.count + new_tokens.count <= new_array.max_count);
memcpy(new_array.tokens + new_array.count, new_tokens.tokens, new_tokens.count*sizeof(Cpp_Token));
new_array.count += new_tokens.count;
new_tokens.count = 0;
if (result == LexResult_Finished){
@ -246,155 +98,23 @@ file_first_lex_serial(System_Functions *system, Models *models, Editing_File *fi
} while (still_lexing);
Cpp_Token_Array *token_array = &file->state.token_array;
token_array->count = swap_array->count;
token_array->max_count = swap_array->max_count;
token_array->count = new_array.count;
token_array->max_count = new_array.max_count;
if (token_array->tokens != 0){
heap_free(heap, token_array->tokens);
}
token_array->tokens = swap_array->tokens;
token_array->tokens = new_array.tokens;
swap_array->tokens = 0;
swap_array->count = 0;
swap_array->max_count = 0;
file->state.tokens_complete = true;
file->state.still_lexing = false;
new_array.tokens = 0;
new_array.count = 0;
new_array.max_count = 0;
end_temp(temp);
file->state.tokens_complete = true;
file_mark_edit_finished(&models->working_set, file);
}
}
internal b32
file_relex_parallel(System_Functions *system, Models *models, Editing_File *file, i32 start_i, i32 end_i, i32 shift_amount){
Mem_Options *mem = &models->mem;
Arena *scratch = &mem->arena;
Heap *heap = &mem->heap;
b32 result = true;
if (file->state.token_array.tokens == 0){
file_first_lex_parallel(system, models, file);
}
else{
b32 internal_lex = !file->state.still_lexing;
if (internal_lex){
Gap_Buffer *buffer = &file->state.buffer;
i32 extra_tolerance = 100;
Cpp_Token_Array *array = &file->state.token_array;
Cpp_Relex_Range relex_range = cpp_get_relex_range(array, start_i, end_i);
i32 relex_space_size = relex_range.end_token_index - relex_range.start_token_index + extra_tolerance;
Temp_Memory temp = begin_temp(scratch);
Parse_Context parse_context = parse_context_get(scratch, &models->parse_context_memory, file->settings.parse_context_id);
Assert(parse_context.valid);
Cpp_Token_Array relex_array;
relex_array.count = 0;
relex_array.max_count = relex_space_size;
relex_array.tokens = push_array(scratch, Cpp_Token, relex_array.max_count);
i32 size = buffer_size(buffer);
Cpp_Relex_Data state = cpp_relex_init(array, start_i, end_i, shift_amount, file->settings.tokens_without_strings, parse_context.kw_table, parse_context.pp_table);
String_Const_u8_Array chunk_space[3];
Cursor chunk_cursor = make_cursor(chunk_space, sizeof(chunk_space));
String_Const_u8_Array chunks = buffer_get_chunks(&chunk_cursor, buffer, BufferGetChunk_ZeroTerminated);
i32 chunk_index = 0;
u8 *chunk = chunks.vals[chunk_index].str;
umem chunk_size = chunks.vals[chunk_index].size;
for (;!cpp_relex_is_start_chunk(&state, (char*)chunk, (i32)chunk_size);){
++chunk_index;
Assert(chunk_index < chunks.count);
chunk = chunks.vals[chunk_index].str;
chunk_size = chunks.vals[chunk_index].size;
}
for (;;){
Cpp_Lex_Result lex_result =
cpp_relex_step(&state, (char*)chunk, (i32)chunk_size, size, array, &relex_array);
switch (lex_result){
case LexResult_NeedChunk:
{
++chunk_index;
Assert(chunk_index < chunks.count);
chunk = chunks.vals[chunk_index].str;
chunk_size = chunks.vals[chunk_index].size;
}break;
case LexResult_NeedTokenMemory:
{
internal_lex = false;
}goto doublebreak;
case LexResult_Finished: goto doublebreak;
}
}
doublebreak:;
if (internal_lex){
i32 new_count = cpp_relex_get_new_count(&state, array->count, &relex_array);
if (new_count > array->max_count){
i32 new_max = round_up_i32(new_count, KB(1));
void *memory = heap_allocate(heap, new_max*sizeof(Cpp_Token));
memcpy(memory, array->tokens, array->count*sizeof(Cpp_Token));
heap_free(heap, array->tokens);
array->tokens = (Cpp_Token*)memory;
array->max_count = new_max;
}
cpp_relex_complete(&state, array, &relex_array);
file_mark_edit_finished(&models->working_set, file);
}
else{
cpp_relex_abort(&state, array);
}
end_temp(temp);
}
if (!internal_lex){
Cpp_Token_Array *array = &file->state.token_array;
Cpp_Get_Token_Result get_token_result = cpp_get_token(*array, end_i);
i32 end_token_i = get_token_result.token_index;
if (end_token_i < 0){
end_token_i = 0;
}
else if (end_i > array->tokens[end_token_i].start){
++end_token_i;
}
cpp_shift_token_starts(array, end_token_i, shift_amount);
--end_token_i;
if (end_token_i >= 0){
Cpp_Token *token = array->tokens + end_token_i;
if (token->start < end_i && token->start + token->size > end_i){
token->size += shift_amount;
}
}
file->state.still_lexing = true;
Job_Data job = {};
job.callback = job_full_lex;
job.data[0] = file;
job.data[1] = heap;
job.data[2] = models;
file->state.lex_job = system->post_job(BACKGROUND_THREADS, job);
result = false;
}
}
return(result);
}
internal b32
file_relex_serial(System_Functions *system, Models *models, Editing_File *file, i32 start_i, i32 end_i, i32 shift_amount){
Mem_Options *mem = &models->mem;
@ -405,8 +125,6 @@ file_relex_serial(System_Functions *system, Models *models, Editing_File *file,
file_first_lex_serial(system, models, file);
}
else{
Assert(!file->state.still_lexing);
Gap_Buffer *buffer = &file->state.buffer;
Cpp_Token_Array *array = &file->state.token_array;
@ -477,23 +195,13 @@ file_relex_serial(System_Functions *system, Models *models, Editing_File *file,
internal void
file_first_lex(System_Functions *system, Models *models, Editing_File *file){
if (!file->settings.virtual_white){
file_first_lex_parallel(system, models, file);
}
else{
file_first_lex_serial(system, models, file);
}
}
internal void
file_relex(System_Functions *system, Models *models, Editing_File *file, i32 start, i32 end, i32 shift_amount){
if (!file->settings.virtual_white){
file_relex_parallel(system, models, file, start, end, shift_amount);
}
else{
file_relex_serial(system, models, file, start, end, shift_amount);
}
}
// BOTTOM

View File

@ -1,56 +0,0 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 20.07.2016
*
* File tracking API.
*
*/
// TOP
#if !defined(FILE_TRACK_4TECH_H)
#define FILE_TRACK_4TECH_H
#if !defined(FILE_TRACK_LINK)
# define FILE_TRACK_LINK static
#endif
struct File_Track_System{
u8 opaque[128];
};
typedef i32 File_Track_Result;
enum{
FileTrack_Good = 0,
FileTrack_MemoryTooSmall = 1,
FileTrack_OutOfTableMemory = 2,
FileTrack_OutOfListenerMemory = 3,
FileTrack_NoMoreEvents = 4,
FileTrack_FileSystemError = 5
};
FILE_TRACK_LINK File_Track_Result
init_track_system(File_Track_System *system, Partition *scratch, void *table_memory, i32 table_memory_size, void *listener_memory, i32 listener_memory_size);
FILE_TRACK_LINK File_Track_Result
add_listener(File_Track_System *system, Partition *scratch, u8 *filename);
FILE_TRACK_LINK File_Track_Result
remove_listener(File_Track_System *system, Partition *scratch, u8 *filename);
FILE_TRACK_LINK File_Track_Result
move_track_system(File_Track_System *system, Partition *scratch, void *mem, i32 size);
FILE_TRACK_LINK File_Track_Result
expand_track_system_listeners(File_Track_System *system, Partition *scratch, void *mem, i32 size);
FILE_TRACK_LINK File_Track_Result
get_change_event(File_Track_System *system, Partition *scratch, u8 *buffer, i32 max, i32 *size);
FILE_TRACK_LINK File_Track_Result
shut_down_track_system(File_Track_System *system, Partition *scratch);
#endif
// BOTTOM

View File

@ -45,16 +45,6 @@ typedef Sys_Load_Close_Sig(System_Load_Close);
#define Sys_Save_File_Sig(name) File_Attributes name(char *filename, char *buffer, u32 size)
typedef Sys_Save_File_Sig(System_Save_File);
// file changes
#define Sys_Add_Listener_Sig(name) b32 name(char *filename)
typedef Sys_Add_Listener_Sig(System_Add_Listener);
#define Sys_Remove_Listener_Sig(name) b32 name(char *filename)
typedef Sys_Remove_Listener_Sig(System_Remove_Listener);
#define Sys_Get_File_Change_Sig(name) b32 name(char *buffer, i32 max, b32 *mem_too_small, i32 *required_size)
typedef Sys_Get_File_Change_Sig(System_Get_File_Change);
// time
#define Sys_Now_Time_Sig(name) u64 name()
typedef Sys_Now_Time_Sig(System_Now_Time);
@ -98,98 +88,49 @@ typedef Sys_CLI_Update_Step_Sig(System_CLI_Update_Step);
#define Sys_CLI_End_Update_Sig(name) b32 name(CLI_Handles *cli)
typedef Sys_CLI_End_Update_Sig(System_CLI_End_Update);
// coroutine
struct Coroutine_Head{
void *in;
void *out;
};
#define COROUTINE_SIG(n) void n(Coroutine_Head *coroutine)
typedef COROUTINE_SIG(Coroutine_Function);
#define Sys_Create_Coroutine_Sig(name) Coroutine_Head *name(Coroutine_Function *func)
typedef Sys_Create_Coroutine_Sig(System_Create_Coroutine);
#define Sys_Launch_Coroutine_Sig(name) Coroutine_Head *name(Coroutine_Head *head, void *in, void *out)
typedef Sys_Launch_Coroutine_Sig(System_Launch_Coroutine);
#define Sys_Resume_Coroutine_Sig(name) Coroutine_Head *name(Coroutine_Head *head, void *in, void *out)
typedef Sys_Resume_Coroutine_Sig(System_Resume_Coroutine);
#define Sys_Yield_Coroutine_Sig(name) void name(Coroutine_Head *head)
typedef Sys_Yield_Coroutine_Sig(System_Yield_Coroutine);
//
#define Sys_Open_Color_Picker_Sig(name) void name(Color_Picker *picker)
typedef Sys_Open_Color_Picker_Sig(System_Open_Color_Picker);
// thread
struct Thread_Context;
typedef Plat_Handle System_Thread;
typedef Plat_Handle System_Mutex;
typedef Plat_Handle System_Condition_Variable;
typedef void Thread_Function(void *ptr);
enum Lock_ID{
FRAME_LOCK,
CANCEL_LOCK0,
CANCEL_LOCK1,
CANCEL_LOCK2,
CANCEL_LOCK3,
CANCEL_LOCK4,
CANCEL_LOCK5,
CANCEL_LOCK6,
CANCEL_LOCK7,
LOCK_COUNT
};
#define Sys_Thread_Launch_Sig(name) System_Thread name(Thread_Function *proc, void *ptr)
typedef Sys_Thread_Launch_Sig(System_Thread_Launch);
enum Thread_Group_ID{
BACKGROUND_THREADS,
THREAD_GROUP_COUNT
};
#define Sys_Thread_Join_Sig(name) void name(System_Thread thread)
typedef Sys_Thread_Join_Sig(System_Thread_Join);
struct Thread_Memory{
void *data;
u32 size;
u32 id;
};
global Thread_Memory null_thread_memory = {};
#define Sys_Thread_Free_Sig(name) void name(System_Thread thread)
typedef Sys_Thread_Free_Sig(System_Thread_Free);
struct Thread_Exchange;
struct System_Functions;
#define Sys_Mutex_Make_Sig(name) System_Mutex name(void)
typedef Sys_Mutex_Make_Sig(System_Mutex_Make);
#define Job_Callback_Sig(name) void name( \
System_Functions *system, \
Thread_Context *thread, \
Thread_Memory *memory, \
void *data[4])
#define Sys_Mutex_Acquire_Sig(name) void name(System_Mutex mutex)
typedef Sys_Mutex_Acquire_Sig(System_Mutex_Acquire);
typedef void Job_Callback(System_Functions *system, Thread_Context *thread, Thread_Memory *memory, void *data[4]);
#define Sys_Mutex_Release_Sig(name) void name(System_Mutex mutex)
typedef Sys_Mutex_Release_Sig(System_Mutex_Release);
struct Job_Data{
Job_Callback *callback;
void *data[4];
};
#define Sys_Mutex_Free_Sig(name) void name(System_Mutex mutex)
typedef Sys_Mutex_Free_Sig(System_Mutex_Free);
#define QUEUE_WRAP 256
#define Sys_Condition_Variable_Make_Sig(name) System_Condition_Variable name(void)
typedef Sys_Condition_Variable_Make_Sig(System_Condition_Variable_Make);
#define THREAD_NOT_ASSIGNED 0xFFFFFFFF
#define Sys_Condition_Variable_Wait_Sig(name) void name(System_Condition_Variable cv, System_Mutex mutex)
typedef Sys_Condition_Variable_Wait_Sig(System_Condition_Variable_Wait);
#define Sys_Post_Job_Sig(name) u32 name(Thread_Group_ID group_id, Job_Data job)
typedef Sys_Post_Job_Sig(System_Post_Job);
#define Sys_Condition_Variable_Signal_Sig(name) void name(System_Condition_Variable cv)
typedef Sys_Condition_Variable_Signal_Sig(System_Condition_Variable_Signal);
#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);
#define Sys_Acquire_Lock_Sig(name) void name(i32 id)
typedef Sys_Acquire_Lock_Sig(System_Acquire_Lock);
#define Sys_Release_Lock_Sig(name) void name(i32 id)
typedef Sys_Release_Lock_Sig(System_Release_Lock);
#define Sys_Condition_Variable_Free_Sig(name) void name(System_Condition_Variable cv)
typedef Sys_Condition_Variable_Free_Sig(System_Condition_Variable_Free);
// memory
#define Sys_Memory_Allocate_Sig(name) void* name(umem size)
@ -223,12 +164,9 @@ struct System_Functions{
Graphics_Get_Texture_Function *get_texture;
Graphics_Fill_Texture_Function *fill_texture;
// files (tracked api): 11
// files
System_Get_Canonical *get_canonical;
System_Get_File_List *get_file_list;
System_Add_Listener *add_listener;
System_Remove_Listener *remove_listener;
System_Get_File_Change *get_file_change;
System_Quick_File_Attributes *quick_file_attributes;
System_Load_Handle *load_handle;
System_Load_Attributes *load_attributes;
@ -236,22 +174,16 @@ struct System_Functions{
System_Load_Close *load_close;
System_Save_File *save_file;
// time: 4
// time
System_Now_Time *now_time;
System_Wake_Up_Timer_Create *wake_up_timer_create;
System_Wake_Up_Timer_Release *wake_up_timer_release;
System_Wake_Up_Timer_Set *wake_up_timer_set;
// clipboard: 1
// clipboard
System_Post_Clipboard *post_clipboard;
// coroutine: 4
System_Create_Coroutine *create_coroutine;
System_Launch_Coroutine *launch_coroutine;
System_Resume_Coroutine *resume_coroutine;
System_Yield_Coroutine *yield_coroutine;
// cli: 4
// cli
System_CLI_Call *cli_call;
System_CLI_Begin_Update *cli_begin_update;
System_CLI_Update_Step *cli_update_step;
@ -260,15 +192,20 @@ struct System_Functions{
// TODO(allen):
System_Open_Color_Picker *open_color_picker;
// threads: 6
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;
// threads
System_Thread_Launch *thread_launch;
System_Thread_Join *thread_join;
System_Thread_Free *thread_free;
System_Mutex_Make *mutex_make;
System_Mutex_Acquire *mutex_acquire;
System_Mutex_Release *mutex_release;
System_Mutex_Free *mutex_free;
System_Condition_Variable_Make *condition_variable_make;
System_Condition_Variable_Wait *condition_variable_wait;
System_Condition_Variable_Signal *condition_variable_signal;
System_Condition_Variable_Free *condition_variable_free;
// custom: 9
// custom
System_Memory_Allocate *memory_allocate;
System_Memory_Set_Protection *memory_set_protection;
System_Memory_Free *memory_free;

View File

@ -524,9 +524,9 @@ render_loaded_file_in_view__inner(Models *models, Render_Target *target, View *v
Assert(!file->is_dummy);
Assert(buffer_good(&file->state.buffer));
b32 tokens_use = file->state.tokens_complete && (file->state.token_array.count > 0);
Cpp_Token_Array token_array = file->state.token_array;
b32 wrapped = !file->settings.unwrapped_lines;
b32 tokens_use = (token_array.tokens != 0);
b32 wrapped = (!file->settings.unwrapped_lines);
Face_ID font_id = file->settings.font_id;
i32 *line_starts = file->state.buffer.line_starts;

View File

@ -307,7 +307,6 @@ file_bind_file_name(System_Functions *system, Heap *heap, Working_Set *working_s
file->canon.name_size = size;
block_copy(file->canon.name_space, canon_file_name.str, size);
file_name_terminate(&file->canon);
system->add_listener((char*)file->canon.name_space);
b32 result = working_set_canon_add(working_set, file, string_from_file_name(&file->canon));
Assert(result);
}
@ -316,7 +315,6 @@ internal void
buffer_unbind_file(System_Functions *system, Working_Set *working_set, Editing_File *file){
Assert(file->unique_name.name_size == 0);
Assert(file->canon.name_size != 0);
system->remove_listener((char*)file->canon.name_space);
working_set_canon_remove(working_set, string_from_file_name(&file->canon));
file->canon.name_size = 0;
}

View File

@ -1,255 +0,0 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 19.07.2017
*
* Coroutine implementation from thread+mutex+cv
*
*/
// TOP
typedef u32 Coroutine_State;
enum{
CoroutineState_Dead,
CoroutineState_Active,
CoroutineState_Inactive,
CoroutineState_Waiting,
};
typedef u32 Coroutine_Type;
enum{
CoroutineType_Uninitialized,
CoroutineType_Root,
CoroutineType_Sub,
};
struct Coroutine{
Coroutine_Head head;
Thread thread;
Condition_Variable cv;
struct Coroutine_System *sys;
Coroutine_Function *function;
Coroutine *yield_ctx;
Coroutine_State state;
Coroutine_Type type;
};
struct Coroutine_System{
Mutex lock;
Condition_Variable init_cv;
b32 did_init;
Coroutine *active;
};
#define COROUTINE_INT_SKIP_SLEEP false
internal void
coroutine_internal_pass_control(Coroutine *me, Coroutine *other, Coroutine_State my_new_state, b32 do_sleep_loop = true){
Assert(me->state == CoroutineState_Active);
Assert(me->sys == other->sys);
me->state = my_new_state;
other->state = CoroutineState_Active;
me->sys->active = other;
system_signal_cv(&other->cv, &me->sys->lock);
if (do_sleep_loop){
for (;me->state != CoroutineState_Active;){
system_wait_cv(&me->cv, &me->sys->lock);
}
}
}
internal
PLAT_THREAD_SIG(coroutine_main){
Coroutine *me = (Coroutine*)ptr;
// NOTE(allen): Init handshake
Assert(me->state == CoroutineState_Dead);
system_acquire_lock(&me->sys->lock);
me->sys->did_init = true;
system_signal_cv(&me->sys->init_cv, &me->sys->lock);
for (;;){
// NOTE(allen): Wait until someone wakes us up, then go into our procedure.
for (;me->state != CoroutineState_Active;){
system_wait_cv(&me->cv, &me->sys->lock);
}
Assert(me->type != CoroutineType_Root);
Assert(me->yield_ctx != 0);
Assert(me->function != 0);
me->function(&me->head);
// NOTE(allen): Wake up the caller and set this coroutine back to being dead.
Coroutine *other = me->yield_ctx;
Assert(other != 0);
Assert(other->state == CoroutineState_Waiting);
coroutine_internal_pass_control(me, other, CoroutineState_Dead, COROUTINE_INT_SKIP_SLEEP);
me->function = 0;
}
}
internal void
init_coroutine_system(Coroutine *root, Coroutine_System *sys){
system_init_lock(&sys->lock);
system_init_cv(&sys->init_cv);
sys->active = root;
memset(root, 0, sizeof(*root));
root->sys = sys;
root->state = CoroutineState_Active;
root->type = CoroutineType_Root;
system_init_cv(&root->cv);
system_acquire_lock(&sys->lock);
}
internal void
init_coroutine_sub(Coroutine *co, Coroutine_System *sys){
memset(co, 0, sizeof(*co));
co->sys = sys;
co->state = CoroutineState_Dead;
co->type = CoroutineType_Sub;
system_init_cv(&co->cv);
sys->did_init = false;
system_init_and_launch_thread(&co->thread, coroutine_main, co);
for (;!sys->did_init;){
system_wait_cv(&sys->init_cv, &sys->lock);
}
}
// HACK(allen): I want to bundle this with launch!
internal void
coroutine_set_function(Coroutine *me, Coroutine_Function *function){
Assert(me->state == CoroutineState_Dead);
me->function = function;
}
internal void
coroutine_launch(Coroutine *me, Coroutine *other){
Assert(me->sys == other->sys);
Assert(other->state == CoroutineState_Dead);
Assert(other->function != 0);
other->yield_ctx = me;
coroutine_internal_pass_control(me, other, CoroutineState_Waiting);
}
internal void
coroutine_yield(Coroutine *me){
Coroutine *other = me->yield_ctx;
Assert(other != 0);
Assert(me->sys == other->sys);
Assert(other->state == CoroutineState_Waiting);
coroutine_internal_pass_control(me, other, CoroutineState_Inactive);
}
internal void
coroutine_resume(Coroutine *me, Coroutine *other){
Assert(me->sys == other->sys);
Assert(other->state == CoroutineState_Inactive);
other->yield_ctx = me;
coroutine_internal_pass_control(me, other, CoroutineState_Waiting);
}
////////////////////////////////
struct Coroutine_Alloc_Block{
Coroutine coroutine;
Coroutine_Alloc_Block *next;
};
#define COROUTINE_SLOT_SIZE sizeof(Coroutine_Alloc_Block)
struct Coroutine_System_Auto_Alloc{
Coroutine_System sys;
Coroutine root;
Coroutine_Alloc_Block *head_free_uninit;
Coroutine_Alloc_Block *head_free_inited;
};
internal void
init_coroutine_system(Coroutine_System_Auto_Alloc *sys){
init_coroutine_system(&sys->root, &sys->sys);
sys->head_free_uninit = 0;
sys->head_free_inited = 0;
}
internal void
coroutine_system_provide_memory(Coroutine_System_Auto_Alloc *sys, void *memory, umem size){
memset(memory, 0, size);
Coroutine_Alloc_Block *blocks = (Coroutine_Alloc_Block*)memory;
umem count = (size / sizeof(*blocks));
Coroutine_Alloc_Block *old_head = sys->head_free_uninit;
sys->head_free_uninit = &blocks[0];
Coroutine_Alloc_Block *block = blocks;
for (u32 i = 1; i < count; ++i, ++block){
block->next = block + 1;
}
block->next = old_head;
}
internal Coroutine_Alloc_Block*
coroutine_system_pop(Coroutine_Alloc_Block **head){
Coroutine_Alloc_Block *result = *head;
if (result != 0){
*head = result->next;
}
result->next = 0;
return(result);
}
internal void
coroutine_system_push(Coroutine_Alloc_Block **head, Coroutine_Alloc_Block *block){
block->next = *head;
*head = block;
}
internal void
coroutine_system_force_init(Coroutine_System_Auto_Alloc *sys, u32 count){
for (u32 i = 0; i < count; ++i){
Coroutine_Alloc_Block *block = coroutine_system_pop(&sys->head_free_uninit);
if (block == 0){
break;
}
init_coroutine_sub(&block->coroutine, &sys->sys);
coroutine_system_push(&sys->head_free_inited, block);
}
}
internal Coroutine*
coroutine_system_alloc(Coroutine_System_Auto_Alloc *sys){
Coroutine_Alloc_Block *block = coroutine_system_pop(&sys->head_free_inited);
if (block == 0){
coroutine_system_force_init(sys, 1);
block = coroutine_system_pop(&sys->head_free_inited);
}
Coroutine *result = 0;
if (block != 0){
result = &block->coroutine;
}
return(result);
}
internal void
coroutine_system_free(Coroutine_System_Auto_Alloc *sys, Coroutine *co){
Coroutine_Alloc_Block *block = (Coroutine_Alloc_Block*)co;
coroutine_system_push(&sys->head_free_inited, block);
}
// BOTTOM

View File

@ -1,76 +0,0 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 10.09.2017
*
* Mac C++ layer for 4coder
*
*/
// TOP
#if !defined(FRED_COROUTINE_FUNCTIONS_CPP)
#define FRED_COROUTINE_FUNCTIONS_CPP
//
// Coroutine
//
internal
Sys_Create_Coroutine_Sig(system_create_coroutine){
Coroutine *coroutine = coroutine_system_alloc(&coroutines);
Coroutine_Head *result = 0;
if (coroutine != 0){
coroutine_set_function(coroutine, func);
result = &coroutine->head;
}
return(result);
}
internal
Sys_Launch_Coroutine_Sig(system_launch_coroutine){
Coroutine *coroutine = (Coroutine*)head;
coroutine->head.in = in;
coroutine->head.out = out;
Coroutine *active = coroutine->sys->active;
Assert(active != 0);
coroutine_launch(active, coroutine);
Assert(active == coroutine->sys->active);
Coroutine_Head *result = &coroutine->head;
if (coroutine->state == CoroutineState_Dead){
coroutine_system_free(&coroutines, coroutine);
result = 0;
}
return(result);
}
Sys_Resume_Coroutine_Sig(system_resume_coroutine){
Coroutine *coroutine = (Coroutine*)head;
coroutine->head.in = in;
coroutine->head.out = out;
Coroutine *active = coroutine->sys->active;
Assert(active != 0);
coroutine_resume(active, coroutine);
Assert(active == coroutine->sys->active);
Coroutine_Head *result = &coroutine->head;
if (coroutine->state == CoroutineState_Dead){
coroutine_system_free(&coroutines, coroutine);
result = 0;
}
return(result);
}
Sys_Yield_Coroutine_Sig(system_yield_coroutine){
Coroutine *coroutine = (Coroutine*)head;
coroutine_yield(coroutine);
}
#endif
// BOTTOM

View File

@ -14,12 +14,9 @@
#define SYSLINK(name) sysfunc.name = system_##name
internal void
link_system_code(){
link_system_code(void){
SYSLINK(get_canonical);
SYSLINK(get_file_list);
SYSLINK(add_listener);
SYSLINK(remove_listener);
SYSLINK(get_file_change);
SYSLINK(quick_file_attributes);
SYSLINK(load_handle);
SYSLINK(load_attributes);
@ -34,11 +31,6 @@ link_system_code(){
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);
@ -46,12 +38,17 @@ link_system_code(){
SYSLINK(open_color_picker);
SYSLINK(post_job);
SYSLINK(cancel_job);
SYSLINK(check_cancel);
SYSLINK(grow_thread_memory);
SYSLINK(acquire_lock);
SYSLINK(release_lock);
SYSLINK(thread_launch);
SYSLINK(thread_join);
SYSLINK(thread_free);
SYSLINK(mutex_make);
SYSLINK(mutex_acquire);
SYSLINK(mutex_release);
SYSLINK(mutex_free);
SYSLINK(condition_variable_make);
SYSLINK(condition_variable_wait);
SYSLINK(condition_variable_signal);
SYSLINK(condition_variable_free);
SYSLINK(memory_allocate);
SYSLINK(memory_set_protection);

View File

@ -136,15 +136,5 @@ read_command_line(Arena *scratch, i32 argc, char **argv){
end_temp(temp);
}
internal void
coroutines_init(){
init_coroutine_system(&coroutines);
umem size = COROUTINE_SLOT_SIZE*18;
void *mem = system_memory_allocate(size);
coroutine_system_provide_memory(&coroutines, mem, size);
coroutine_system_force_init(&coroutines, 4);
}
// BOTTOM

View File

@ -1,38 +0,0 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 18.07.2017
*
* Cross platform threading constants
*
*/
// TOP
#if !defined(FRED_SHARED_THREADING_CONSTANTS_H)
#define FRED_SHARED_THREADING_CONSTANTS_H
#define CORE_COUNT 8
#define THREAD_TYPE_SIZE 32
#define MUTEX_TYPE_SIZE 64
#define CONDITION_VARIABLE_TYPE_SIZE 48
#define SEMAPHORE_TYPE_SIZE 32
/*
fprintf(stdout, "%d VS %d\n", (i32)sizeof(Thread), THREAD_TYPE_SIZE); \
fprintf(stdout, "%d VS %d\n", (i32)sizeof(Mutex), MUTEX_TYPE_SIZE); \
fprintf(stdout, "%d VS %d\n", (i32)sizeof(Condition_Variable), CONDITION_VARIABLE_TYPE_SIZE); \
fprintf(stdout, "%d VS %d\n", (i32)sizeof(Semaphore), SEMAPHORE_TYPE_SIZE); \
*/
#define AssertThreadSizes() \
Assert( sizeof(Thread) == THREAD_TYPE_SIZE ); \
Assert( sizeof(Mutex) == MUTEX_TYPE_SIZE ); \
Assert(sizeof(Condition_Variable) == CONDITION_VARIABLE_TYPE_SIZE); \
Assert( sizeof(Semaphore) == SEMAPHORE_TYPE_SIZE )
#endif
// BOTTOM

View File

@ -1,398 +0,0 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 18.07.2017
*
* Cross platform logic for work queues.
*
*/
// TOP
enum CV_ID{
CANCEL_CV0,
CANCEL_CV1,
CANCEL_CV2,
CANCEL_CV3,
CANCEL_CV4,
CANCEL_CV5,
CANCEL_CV6,
CANCEL_CV7,
CV_COUNT
};
struct Full_Job_Data{
Job_Data job;
u32 running_thread;
u32 id;
};
struct Unbounded_Work_Queue{
Full_Job_Data *jobs;
i32 count, max, skip;
u32 next_job_id;
};
struct Work_Queue{
Full_Job_Data jobs[QUEUE_WRAP];
Semaphore semaphore;
volatile u32 write_position;
volatile u32 read_position;
};
struct Thread_Context{
u32 job_id;
b32 running;
b32 cancel;
Work_Queue *queue;
u32 id;
u32 group_id;
u32 windows_id;
Thread thread;
};
struct Thread_Group{
Thread_Context *threads;
i32 count;
Unbounded_Work_Queue queue;
i32 cancel_lock0;
i32 cancel_cv0;
};
struct Threading_Vars{
Thread_Memory *thread_memory;
Work_Queue queues[THREAD_GROUP_COUNT];
Thread_Group groups[THREAD_GROUP_COUNT];
Mutex locks[LOCK_COUNT];
Condition_Variable conds[CV_COUNT];
};
global Threading_Vars threadvars;
internal
Sys_Acquire_Lock_Sig(system_acquire_lock){
system_acquire_lock(&threadvars.locks[id]);
}
internal
Sys_Release_Lock_Sig(system_release_lock){
system_release_lock(&threadvars.locks[id]);
}
internal
PLAT_THREAD_SIG(job_thread_proc){
Thread_Context *thread = (Thread_Context*)ptr;
Work_Queue *queue = threadvars.queues + thread->group_id;
Thread_Group *group = threadvars.groups + thread->group_id;
i32 thread_index = thread->id - 1;
Thread_Memory *thread_memory = threadvars.thread_memory + thread_index;
i32 cancel_lock_id = group->cancel_lock0 + thread_index;
i32 cancel_cv_id = group->cancel_cv0 + thread_index;
Mutex *cancel_lock = &threadvars.locks[cancel_lock_id];
Condition_Variable *cancel_cv = &threadvars.conds[cancel_cv_id];
if (thread_memory->size == 0){
i32 new_size = KB(64);
thread_memory->data = system_memory_allocate(new_size);
thread_memory->size = new_size;
}
for (;;){
u32 read_index = queue->read_position;
u32 write_index = queue->write_position;
if (read_index != write_index){
u32 next_read_index = (read_index + 1) % QUEUE_WRAP;
u32 safe_read_index = InterlockedCompareExchange(&queue->read_position, next_read_index, read_index);
if (safe_read_index == read_index){
Full_Job_Data *full_job = queue->jobs + safe_read_index;
// NOTE(allen): This is interlocked so that it plays nice
// with the cancel job routine, which may try to cancel this job
// at the same time that we try to run it
i32 safe_running_thread = InterlockedCompareExchange(&full_job->running_thread, thread->id, THREAD_NOT_ASSIGNED);
if (safe_running_thread == THREAD_NOT_ASSIGNED){
thread->job_id = full_job->id;
thread->running = true;
full_job->job.callback(&sysfunc, thread, thread_memory, full_job->job.data);
system_schedule_step();
thread->running = false;
system_acquire_lock(cancel_lock);
if (thread->cancel){
thread->cancel = 0;
system_signal_cv(cancel_cv, cancel_lock);
}
system_release_lock(cancel_lock);
}
}
}
else{
system_wait_on_semaphore(&queue->semaphore);
}
}
}
internal void
initialize_unbounded_queue(Unbounded_Work_Queue *source_queue){
i32 max = 512;
source_queue->jobs = (Full_Job_Data*)system_memory_allocate(max*sizeof(Full_Job_Data));
source_queue->count = 0;
source_queue->max = max;
source_queue->skip = 0;
}
internal i32
get_work_queue_available_space(i32 write, i32 read){
// NOTE(allen): The only time that queue->write_position == queue->read_position
// is allowed is when the queue is empty. Thus if (write_position+1 == read_position)
// the available space is zero. So these computations both end up leaving one slot unused.
// TODO(allen): The only way I can think to easily eliminate this is to have read and write wrap
// at twice the size of the underlying array but modulo their values into the array then if write
// has caught up with read it still will not be equal... but lots of modulos... ehh.
i32 available_space = 0;
if (write >= read){
available_space = QUEUE_WRAP - (write - read) - 1;
}
else{
available_space = (read - write) - 1;
}
return(available_space);
}
#define UNBOUNDED_SKIP_MAX 128
internal i32
flush_thread_group(Thread_Group_ID group_id){
Thread_Group *group = threadvars.groups + group_id;
Work_Queue *queue = threadvars.queues + group_id;
Unbounded_Work_Queue *source_queue = &group->queue;
i32 thread_count = group->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
// main thread in this system, so it will not be interlocked.
u32 read_position = queue->read_position;
u32 write_position = queue->write_position;
u32 available_space = get_work_queue_available_space(write_position, read_position);
u32 available_jobs = source_queue->count - source_queue->skip;
u32 writable_count = Min(available_space, available_jobs);
if (writable_count > 0){
u32 count1 = writable_count;
if (count1+write_position > QUEUE_WRAP){
count1 = QUEUE_WRAP - write_position;
}
u32 count2 = writable_count - count1;
Full_Job_Data *job_src1 = source_queue->jobs + source_queue->skip;
Full_Job_Data *job_src2 = job_src1 + count1;
Full_Job_Data *job_dst1 = queue->jobs + write_position;
Full_Job_Data *job_dst2 = queue->jobs;
Assert((job_src1->id % QUEUE_WRAP) == write_position);
memcpy(job_dst1, job_src1, sizeof(Full_Job_Data)*count1);
memcpy(job_dst2, job_src2, sizeof(Full_Job_Data)*count2);
queue->write_position = (write_position + writable_count) % QUEUE_WRAP;
source_queue->skip += writable_count;
if (source_queue->skip == source_queue->count){
source_queue->skip = source_queue->count = 0;
}
else if (source_queue->skip > UNBOUNDED_SKIP_MAX){
u32 left_over = source_queue->count - source_queue->skip;
memmove(source_queue->jobs, source_queue->jobs + source_queue->skip,
sizeof(Full_Job_Data)*left_over);
source_queue->count = left_over;
source_queue->skip = 0;
}
}
i32 semaphore_release_count = writable_count;
if (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);
}
// 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 = threadvars.groups + group_id;
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 = {};
full_job.job = job;
full_job.running_thread = THREAD_NOT_ASSIGNED;
full_job.id = result;
queue->jobs[queue->count++] = full_job;
flush_thread_group(group_id);
return(result);
}
internal
Sys_Cancel_Job_Sig(system_cancel_job){
Thread_Group *group = threadvars.groups + group_id;
Work_Queue *queue = threadvars.queues + 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){
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_id = group->cancel_lock0 + thread_index;
i32 cancel_cv_id = group->cancel_cv0 + thread_index;
Mutex *cancel_lock = &threadvars.locks[cancel_lock_id];
Condition_Variable *cancel_cv = &threadvars.conds[cancel_cv_id];
Thread_Context *thread = group->threads + thread_index;
system_acquire_lock(cancel_lock);
thread->cancel = true;
system_release_lock(&threadvars.locks[FRAME_LOCK]);
do{
system_wait_cv(cancel_cv, cancel_lock);
}while (thread->cancel);
system_acquire_lock(&threadvars.locks[FRAME_LOCK]);
system_release_lock(cancel_lock);
}
}
}
internal
Sys_Check_Cancel_Sig(system_check_cancel){
Thread_Group *group = threadvars.groups + thread->group_id;
b32 result = false;
i32 thread_index = thread->id - 1;
i32 cancel_lock_id = group->cancel_lock0 + thread_index;
Mutex *cancel_lock = &threadvars.locks[cancel_lock_id];
system_acquire_lock(cancel_lock);
if (thread->cancel){
result = true;
}
system_release_lock(cancel_lock);
return(result);
}
internal
Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
Mutex *cancel_lock = &threadvars.locks[CANCEL_LOCK0 + memory->id - 1];
system_acquire_lock(cancel_lock);
void *old_data = memory->data;
i32 old_size = memory->size;
i32 new_size = 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_lock);
}
internal void
work_system_init(){
AssertThreadSizes();
u32 core_count = CORE_COUNT;
Arena thread_arena = make_arena_system(&sysfunc);
for (i32 i = 0; i < LOCK_COUNT; ++i){
system_init_lock(&threadvars.locks[i]);
}
for (i32 i = 0; i < CV_COUNT; ++i){
system_init_cv(&threadvars.conds[i]);
}
threadvars.thread_memory = push_array(&thread_arena, Thread_Memory, core_count);
for (u32 group_i = 0; group_i < THREAD_GROUP_COUNT; ++group_i){
Thread_Context *threads = push_array(&thread_arena, Thread_Context, core_count);
threadvars.groups[group_i].threads = threads;
threadvars.groups[group_i].count = core_count;
threadvars.groups[group_i].cancel_lock0 = CANCEL_LOCK0;
threadvars.groups[group_i].cancel_cv0 = CANCEL_CV0;
system_init_semaphore(&threadvars.queues[group_i].semaphore, core_count);
for (u32 i = 0; i < core_count; ++i){
Thread_Context *thread = threads + i;
thread->id = i + 1;
thread->group_id = group_i;
Thread_Memory *memory = &threadvars.thread_memory[i];
memset(memory, 0, sizeof(*memory));
memory->id = thread->id;
thread->queue = &threadvars.queues[group_i];
system_init_and_launch_thread(&thread->thread, job_thread_proc, thread);
}
initialize_unbounded_queue(&threadvars.groups[group_i].queue);
}
}
// BOTTOM

File diff suppressed because it is too large Load Diff

View File

@ -1,92 +0,0 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 18.07.2017
*
* Win32 threading wrapper
*
*/
// TOP
#if !defined(WIN32_THREADING_WRAPPER)
#define WIN32_THREADING_WRAPPER
#define PLAT_THREAD_SIG(n) DWORD CALL_CONVENTION n(LPVOID ptr)
typedef PLAT_THREAD_SIG(Thread_Function);
union Thread{
HANDLE t;
FixSize(THREAD_TYPE_SIZE);
};
union Mutex{
CRITICAL_SECTION crit;
FixSize(MUTEX_TYPE_SIZE);
};
union Condition_Variable{
CONDITION_VARIABLE cv;
FixSize(CONDITION_VARIABLE_TYPE_SIZE);
};
union Semaphore{
HANDLE s;
FixSize(SEMAPHORE_TYPE_SIZE);
};
internal void
system_init_and_launch_thread(Thread *t, Thread_Function *proc, void *ptr){
t->t = CreateThread(0, 0, proc, ptr, 0, 0);
}
internal void
system_init_lock(Mutex *m){
InitializeCriticalSection(&m->crit);
}
internal void
system_acquire_lock(Mutex *m){
EnterCriticalSection(&m->crit);
}
internal void
system_release_lock(Mutex *m){
LeaveCriticalSection(&m->crit);
}
internal void
system_init_cv(Condition_Variable *cv){
InitializeConditionVariable(&cv->cv);
}
internal void
system_wait_cv(Condition_Variable *cv, Mutex *lock){
SleepConditionVariableCS(&cv->cv, &lock->crit, INFINITE);
}
internal void
system_signal_cv(Condition_Variable *cv, Mutex *lock){
WakeConditionVariable(&cv->cv);
}
internal void
system_init_semaphore(Semaphore *s, u32 max){
s->s = CreateSemaphore(0, 0, max, 0);
}
internal void
system_wait_on_semaphore(Semaphore *s){
WaitForSingleObject(s->s, INFINITE);
}
internal void
system_release_semaphore(Semaphore *s){
ReleaseSemaphore(s->s, 1, 0);
}
#endif
// BOTTOM