From d0b97a3010319e791048bda557d334157cef38a8 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 29 Oct 2024 16:27:21 -0700 Subject: [PATCH] first pass at more comprehensive async layer, for replacing task system & providing single mechanism for async work, which is currently done ad-hoc in various layers --- src/async/async.c | 146 ++++++++++++++++++ src/async/async.h | 116 ++++++++++++++ src/os/core/win32/os_core_win32.c | 9 +- src/raddbg/raddbg_main.c | 3 + .../rdi_breakpad_from_pdb_main.c | 6 +- src/rdi_from_pdb/rdi_from_pdb.c | 84 +++++----- src/rdi_from_pdb/rdi_from_pdb_main.c | 2 + src/task_system/task_system.c | 34 ++-- src/task_system/task_system.h | 30 +++- 9 files changed, 366 insertions(+), 64 deletions(-) create mode 100644 src/async/async.c create mode 100644 src/async/async.h diff --git a/src/async/async.c b/src/async/async.c new file mode 100644 index 00000000..c3a6b145 --- /dev/null +++ b/src/async/async.c @@ -0,0 +1,146 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Top-Level Layer Initialization + +internal void +async_init(void) +{ + Arena *arena = arena_alloc(); + async_shared = push_array(arena, ASYNC_Shared, 1); + async_shared->arena = arena; + async_shared->u2w_ring_size = MB(8); + async_shared->u2w_ring_base = push_array_no_zero(arena, U8, async_shared->u2w_ring_size); + async_shared->u2w_ring_mutex = os_mutex_alloc(); + async_shared->u2w_ring_cv = os_condition_variable_alloc(); + async_shared->work_threads_count = Max(1, os_get_system_info()->logical_processor_count-1); + async_shared->work_threads = push_array(arena, OS_Handle, async_shared->work_threads_count); + for EachIndex(idx, async_shared->work_threads_count) + { + async_shared->work_threads[idx] = os_thread_launch(async_work_thread__entry_point, (void *)idx, 0); + } +} + +//////////////////////////////// +//~ rjf: Top-Level Accessors + +internal U64 +async_thread_count(void) +{ + return async_shared->work_threads_count; +} + +//////////////////////////////// +//~ rjf: Work Kickoffs + +internal B32 +async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params) +{ + B32 result = 0; + ASYNC_Work work = {0}; + work.work_function = work_function; + work.input = params->input; + work.output = params->output; + work.semaphore = params->semaphore; + OS_MutexScope(async_shared->u2w_ring_mutex) for(;;) + { + U64 unconsumed_size = async_shared->u2w_ring_write_pos - async_shared->u2w_ring_read_pos; + U64 available_size = async_shared->u2w_ring_size - unconsumed_size; + if(available_size >= sizeof(work)) + { + result = 1; + if(!os_handle_match(params->semaphore, os_handle_zero())) + { + os_semaphore_take(params->semaphore, max_U64); + } + async_shared->u2w_ring_write_pos += ring_write_struct(async_shared->u2w_ring_base, async_shared->u2w_ring_size, async_shared->u2w_ring_write_pos, &work); + break; + } + if(os_now_microseconds() >= params->endt_us) + { + break; + } + os_condition_variable_wait(async_shared->u2w_ring_cv, async_shared->u2w_ring_mutex, params->endt_us); + } + return result; +} + +//////////////////////////////// +//~ rjf: Task-Based Work Helper + +internal void +async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task t) +{ + ASYNC_TaskNode *n = push_array(arena, ASYNC_TaskNode, 1); + SLLQueuePush(list->first, list->last, n); + n->v = t; + list->count += 1; +} + +internal ASYNC_Task +async_task_launch_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params) +{ + ASYNC_Task task = {0}; + task.semaphore = os_semaphore_alloc(1, 1, str8_zero()); + ASYNC_WorkParams params_refined = {0}; + MemoryCopyStruct(¶ms_refined, params); + params_refined.endt_us = max_U64; + params_refined.semaphore = task.semaphore; + if(params_refined.output == 0) + { + params_refined.output = &task.output; + } + async_push_work_(work_function, ¶ms_refined); + return task; +} + +internal void * +async_task_join(ASYNC_Task task) +{ + os_semaphore_take(task.semaphore, max_U64); + os_semaphore_release(task.semaphore); + MemoryZeroStruct(&task.semaphore); + void *result = (void *)ins_atomic_u64_eval(&task.output); + return result; +} + +//////////////////////////////// +//~ rjf: Work Thread Entry Point + +internal void +async_work_thread__entry_point(void *p) +{ + U64 thread_idx = (U64)p; + ThreadNameF("[async] work thread #%I64u", thread_idx); + for(;;) + { + //- rjf: grab next work + ASYNC_Work work = {0}; + OS_MutexScope(async_shared->u2w_ring_mutex) for(;;) + { + U64 unconsumed_size = async_shared->u2w_ring_write_pos - async_shared->u2w_ring_read_pos; + if(unconsumed_size >= sizeof(work)) + { + async_shared->u2w_ring_read_pos += ring_read_struct(async_shared->u2w_ring_base, async_shared->u2w_ring_size, async_shared->u2w_ring_read_pos, &work); + break; + } + os_condition_variable_wait(async_shared->u2w_ring_cv, async_shared->u2w_ring_mutex, max_U64); + } + + //- rjf: run work + void *work_out = work.work_function(thread_idx, work.input); + + //- rjf: store output + if(work.output != 0) + { + ins_atomic_u64_eval_assign((U64 *)work.output, (U64)work_out); + } + + //- rjf: release semaphore + if(!os_handle_match(work.semaphore, os_handle_zero())) + { + os_semaphore_drop(work.semaphore); + } + } +} diff --git a/src/async/async.h b/src/async/async.h new file mode 100644 index 00000000..44b171ef --- /dev/null +++ b/src/async/async.h @@ -0,0 +1,116 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef ASYNC_H +#define ASYNC_H + +//////////////////////////////// +//~ rjf: Work Function Type + +#define ASYNC_WORK_SIG(name) void *name(U64 thread_idx, void *input) +#define ASYNC_WORK_DEF(name) internal ASYNC_WORK_SIG(name) +typedef ASYNC_WORK_SIG(ASYNC_WorkFunctionType); + +//////////////////////////////// +//~ rjf: Work Types + +typedef struct ASYNC_WorkParams ASYNC_WorkParams; +struct ASYNC_WorkParams +{ + void *input; + void **output; + OS_Handle semaphore; + U64 endt_us; +}; + +typedef struct ASYNC_Work ASYNC_Work; +struct ASYNC_Work +{ + ASYNC_WorkFunctionType *work_function; + void *input; + void **output; + OS_Handle semaphore; +}; + +//////////////////////////////// +//~ rjf: Task-Based Work Types + +typedef struct ASYNC_Task ASYNC_Task; +struct ASYNC_Task +{ + OS_Handle semaphore; + void *output; +}; + +typedef struct ASYNC_TaskNode ASYNC_TaskNode; +struct ASYNC_TaskNode +{ + ASYNC_TaskNode *next; + ASYNC_Task v; +}; + +typedef struct ASYNC_TaskList ASYNC_TaskList; +struct ASYNC_TaskList +{ + ASYNC_TaskNode *first; + ASYNC_TaskNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Shared State Bundle + +typedef struct ASYNC_Shared ASYNC_Shared; +struct ASYNC_Shared +{ + Arena *arena; + + // rjf: user -> work thread ring buffer + U64 u2w_ring_size; + U8 *u2w_ring_base; + U64 u2w_ring_write_pos; + U64 u2w_ring_read_pos; + OS_Handle u2w_ring_mutex; + OS_Handle u2w_ring_cv; + + // rjf: work threads + OS_Handle *work_threads; + U64 work_threads_count; +}; + +//////////////////////////////// +//~ rjf: Globals + +global ASYNC_Shared *async_shared = 0; + +//////////////////////////////// +//~ rjf: Top-Level Layer Initialization + +internal void async_init(void); + +//////////////////////////////// +//~ rjf: Top-Level Accessors + +internal U64 async_thread_count(void); + +//////////////////////////////// +//~ rjf: Work Kickoffs + +internal B32 async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params); +#define async_push_work(function, ...) async_push_work_((function), &(ASYNC_WorkParams){.endt_us = max_U64, __VA_ARGS__}) + +//////////////////////////////// +//~ rjf: Task-Based Work Helper + +internal void async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task t); +internal ASYNC_Task async_task_launch_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params); +#define async_task_kickoff(work_function, ...) async_task_kickoff_((work_function), &(ASYNC_WorkParams){.endt_us = max_U64, __VA_ARGS__}) +internal void *async_task_join(ASYNC_Task task); +#define async_task_join_struct(task, T) (T *)async_task_join(task) + +//////////////////////////////// +//~ rjf: Work Thread Entry Point + +internal void async_work_thread__entry_point(void *p); + +#endif // ASYNC_H diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index eb49b4e0..7a850674 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -710,8 +710,13 @@ os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out) internal void os_file_iter_end(OS_FileIter *iter) { - OS_W32_FileIter *w32_iter = (OS_W32_FileIter*)iter->memory; - FindClose(w32_iter->handle); + OS_W32_FileIter *w32_iter = (OS_W32_FileIter*)iter->memory; + HANDLE zero_handle; + MemoryZeroStruct(&zero_handle); + if(!MemoryMatchStruct(&zero_handle, &w32_iter->handle)) + { + FindClose(w32_iter->handle); + } } //- rjf: directory creation diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 9ea18671..606511b5 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -123,6 +123,7 @@ // ability to put "$err, hr" into the watch window, which will just show // the value of GetLastError() as a string. This is super useful for // debugging, so you don't have to litter your own code with it. +// (NOTE(rjf): NtQueryInformationThread) // // [ ] Tooltip Coverage: // [ ] lock icon @@ -571,6 +572,7 @@ //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" +#include "async/async.h" #include "task_system/task_system.h" #include "rdi_format/rdi_format_local.h" #include "rdi_make/rdi_make_local.h" @@ -613,6 +615,7 @@ //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" +#include "async/async.c" #include "task_system/task_system.c" #include "rdi_format/rdi_format_local.c" #include "rdi_make/rdi_make_local.c" diff --git a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c index aaf06bc8..fcfa2893 100644 --- a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c +++ b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c @@ -225,11 +225,11 @@ entry_point(CmdLine *cmdline) //- rjf: kick off unit vmap baking P2B_BakeUnitVMapIn bake_unit_vmap_in = {¶ms->units}; - TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2b_bake_unit_vmap_task__entry_point, 0, &bake_unit_vmap_in); + TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2b_bake_unit_vmap_task__entry_point, &bake_unit_vmap_in); //- rjf: kick off line-table baking P2B_BakeLineTablesIn bake_line_tables_in = {¶ms->line_tables}; - TS_Ticket bake_line_tables_ticket = ts_kickoff(p2b_bake_line_table_task__entry_point, 0, &bake_line_tables_in); + TS_Ticket bake_line_tables_ticket = ts_kickoff(p2b_bake_line_table_task__entry_point, &bake_line_tables_in); //- rjf: build unit -> line table idx array U64 unit_count = params->units.total_count; @@ -288,7 +288,7 @@ entry_point(CmdLine *cmdline) dump_proc_chunk_in[task_idx].unit_count = unit_count; dump_proc_chunk_in[task_idx].line_tables_bake = bake_line_tables_out; dump_proc_chunk_in[task_idx].chunk = n; - dump_proc_chunk_tickets[task_idx] = ts_kickoff(p2b_dump_proc_chunk_task__entry_point, 0, &dump_proc_chunk_in[task_idx]); + dump_proc_chunk_tickets[task_idx] = ts_kickoff(p2b_dump_proc_chunk_task__entry_point, &dump_proc_chunk_in[task_idx]); } } diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index fbee7f08..06810d7a 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -3184,7 +3184,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: kickoff EXE hash // P2R_EXEHashIn exe_hash_in = {in->input_exe_data}; - TS_Ticket exe_hash_ticket = ts_kickoff(p2r_exe_hash_task__entry_point, 0, &exe_hash_in); + TS_Ticket exe_hash_ticket = ts_kickoff(p2r_exe_hash_task__entry_point, &exe_hash_in); ////////////////////////////////////////////////////////////// //- rjf: kickoff TPI hash parse @@ -3197,7 +3197,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) tpi_hash_in.tpi = tpi; tpi_hash_in.hash_data = msf_data_from_stream(msf, tpi->hash_sn); tpi_hash_in.aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); - tpi_hash_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, 0, &tpi_hash_in); + tpi_hash_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, &tpi_hash_in); } ////////////////////////////////////////////////////////////// @@ -3209,7 +3209,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) { tpi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(tpi); tpi_leaf_in.itype_first = tpi->itype_first; - tpi_leaf_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, 0, &tpi_leaf_in); + tpi_leaf_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, &tpi_leaf_in); } ////////////////////////////////////////////////////////////// @@ -3223,7 +3223,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) ipi_hash_in.tpi = ipi; ipi_hash_in.hash_data = msf_data_from_stream(msf, ipi->hash_sn); ipi_hash_in.aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); - ipi_hash_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, 0, &ipi_hash_in); + ipi_hash_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, &ipi_hash_in); } ////////////////////////////////////////////////////////////// @@ -3235,22 +3235,22 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) { ipi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(ipi); ipi_leaf_in.itype_first = ipi->itype_first; - ipi_leaf_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, 0, &ipi_leaf_in); + ipi_leaf_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, &ipi_leaf_in); } ////////////////////////////////////////////////////////////// //- rjf: kickoff top-level global symbol stream parse // P2R_SymbolStreamParseIn sym_parse_in = {dbi ? msf_data_from_stream(msf, dbi->sym_sn) : str8_zero()}; - TS_Ticket sym_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_symbol_stream_parse_task__entry_point, 0, &sym_parse_in); + TS_Ticket sym_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_symbol_stream_parse_task__entry_point, &sym_parse_in); ////////////////////////////////////////////////////////////// //- rjf: kickoff compilation unit parses // P2R_CompUnitParseIn comp_unit_parse_in = {dbi ? pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo) : str8_zero()}; P2R_CompUnitContributionsParseIn comp_unit_contributions_parse_in = {dbi ? pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon) : str8_zero(), coff_sections}; - TS_Ticket comp_unit_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_comp_unit_parse_task__entry_point, 0, &comp_unit_parse_in); - TS_Ticket comp_unit_contributions_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_comp_unit_contributions_parse_task__entry_point, 0, &comp_unit_contributions_parse_in); + TS_Ticket comp_unit_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_comp_unit_parse_task__entry_point, &comp_unit_parse_in); + TS_Ticket comp_unit_contributions_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_comp_unit_contributions_parse_task__entry_point, &comp_unit_contributions_parse_in); ////////////////////////////////////////////////////////////// //- rjf: join compilation unit parses @@ -3282,11 +3282,11 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) { PDB_CompUnit *unit = comp_units->units[idx]; sym_tasks_inputs[idx].data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); - sym_tasks_tickets[idx] = ts_kickoff(p2r_symbol_stream_parse_task__entry_point, 0, &sym_tasks_inputs[idx]); + sym_tasks_tickets[idx] = ts_kickoff(p2r_symbol_stream_parse_task__entry_point, &sym_tasks_inputs[idx]); c13_tasks_inputs[idx].data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); c13_tasks_inputs[idx].strtbl = raw_strtbl; c13_tasks_inputs[idx].coff_sections = coff_sections; - c13_tasks_tickets[idx] = ts_kickoff(p2r_c13_stream_parse_task__entry_point, 0, &c13_tasks_inputs[idx]); + c13_tasks_tickets[idx] = ts_kickoff(p2r_c13_stream_parse_task__entry_point, &c13_tasks_inputs[idx]); } //- rjf: join tasks @@ -3389,7 +3389,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: kick off unit conversion & source file collection // P2R_UnitConvertIn unit_convert_in = {strtbl, coff_sections, comp_units, comp_unit_contributions, sym_for_unit, c13_for_unit}; - TS_Ticket unit_convert_ticket = ts_kickoff(p2r_units_convert_task__entry_point, 0, &unit_convert_in); + TS_Ticket unit_convert_ticket = ts_kickoff(p2r_units_convert_task__entry_point, &unit_convert_in); ////////////////////////////////////////////////////////////// //- rjf: join global sym stream parse @@ -3432,7 +3432,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) link_name_map_build_in.sym = sym; link_name_map_build_in.coff_sections = coff_sections; link_name_map_build_in.link_name_map = &link_name_map__in_progress; - link_name_map_ticket = ts_kickoff(p2r_link_name_map_build_task__entry_point, 0, &link_name_map_build_in); + link_name_map_ticket = ts_kickoff(p2r_link_name_map_build_task__entry_point, &link_name_map_build_in); } ////////////////////////////////////////////////////////////// @@ -3481,7 +3481,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) tasks_inputs[idx].itype_opl = tasks_inputs[idx].itype_first + task_size_itypes; tasks_inputs[idx].itype_opl = ClampTop(tasks_inputs[idx].itype_opl, itype_opl); tasks_inputs[idx].itype_fwd_map = itype_fwd_map; - tasks_tickets[idx] = ts_kickoff(p2r_itype_fwd_map_fill_task__entry_point, 0, &tasks_inputs[idx]); + tasks_tickets[idx] = ts_kickoff(p2r_itype_fwd_map_fill_task__entry_point, &tasks_inputs[idx]); } //- rjf: join all tasks @@ -3520,7 +3520,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) tasks_inputs[idx].itype_opl = ClampTop(tasks_inputs[idx].itype_opl, itype_opl); tasks_inputs[idx].itype_chains = itype_chains; tasks_inputs[idx].itype_fwd_map = itype_fwd_map; - tasks_tickets[idx] = ts_kickoff(p2r_itype_chain_build_task__entry_point, 0, &tasks_inputs[idx]); + tasks_tickets[idx] = ts_kickoff(p2r_itype_chain_build_task__entry_point, &tasks_inputs[idx]); } //- rjf: join all tasks @@ -3990,7 +3990,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) udt_tasks_inputs[idx].itype_opl = ClampTop(udt_tasks_inputs[idx].itype_opl, itype_opl); udt_tasks_inputs[idx].itype_fwd_map = itype_fwd_map; udt_tasks_inputs[idx].itype_type_ptrs = itype_type_ptrs; - udt_tasks_tickets[idx] = ts_kickoff(p2r_udt_convert_task__entry_point, 0, &udt_tasks_inputs[idx]); + udt_tasks_tickets[idx] = ts_kickoff(p2r_udt_convert_task__entry_point, &udt_tasks_inputs[idx]); } } @@ -4064,7 +4064,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) tasks_inputs[idx].sym_ranges_opl = sym_for_unit[idx-global_stream_subdivision_tasks_count]->sym_ranges.count; tasks_inputs[idx].first_inline_site_line_table = units_first_inline_site_line_tables[idx-global_stream_subdivision_tasks_count]; } - tasks_tickets[idx] = ts_kickoff(p2r_symbol_stream_convert_task__entry_point, 0, &tasks_inputs[idx]); + tasks_tickets[idx] = ts_kickoff(p2r_symbol_stream_convert_task__entry_point, &tasks_inputs[idx]); } } @@ -4422,7 +4422,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) { P2R_BakeLineTablesIn *in = push_array(scratch.arena, P2R_BakeLineTablesIn, 1); in->line_tables = &in_params->line_tables; - bake_line_tables_ticket = ts_kickoff(p2r_bake_line_tables_task__entry_point, 0, in); + bake_line_tables_ticket = ts_kickoff(p2r_bake_line_tables_task__entry_point, in); } ////////////////////////////// @@ -4452,7 +4452,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) in->top = &bake_string_map_topology; in->maps = bake_string_maps__in_progress; in->list = &in_params->src_files; - ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_src_files_strings_task__entry_point, 0, in)); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_src_files_strings_task__entry_point, in)); } // rjf: units @@ -4462,7 +4462,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) in->top = &bake_string_map_topology; in->maps = bake_string_maps__in_progress; in->list = &in_params->units; - ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_units_strings_task__entry_point, 0, in)); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_units_strings_task__entry_point, in)); } // rjf: types @@ -4493,7 +4493,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) chunk_off = 0; } } - ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_types_strings_task__entry_point, 0, in)); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_types_strings_task__entry_point, in)); } } @@ -4525,7 +4525,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) chunk_off = 0; } } - ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_udts_strings_task__entry_point, 0, in)); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_udts_strings_task__entry_point, in)); } } @@ -4565,7 +4565,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) chunk_off = 0; } } - ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_symbols_strings_task__entry_point, 0, in)); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_symbols_strings_task__entry_point, in)); } } } @@ -4598,7 +4598,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) chunk_off = 0; } } - ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_scopes_strings_task__entry_point, 0, in)); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_scopes_strings_task__entry_point, in)); } } } @@ -4614,7 +4614,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) { build_bake_name_map_in[k].k = k; build_bake_name_map_in[k].params = in_params; - build_bake_name_map_ticket[k] = ts_kickoff(p2r_build_bake_name_map_task__entry_point, 0, &build_bake_name_map_in[k]); + build_bake_name_map_ticket[k] = ts_kickoff(p2r_build_bake_name_map_task__entry_point, &build_bake_name_map_in[k]); } ////////////////////////////// @@ -4680,7 +4680,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) in->dst_map = unsorted_bake_string_map; in->slot_idx_range = r1u64(task_idx*slots_per_task, task_idx*slots_per_task + slots_per_task); in->slot_idx_range.max = Min(in->slot_idx_range.max, in->top->slots_count); - task_tickets[task_idx] = ts_kickoff(p2r_bake_string_map_join_task__entry_point, 0, in); + task_tickets[task_idx] = ts_kickoff(p2r_bake_string_map_join_task__entry_point, in); } // rjf: join tasks @@ -4746,7 +4746,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) in->slot_count = bake_string_map_topology.slots_count - in->slot_idx; } } - ts_ticket_list_push(scratch.arena, &sort_bake_string_map_task_tickets, ts_kickoff(p2r_bake_string_map_sort_task__entry_point, 0, in)); + ts_ticket_list_push(scratch.arena, &sort_bake_string_map_task_tickets, ts_kickoff(p2r_bake_string_map_sort_task__entry_point, in)); } } @@ -4824,31 +4824,31 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) //- rjf: kick off pass 2 tasks // P2R_BakeUnitsIn bake_units_top_level_in = {&bake_strings, path_tree, &in_params->units}; - TS_Ticket bake_units_ticket = ts_kickoff(p2r_bake_units_task__entry_point, 0, &bake_units_top_level_in); + TS_Ticket bake_units_ticket = ts_kickoff(p2r_bake_units_task__entry_point, &bake_units_top_level_in); P2R_BakeUnitVMapIn bake_unit_vmap_in = {&in_params->units}; - TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2r_bake_unit_vmap_task__entry_point, 0, &bake_unit_vmap_in); + TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2r_bake_unit_vmap_task__entry_point, &bake_unit_vmap_in); P2R_BakeSrcFilesIn bake_src_files_in = {&bake_strings, path_tree, &in_params->src_files}; - TS_Ticket bake_src_files_ticket = ts_kickoff(p2r_bake_src_files_task__entry_point, 0, &bake_src_files_in); + TS_Ticket bake_src_files_ticket = ts_kickoff(p2r_bake_src_files_task__entry_point, &bake_src_files_in); P2R_BakeUDTsIn bake_udts_in = {&bake_strings, &in_params->udts}; - TS_Ticket bake_udts_ticket = ts_kickoff(p2r_bake_udts_task__entry_point, 0, &bake_udts_in); + TS_Ticket bake_udts_ticket = ts_kickoff(p2r_bake_udts_task__entry_point, &bake_udts_in); P2R_BakeGlobalVariablesIn bake_global_variables_in = {&bake_strings, &in_params->global_variables}; - TS_Ticket bake_global_variables_ticket = ts_kickoff(p2r_bake_global_variables_task__entry_point, 0, &bake_global_variables_in); + TS_Ticket bake_global_variables_ticket = ts_kickoff(p2r_bake_global_variables_task__entry_point, &bake_global_variables_in); P2R_BakeGlobalVMapIn bake_global_vmap_in = {&in_params->global_variables}; - TS_Ticket bake_global_vmap_ticket = ts_kickoff(p2r_bake_global_vmap_task__entry_point, 0, &bake_global_vmap_in); + TS_Ticket bake_global_vmap_ticket = ts_kickoff(p2r_bake_global_vmap_task__entry_point, &bake_global_vmap_in); P2R_BakeThreadVariablesIn bake_thread_variables_in = {&bake_strings, &in_params->thread_variables}; - TS_Ticket bake_thread_variables_ticket = ts_kickoff(p2r_bake_thread_variables_task__entry_point, 0, &bake_thread_variables_in); + TS_Ticket bake_thread_variables_ticket = ts_kickoff(p2r_bake_thread_variables_task__entry_point, &bake_thread_variables_in); P2R_BakeProceduresIn bake_procedures_in = {&bake_strings, &in_params->procedures}; - TS_Ticket bake_procedures_ticket = ts_kickoff(p2r_bake_procedures_task__entry_point, 0, &bake_procedures_in); + TS_Ticket bake_procedures_ticket = ts_kickoff(p2r_bake_procedures_task__entry_point, &bake_procedures_in); P2R_BakeScopesIn bake_scopes_in = {&bake_strings, &in_params->scopes}; - TS_Ticket bake_scopes_ticket = ts_kickoff(p2r_bake_scopes_task__entry_point, 0, &bake_scopes_in); + TS_Ticket bake_scopes_ticket = ts_kickoff(p2r_bake_scopes_task__entry_point, &bake_scopes_in); P2R_BakeScopeVMapIn bake_scope_vmap_in = {&in_params->scopes}; - TS_Ticket bake_scope_vmap_ticket = ts_kickoff(p2r_bake_scope_vmap_task__entry_point, 0, &bake_scope_vmap_in); + TS_Ticket bake_scope_vmap_ticket = ts_kickoff(p2r_bake_scope_vmap_task__entry_point, &bake_scope_vmap_in); P2R_BakeInlineSitesIn bake_inline_sites_in = {&bake_strings, &in_params->inline_sites}; - TS_Ticket bake_inline_sites_ticket = ts_kickoff(p2r_bake_inline_sites_task__entry_point, 0, &bake_inline_sites_in); + TS_Ticket bake_inline_sites_ticket = ts_kickoff(p2r_bake_inline_sites_task__entry_point, &bake_inline_sites_in); P2R_BakeFilePathsIn bake_file_paths_in = {&bake_strings, path_tree}; - TS_Ticket bake_file_paths_ticket = ts_kickoff(p2r_bake_file_paths_task__entry_point, 0, &bake_file_paths_in); + TS_Ticket bake_file_paths_ticket = ts_kickoff(p2r_bake_file_paths_task__entry_point, &bake_file_paths_in); P2R_BakeStringsIn bake_strings_in = {&bake_strings}; - TS_Ticket bake_strings_ticket = ts_kickoff(p2r_bake_strings_task__entry_point, 0, &bake_strings_in); + TS_Ticket bake_strings_ticket = ts_kickoff(p2r_bake_strings_task__entry_point, &bake_strings_in); ////////////////////////////// //- rjf: join name map building tasks @@ -4884,7 +4884,7 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) //- rjf: kick off pass 3 tasks // P2R_BakeTypeNodesIn bake_type_nodes_in = {&bake_strings, idx_runs, &in_params->types}; - TS_Ticket bake_type_nodes_ticket = ts_kickoff(p2r_bake_type_nodes_task__entry_point, 0, &bake_type_nodes_in); + TS_Ticket bake_type_nodes_ticket = ts_kickoff(p2r_bake_type_nodes_task__entry_point, &bake_type_nodes_in); TS_Ticket bake_name_maps_tickets[RDI_NameMapKind_COUNT] = {0}; { for EachNonZeroEnumVal(RDI_NameMapKind, k) @@ -4898,11 +4898,11 @@ p2r_bake(Arena *arena, P2R_Convert2Bake *in) in->idx_runs = idx_runs; in->map = name_maps[k]; in->kind = k; - bake_name_maps_tickets[k] = ts_kickoff(p2r_bake_name_map_task__entry_point, 0, in); + bake_name_maps_tickets[k] = ts_kickoff(p2r_bake_name_map_task__entry_point, in); } } P2R_BakeIdxRunsIn bake_idx_runs_in = {idx_runs}; - TS_Ticket bake_idx_runs_ticket = ts_kickoff(p2r_bake_idx_runs_task__entry_point, 0, &bake_idx_runs_in); + TS_Ticket bake_idx_runs_ticket = ts_kickoff(p2r_bake_idx_runs_task__entry_point, &bake_idx_runs_in); ////////////////////////////// //- rjf: join remaining completed bakes diff --git a/src/rdi_from_pdb/rdi_from_pdb_main.c b/src/rdi_from_pdb/rdi_from_pdb_main.c index baeabf08..742b964f 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_main.c +++ b/src/rdi_from_pdb/rdi_from_pdb_main.c @@ -24,6 +24,7 @@ #include "base/base_inc.h" #include "os/os_inc.h" #include "task_system/task_system.h" +#include "task_system/task_system2.h" #include "rdi_make/rdi_make_local.h" #include "coff/coff.h" #include "codeview/codeview.h" @@ -39,6 +40,7 @@ #include "base/base_inc.c" #include "os/os_inc.c" #include "task_system/task_system.c" +#include "task_system/task_system2.c" #include "rdi_make/rdi_make_local.c" #include "coff/coff.c" #include "codeview/codeview.c" diff --git a/src/task_system/task_system.c b/src/task_system/task_system.c index bbc0d5af..26b2ee05 100644 --- a/src/task_system/task_system.c +++ b/src/task_system/task_system.c @@ -11,6 +11,13 @@ ts_ticket_zero(void) return ticket; } +internal B32 +ts_ticket_match(TS_Ticket a, TS_Ticket b) +{ + B32 result = MemoryMatchStruct(&a, &b); + return result; +} + internal void ts_ticket_list_push(Arena *arena, TS_TicketList *list, TS_Ticket ticket) { @@ -65,7 +72,7 @@ ts_thread_count(void) //~ rjf: High-Level Task Kickoff / Joining internal TS_Ticket -ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p) +ts_kickoff_(TS_TaskFunctionType *entry_point, TS_KickoffParams *params) { ProfBeginFunction(); @@ -93,7 +100,7 @@ ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p } artifact->num = artifact_num; artifact->task_is_done = 0; - artifact->result = 0; + artifact->out = 0; } } @@ -107,20 +114,20 @@ ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p { U64 unconsumed_size = ts_shared->u2t_ring_write_pos - ts_shared->u2t_ring_read_pos; U64 available_size = ts_shared->u2t_ring_size-unconsumed_size; - if(available_size >= sizeof(entry_point) + sizeof(p) + sizeof(ticket)) + if(available_size >= sizeof(entry_point) + sizeof(Arena *) + sizeof(params->in) + sizeof(ticket)) { Arena *task_arena = 0; - if(optional_arena_ptr != 0) + if(params->optional_arena_ptr != 0) { - task_arena = *optional_arena_ptr; + task_arena = *params->optional_arena_ptr; } ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &entry_point); ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &task_arena); - ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &p); + ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, ¶ms->in); ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &ticket); - if(optional_arena_ptr != 0) + if(params->optional_arena_ptr != 0) { - *optional_arena_ptr = 0; + *params->optional_arena_ptr = 0; } break; } @@ -133,10 +140,10 @@ ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p return ticket; } -internal void * +internal TS_JoinResult ts_join(TS_Ticket ticket, U64 endt_us) { - void *result = 0; + TS_JoinResult result = {0}; U64 artifact_num = ticket.u64[0]; U64 slot_idx = artifact_num%ts_shared->artifact_slots_count; U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count; @@ -152,7 +159,8 @@ ts_join(TS_Ticket ticket, U64 endt_us) { OS_MutexScopeRWPromote(stripe->rw_mutex) { - result = artifact->result; + result.good = 1; + result.out = artifact->out; SLLStackPush(stripe->free_artifact, artifact); } break; @@ -211,7 +219,7 @@ ts_task_thread__entry_point(void *p) } //- rjf: run task - void *task_result = task_function(task_arena, thread_idx, task_params); + void *task_out = task_function(task_arena, thread_idx, task_params); //- rjf: store into artifact U64 artifact_num = task_ticket.u64[0]; @@ -223,7 +231,7 @@ ts_task_thread__entry_point(void *p) OS_MutexScopeW(stripe->rw_mutex) { artifact->task_is_done = 1; - artifact->result = task_result; + artifact->out = task_out; } os_condition_variable_broadcast(stripe->cv); } diff --git a/src/task_system/task_system.h b/src/task_system/task_system.h index 96483595..7b17429e 100644 --- a/src/task_system/task_system.h +++ b/src/task_system/task_system.h @@ -37,6 +37,26 @@ struct TS_TicketList #define TS_TASK_FUNCTION_DEF(name) void *name(Arena *arena, U64 thread_idx, void *p) typedef TS_TASK_FUNCTION_DEF(TS_TaskFunctionType); +//////////////////////////////// +//~ rjf: Task Kickoff Parameters + +typedef struct TS_KickoffParams TS_KickoffParams; +struct TS_KickoffParams +{ + Arena **optional_arena_ptr; + void *in; +}; + +//////////////////////////////// +//~ rjf: Task Join Result + +typedef struct TS_JoinResult TS_JoinResult; +struct TS_JoinResult +{ + B32 good; + void *out; +}; + //////////////////////////////// //~ rjf: Task Artifact Cache Types @@ -46,7 +66,7 @@ struct TS_TaskArtifact TS_TaskArtifact *next; U64 num; B64 task_is_done; - void *result; + void *out; }; typedef struct TS_TaskArtifactSlot TS_TaskArtifactSlot; @@ -112,6 +132,7 @@ global TS_Shared *ts_shared = 0; //~ rjf: Basic Type Functions internal TS_Ticket ts_ticket_zero(void); +internal B32 ts_ticket_match(TS_Ticket a, TS_Ticket b); internal void ts_ticket_list_push(Arena *arena, TS_TicketList *list, TS_Ticket ticket); //////////////////////////////// @@ -127,9 +148,10 @@ internal U64 ts_thread_count(void); //////////////////////////////// //~ rjf: High-Level Task Kickoff / Joining -internal TS_Ticket ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p); -internal void *ts_join(TS_Ticket ticket, U64 endt_us); -#define ts_join_struct(ticket, endt_us, type) (type *)ts_join((ticket), (endt_us)) +internal TS_Ticket ts_kickoff_(TS_TaskFunctionType *entry_point, TS_KickoffParams *params); +#define ts_kickoff(entry_point, input_ptr, ...) ts_kickoff_((entry_point), &(TS_KickoffParams){.in = (input_ptr), __VA_ARGS__}) +internal TS_JoinResult ts_join(TS_Ticket ticket, U64 endt_us); +#define ts_join_struct(ticket, endt_us, type) (type *)ts_join((ticket), (endt_us)).out //////////////////////////////// //~ rjf: Task Threads