From 47d658daed114af180e520d433786966f09d367f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 19 May 2025 16:21:38 -0700 Subject: [PATCH] ensure rd frame depth is always computed correctly; eliminate incorrect frame scope (ctrl/di) usage - fix weird deadlocks! --- src/hash_store/hash_store.c | 142 ++++++++++++++++++++++++------------ src/hash_store/hash_store.h | 9 +-- src/raddbg/raddbg_core.c | 37 ++++------ 3 files changed, 115 insertions(+), 73 deletions(-) diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c index 297f532f..95cdd20f 100644 --- a/src/hash_store/hash_store.c +++ b/src/hash_store/hash_store.c @@ -139,10 +139,15 @@ hs_root_alloc(void) internal void hs_root_release(HS_Root root) { + //- rjf: unpack root U64 slot_idx = root.u64[1]%hs_shared->root_slots_count; U64 stripe_idx = slot_idx%hs_shared->root_stripes_count; HS_RootSlot *slot = &hs_shared->root_slots[slot_idx]; HS_Stripe *stripe = &hs_shared->root_stripes[stripe_idx]; + + //- rjf: release root node, grab its arena / ID list + Arena *root_arena = 0; + HS_RootIDChunkList root_ids = {0}; OS_MutexScopeW(stripe->rw_mutex) { for(HS_RootNode *n = slot->first; n != 0; n = n->next) @@ -150,12 +155,62 @@ hs_root_release(HS_Root root) if(MemoryMatchStruct(&root, &n->root)) { DLLRemove(slot->first, slot->last, n); - arena_release(n->arena); + root_arena = n->arena; + root_ids = n->ids; SLLStackPush(hs_shared->root_stripes_free_nodes[stripe_idx], n); break; } } } + + //- rjf: release all IDs + for(HS_RootIDChunkNode *id_chunk_n = root_ids.first; id_chunk_n != 0; id_chunk_n = id_chunk_n->next) + { + for EachIndex(chunk_idx, id_chunk_n->count) + { + HS_ID id = id_chunk_n->v[chunk_idx]; + HS_Key key = hs_key_make(root, id); + U64 key_hash = hs_little_hash_from_data(str8_struct(&key)); + U64 key_slot_idx = key_hash%hs_shared->key_slots_count; + U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; + HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; + HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; + OS_MutexScopeW(key_stripe->rw_mutex) + { + for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(hs_key_match(n->key, key)) + { + // rjf: release reference to all hashes + for(U64 history_idx = 0; history_idx < HS_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1) + { + U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; + U64 hash_slot_idx = hash.u64[1]%hs_shared->slots_count; + U64 hash_stripe_idx = hash_slot_idx%hs_shared->stripes_count; + HS_Slot *hash_slot = &hs_shared->slots[hash_slot_idx]; + HS_Stripe *hash_stripe = &hs_shared->stripes[hash_stripe_idx]; + OS_MutexScopeR(hash_stripe->rw_mutex) + { + for(HS_Node *n = hash_slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + ins_atomic_u64_dec_eval(&n->key_ref_count); + break; + } + } + } + } + + // rjf: release key node + DLLRemove(key_slot->first, key_slot->last, n); + SLLStackPush(hs_shared->key_stripes_free_nodes[key_stripe_idx], n); + break; + } + } + } + } + } } //////////////////////////////// @@ -226,6 +281,8 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) U128 key_expired_hash = {0}; ProfScope("commit this hash to key cache") OS_MutexScopeW(key_stripe->rw_mutex) { + // rjf: find existing key + B32 key_is_new = 0; HS_KeyNode *key_node = 0; for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) { @@ -235,8 +292,11 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) break; } } + + // rjf: create key node if it doesn't exist if(!key_node) { + key_is_new = 1; key_node = hs_shared->key_stripes_free_nodes[key_stripe_idx]; if(key_node) { @@ -249,6 +309,8 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) key_node->key = key; DLLPushBack(key_slot->first, key_slot->last, key_node); } + + // rjf: push hash into key's history if(key_node) { if(key_node->hash_history_gen >= HS_KEY_HASH_HISTORY_STRONG_REF_COUNT) @@ -258,6 +320,40 @@ hs_submit_data(HS_Key key, Arena **data_arena, String8 data) key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; key_node->hash_history_gen += 1; } + + // rjf: key is new -> add this key to the associated root + if(key_is_new) + { + U64 root_hash = hs_little_hash_from_data(str8_struct(&key.root)); + U64 root_slot_idx = root_hash%hs_shared->root_slots_count; + U64 root_stripe_idx = root_slot_idx%hs_shared->root_stripes_count; + HS_RootSlot *root_slot = &hs_shared->root_slots[root_slot_idx]; + HS_Stripe *root_stripe = &hs_shared->root_stripes[root_stripe_idx]; + OS_MutexScopeW(root_stripe->rw_mutex) + { + for(HS_RootNode *n = root_slot->first; n != 0; n = n->next) + { + if(MemoryMatchStruct(&n->root, &key.root)) + { + HS_RootIDChunkNode *chunk = n->ids.last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(n->arena, HS_RootIDChunkNode, 1); + SLLQueuePush(n->ids.first, n->ids.last, chunk); + n->ids.chunk_count += 1; + chunk->cap = 1024; + chunk->v = push_array_no_zero(n->arena, HS_ID, chunk->cap); + } + chunk->v[chunk->count] = key.id; + key_node->root_id_chunk_node = chunk; + key_node->root_id_chunk_idx = chunk->count; + chunk->count += 1; + n->ids.total_count += 1; + break; + } + } + } + } } //- rjf: decrement key ref count of expired hash @@ -354,50 +450,6 @@ hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node) SLLStackPush(scope->top_touch, touch); } -//////////////////////////////// -//~ rjf: Key Closing - -internal void -hs_key_close(HS_Key key) -{ - U64 key_hash = hs_little_hash_from_data(str8_struct(&key)); - U64 key_slot_idx = key_hash%hs_shared->key_slots_count; - U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; - HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; - HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; - OS_MutexScopeW(key_stripe->rw_mutex) - { - for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) - { - if(hs_key_match(n->key, key)) - { - for(U64 history_idx = 0; history_idx < HS_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1) - { - U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; - U64 hash_slot_idx = hash.u64[1]%hs_shared->slots_count; - U64 hash_stripe_idx = hash_slot_idx%hs_shared->stripes_count; - HS_Slot *hash_slot = &hs_shared->slots[hash_slot_idx]; - HS_Stripe *hash_stripe = &hs_shared->stripes[hash_stripe_idx]; - OS_MutexScopeR(hash_stripe->rw_mutex) - { - for(HS_Node *n = hash_slot->first; n != 0; n = n->next) - { - if(u128_match(n->hash, hash)) - { - ins_atomic_u64_dec_eval(&n->key_ref_count); - break; - } - } - } - } - DLLRemove(key_slot->first, key_slot->last, n); - SLLStackPush(hs_shared->key_stripes_free_nodes[key_stripe_idx], n); - break; - } - } - } -} - //////////////////////////////// //~ rjf: Downstream Accesses diff --git a/src/hash_store/hash_store.h b/src/hash_store/hash_store.h index c5c3412e..209fd03c 100644 --- a/src/hash_store/hash_store.h +++ b/src/hash_store/hash_store.h @@ -70,7 +70,7 @@ typedef struct HS_RootIDChunkNode HS_RootIDChunkNode; struct HS_RootIDChunkNode { HS_RootIDChunkNode *next; - U128 *v; + HS_ID *v; U64 count; U64 cap; }; @@ -109,6 +109,8 @@ struct HS_KeyNode { HS_KeyNode *next; HS_KeyNode *prev; + HS_RootIDChunkNode *root_id_chunk_node; + U64 root_id_chunk_idx; HS_Key key; U128 hash_history[HS_KEY_HASH_HISTORY_COUNT]; U64 hash_history_gen; @@ -250,11 +252,6 @@ internal HS_Scope *hs_scope_open(void); internal void hs_scope_close(HS_Scope *scope); internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node); -//////////////////////////////// -//~ rjf: Key Closing - -internal void hs_key_close(HS_Key key); - //////////////////////////////// //~ rjf: Downstream Accesses diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 458ee937..e1fb2b4b 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -5778,7 +5778,6 @@ rd_window_state_from_cfg(RD_Cfg *cfg) if(window_cfg != &rd_nil_cfg && ws == &rd_nil_window_state) { Temp scratch = scratch_begin(0, 0); - rd_state->frame_depth += 1; // rjf: unpack configuration options B32 has_pos = 0; @@ -5853,7 +5852,6 @@ rd_window_state_from_cfg(RD_Cfg *cfg) DLLPushBack_NPZ(&rd_nil_window_state, rd_state->first_window_state, rd_state->last_window_state, ws, order_next, order_prev); DLLPushBack_NP(slot->first, slot->last, ws, hash_next, hash_prev); - rd_state->frame_depth -= 1; scratch_end(scratch); } @@ -11026,6 +11024,7 @@ rd_frame(void) ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); log_scope_begin(); + rd_state->frame_depth += 1; ////////////////////////////// //- rjf: (DEBUG) take top-level cfg roots, stringize them, and store them to hash store @@ -11076,7 +11075,7 @@ rd_frame(void) ////////////////////////////// //- rjf: iterate all tabs, touch their view-states // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { Temp scratch = scratch_begin(0, 0); RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); @@ -11103,7 +11102,7 @@ rd_frame(void) ////////////////////////////// //- rjf: garbage collect untouched immediate cfg trees // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { RD_Cfg *transient = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); for(RD_Cfg *tln = transient->first, *next = &rd_nil_cfg; tln != &rd_nil_cfg; tln = next) @@ -11136,7 +11135,7 @@ rd_frame(void) ////////////////////////////// //- rjf: garbage collect untouched view states // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { for EachIndex(slot_idx, rd_state->view_state_slots_count) { @@ -11195,7 +11194,7 @@ rd_frame(void) ////////////////////////////// //- rjf: animate all views // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { F32 slow_rate = 1 - pow_f32(2, (-10.f * rd_state->frame_dt)); F32 fast_rate = 1 - pow_f32(2, (-40.f * rd_state->frame_dt)); @@ -11242,7 +11241,7 @@ rd_frame(void) //- rjf: get events from the OS // OS_EventList events = {0}; - if(rd_state->frame_depth == 0) DeferLoop(rd_state->frame_depth += 1, rd_state->frame_depth -= 1) + if(rd_state->frame_depth == 1) { events = os_get_events(scratch.arena, rd_state->num_frames_requested == 0); } @@ -11250,8 +11249,10 @@ rd_frame(void) ////////////////////////////// //- rjf: open frame scopes // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { + if(rd_state->frame_di_scope) { di_scope_close(rd_state->frame_di_scope); } + if(rd_state->frame_ctrl_scope) { ctrl_scope_close(rd_state->frame_ctrl_scope); } rd_state->frame_di_scope = di_scope_open(); rd_state->frame_ctrl_scope = ctrl_scope_open(); } @@ -12456,7 +12457,7 @@ rd_frame(void) //////////////////////////// //- rjf: process top-level graphical commands // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { for(;rd_next_cmd(&cmd);) RD_RegsScope() { @@ -16512,7 +16513,7 @@ rd_frame(void) // the commands pushed by the view will be in the queue, and the core can // treat that queue as r/w again. // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { // rjf: rotate { @@ -16714,15 +16715,6 @@ rd_frame(void) rd_state->num_frames_requested -= 1; } - ////////////////////////////// - //- rjf: close frame scopes - // - if(rd_state->frame_depth == 0) - { - di_scope_close(rd_state->frame_di_scope); - ctrl_scope_close(rd_state->frame_ctrl_scope); - } - ////////////////////////////// //- rjf: submit rendering to all windows // @@ -16741,7 +16733,7 @@ rd_frame(void) ////////////////////////////// //- rjf: show windows after first frame // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { RD_CfgIDList windows_to_show = {0}; for(RD_WindowState *w = rd_state->first_window_state; w != &rd_nil_window_state; w = w->order_next) @@ -16755,7 +16747,7 @@ rd_frame(void) { RD_Cfg *window = rd_cfg_from_id(n->v); RD_WindowState *ws = rd_window_state_from_cfg(window); - DeferLoop(rd_state->frame_depth += 1, rd_state->frame_depth -= 1) os_window_first_paint(ws->os); + os_window_first_paint(ws->os); } } @@ -16776,7 +16768,7 @@ rd_frame(void) ////////////////////////////// //- rjf: bump command batch ring buffer generation // - if(rd_state->frame_depth == 0) + if(rd_state->frame_depth == 1) { rd_state->cmds_gen += 1; } @@ -16809,6 +16801,7 @@ rd_frame(void) } #endif + rd_state->frame_depth -= 1; scratch_end(scratch); ProfEnd(); }