mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
ensure rd frame depth is always computed correctly; eliminate incorrect frame scope (ctrl/di) usage - fix weird deadlocks!
This commit is contained in:
+97
-45
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+15
-22
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user