mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
implement 'priority thread' in demon, to prefer debug events from selected thread - greatly improves multithreaded stepping
This commit is contained in:
@@ -5870,6 +5870,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
//- rjf: setup run controls
|
||||
//
|
||||
DMN_RunCtrls run_ctrls = {0};
|
||||
run_ctrls.priority_thread = target_thread.dmn_handle;
|
||||
run_ctrls.ignore_previous_exception = 1;
|
||||
run_ctrls.run_entity_count = frozen_threads.count;
|
||||
run_ctrls.run_entities = push_array(scratch.arena, DMN_Handle, run_ctrls.run_entity_count);
|
||||
|
||||
@@ -139,6 +139,7 @@ struct DMN_TrapChunkList
|
||||
typedef struct DMN_RunCtrls DMN_RunCtrls;
|
||||
struct DMN_RunCtrls
|
||||
{
|
||||
DMN_Handle priority_thread;
|
||||
DMN_Handle single_step_thread;
|
||||
B8 ignore_previous_exception;
|
||||
B8 run_entities_are_unfrozen;
|
||||
|
||||
@@ -1801,40 +1801,14 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: resume threads which will run
|
||||
//
|
||||
ProfScope("resume threads which will run")
|
||||
{
|
||||
for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
|
||||
{
|
||||
DMN_W32_Entity *thread = n->v;
|
||||
DWORD resume_result = ResumeThread(thread->handle);
|
||||
switch(resume_result)
|
||||
{
|
||||
case 0xffffffffu:
|
||||
{
|
||||
// TODO(rjf): error - unknown cause. need to do GetLastError, FormatMessage
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
DWORD desired_counter = 0;
|
||||
DWORD current_counter = resume_result - 1;
|
||||
if(current_counter != desired_counter)
|
||||
{
|
||||
// NOTE(rjf): Warning. The user has manually suspended this thread,
|
||||
// so even though from Demon's perspective it thinks this thread
|
||||
// should run, it will not, because the user has manually called
|
||||
// SuspendThread or used CREATE_SUSPENDED or whatever.
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: loop, consume win32 debug events until we produce the relevant demon events
|
||||
//
|
||||
B32 priority_mode = !dmn_handle_match(dmn_handle_zero(), ctrls->priority_thread);
|
||||
B32 did_priority_mode = priority_mode;
|
||||
B32 do_threads_resume = 1;
|
||||
DMN_W32_EntityNode *first_ran_thread = 0;
|
||||
DMN_W32_EntityNode *last_ran_thread = 0;
|
||||
U64 begin_time = os_now_microseconds();
|
||||
String8List debug_strings = {0};
|
||||
DMN_Event *debug_strings_event = 0;
|
||||
@@ -1842,6 +1816,54 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
keep_going = 0;
|
||||
|
||||
////////////////////////
|
||||
//- rjf: resume threads that we want to run
|
||||
//
|
||||
// if priority mode? => first, just resume priority thread
|
||||
// if not? => resume all non-priority threads
|
||||
//
|
||||
if(do_threads_resume)
|
||||
{
|
||||
do_threads_resume = 0;
|
||||
for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
|
||||
{
|
||||
DMN_W32_Entity *thread = n->v;
|
||||
B32 thread_is_priority = dmn_handle_match(dmn_w32_handle_from_entity(thread), ctrls->priority_thread);
|
||||
if((priority_mode && !thread_is_priority) ||
|
||||
(!priority_mode && did_priority_mode && thread_is_priority))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DWORD resume_result = ResumeThread(thread->handle);
|
||||
DMN_W32_EntityNode *n = push_array(scratch.arena, DMN_W32_EntityNode, 1);
|
||||
SLLQueuePush(first_ran_thread, last_ran_thread, n);
|
||||
n->v = thread;
|
||||
switch(resume_result)
|
||||
{
|
||||
case 0xffffffffu:
|
||||
{
|
||||
// TODO(rjf): error - unknown cause. need to do GetLastError, FormatMessage
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
DWORD desired_counter = 0;
|
||||
DWORD current_counter = resume_result - 1;
|
||||
if(current_counter != desired_counter)
|
||||
{
|
||||
// NOTE(rjf): Warning. The user has manually suspended this thread,
|
||||
// so even though from Demon's perspective it thinks this thread
|
||||
// should run, it will not, because the user has manually called
|
||||
// SuspendThread or used CREATE_SUSPENDED or whatever.
|
||||
}
|
||||
}break;
|
||||
}
|
||||
if(priority_mode && thread_is_priority)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
//- rjf: choose win32 resume code
|
||||
//
|
||||
@@ -1878,7 +1900,12 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
}
|
||||
if(resume_good)
|
||||
{
|
||||
evt_good = !!WaitForDebugEvent(&evt, 100);
|
||||
DWORD wait_ms = 100;
|
||||
if(priority_mode)
|
||||
{
|
||||
wait_ms = 30;
|
||||
}
|
||||
evt_good = !!WaitForDebugEvent(&evt, wait_ms);
|
||||
if(evt_good)
|
||||
{
|
||||
dmn_w32_shared->resume_needed = 1;
|
||||
@@ -1891,6 +1918,11 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
(void)err;
|
||||
keep_going = 1;
|
||||
}
|
||||
if(priority_mode)
|
||||
{
|
||||
priority_mode = 0;
|
||||
do_threads_resume = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2664,7 +2696,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
//
|
||||
ProfScope("suspend threads which ran")
|
||||
{
|
||||
for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
|
||||
for(DMN_W32_EntityNode *n = first_ran_thread; n != 0; n = n->next)
|
||||
{
|
||||
DMN_W32_Entity *thread = n->v;
|
||||
if(thread->kind != DMN_W32_EntityKind_Thread)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
//
|
||||
//- urgent fixes
|
||||
// [ ] hardware breakpoints regression (global eval in ctrl)
|
||||
// [ ] []string being sized by [0], due to `.` applying to first ^string
|
||||
//
|
||||
//- memory view
|
||||
// [ ] have smaller visible range than entire memory
|
||||
@@ -21,9 +20,6 @@
|
||||
// [ ] disassembly sometimes has a problem where source line annotations are
|
||||
// periodically removed/inserted... maybe updating on fs change when we
|
||||
// shouldn't, non-deterministic line annotation path?
|
||||
// [ ] process memory cache sometimes is not correctly updating - best repro
|
||||
// case so far is (for some reason?) only hover evaluation - only spotted
|
||||
// on laptop in debug builds. g0 ctrl_bindings.bindings initialization.
|
||||
//
|
||||
//- watch improvements
|
||||
// [ ] *ALL* expressions in watch windows need to be editable.
|
||||
@@ -115,7 +111,6 @@
|
||||
//- eval improvements
|
||||
// [ ] maybe add extra caching layer to process memory querying? we pay a pretty
|
||||
// heavy cost even to just read 8 bytes...
|
||||
// [ ] evaluate `foo.bar` symbol names without escape hatch?
|
||||
// [ ] serializing eval view maps (?)
|
||||
// [ ] EVAL LOOKUP RULES -> currently going 0 -> rdis_count, but we need
|
||||
// to prioritize the primary rdi
|
||||
@@ -149,7 +144,6 @@
|
||||
// [ ] investigate wide-conversion performance
|
||||
// [ ] oversubscribing cores?
|
||||
// [ ] conversion crashes?
|
||||
// [ ] fastpath lookup to determine debug info relevance?
|
||||
// [ ] live++ investigations - ctrl+alt+f11 in UE?
|
||||
//
|
||||
//- memory usage improvements
|
||||
@@ -189,6 +183,12 @@
|
||||
// is not correctly incremented.
|
||||
// [x] output: add option for scroll-to-bottom - ensure this shows up in universal ctx menu
|
||||
// [x] auto-annotations for non-locals
|
||||
// [x] []string being sized by [0], due to `.` applying to first ^string
|
||||
// [x] process memory cache sometimes is not correctly updating - best repro
|
||||
// case so far is (for some reason?) only hover evaluation - only spotted
|
||||
// on laptop in debug builds. g0 ctrl_bindings.bindings initialization.
|
||||
// [x] evaluate `foo.bar` symbol names without escape hatch?
|
||||
// [x] fastpath lookup to determine debug info relevance?
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Options
|
||||
|
||||
Reference in New Issue
Block a user