pass over ctrl call stack lookup path, eliminate races between multiple retry loops

This commit is contained in:
Ryan Fleury
2025-06-18 12:42:34 -07:00
parent a1f71379f4
commit df901b2497
+65 -76
View File
@@ -3411,99 +3411,88 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_
//- rjf: loop: try to grab cached call stack; request; wait
//
B32 can_request = !ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state);
B32 did_request = 0;
OS_MutexScopeR(stripe->rw_mutex)
for(;;)
{
CTRL_CallStackCacheNode *taken_node = 0;
for(;;)
//- rjf: step 1: [read-only] try to look for current call stack; wait if working
B32 node_exists = 0;
B32 node_stale = 1;
B32 node_working = 0;
OS_MutexScopeR(stripe->rw_mutex) for(;;)
{
////////////////////////////
//- rjf: try to grab cached
//
B32 is_good = 0;
B32 is_stale = 1;
B32 is_working = 0;
CTRL_CallStackCacheNode *node = 0;
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
{
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
if(ctrl_handle_match(n->thread, handle))
{
if(ctrl_handle_match(n->thread, handle))
{
node = n;
is_good = 1;
is_stale = (reg_gen > n->reg_gen || mem_gen > n->mem_gen);
is_working = (n->working_count > 0);
call_stack = n->call_stack;
taken_node = node;
break;
}
node = n;
node_exists = 1;
node_stale = (reg_gen > n->reg_gen || mem_gen > n->mem_gen);
node_working = (n->working_count > 0);
break;
}
}
////////////////////////////
//- rjf: create node if needed
//
if(!is_good) OS_MutexScopeRWPromote(stripe->rw_mutex)
{
node = 0;
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
{
if(ctrl_handle_match(n->thread, handle))
{
node = n;
break;
}
}
if(node == 0)
{
node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1);
DLLPushBack(slot->first, slot->last, node);
node->thread = thread->handle;
}
}
////////////////////////////
//- rjf: request if needed
//
if(can_request && node != 0 && !is_working && is_stale)
{
if(ctrl_u2csb_enqueue_req(thread->handle, endt_us))
{
did_request = 1;
is_working = 1;
ins_atomic_u64_inc_eval(&node->working_count);
DeferLoop(os_rw_mutex_drop_r(stripe->rw_mutex), os_rw_mutex_take_r(stripe->rw_mutex))
{
async_push_work(ctrl_call_stack_build_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low);
}
}
}
////////////////////////////
//- rjf: good, or timeout? -> exit
//
if(!can_request || !is_stale || os_now_microseconds() >= endt_us)
if(node_exists && (!node_stale || os_now_microseconds() >= endt_us))
{
call_stack = node->call_stack;
ctrl_scope_touch_call_stack_node__stripe_r_guarded(scope, stripe, node);
break;
}
////////////////////////////
//- rjf: time to wait for new result? -> wait
//
if(did_request && !is_working)
{
break;
}
else if(did_request)
else if(node_working)
{
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
}
else
{
break;
}
}
if(taken_node != 0)
//- rjf: step 2: [write] node does not exist => create; request if new or stale
CTRL_CallStackCacheNode *node_to_request = 0;
if(!node_exists || node_stale) OS_MutexScopeW(stripe->rw_mutex)
{
ctrl_scope_touch_call_stack_node__stripe_r_guarded(scope, stripe, taken_node);
CTRL_CallStackCacheNode *node = 0;
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
{
if(ctrl_handle_match(n->thread, handle))
{
node = n;
break;
}
}
if(node == 0)
{
node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1);
DLLPushBack(slot->first, slot->last, node);
node->thread = thread->handle;
}
if(can_request && node->working_count == 0)
{
node->working_count += 1;
node_to_request = node;
}
}
//- rjf: step 3: request if needed
if(node_to_request != 0)
{
if(ctrl_u2csb_enqueue_req(thread->handle, endt_us))
{
async_push_work(ctrl_call_stack_build_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low);
}
else OS_MutexScopeW(stripe->rw_mutex)
{
node_to_request->working_count -= 1;
}
}
//- rjf: step 4: out of time => exit
if(os_now_microseconds() >= endt_us)
{
break;
}
}
return call_stack;
}