diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 7a60663f..faf87e31 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -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; }