mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-07-09 11:01:37 -07:00
introduce dedicated kill-all path; fix exit conditions for single-stepping stuck threads to be robust toward unexpected kills; fix exit conditions for kill-single-process path, to be more robust to halts; correctly report stop cause
This commit is contained in:
+107
-13
@@ -81,6 +81,7 @@ ctrl_string_from_msg_kind(CTRL_MsgKind kind)
|
||||
case CTRL_MsgKind_Launch: {result = str8_lit("Launch");}break;
|
||||
case CTRL_MsgKind_Attach: {result = str8_lit("Attach");}break;
|
||||
case CTRL_MsgKind_Kill: {result = str8_lit("Kill");}break;
|
||||
case CTRL_MsgKind_KillAll: {result = str8_lit("KillAll");}break;
|
||||
case CTRL_MsgKind_Detach: {result = str8_lit("Detach");}break;
|
||||
case CTRL_MsgKind_Run: {result = str8_lit("Run");}break;
|
||||
case CTRL_MsgKind_SingleStep: {result = str8_lit("SingleStep");}break;
|
||||
@@ -3250,8 +3251,7 @@ ctrl_thread__entry_point(void *p)
|
||||
//- rjf: process messages
|
||||
DMN_CtrlExclusiveAccessScope
|
||||
{
|
||||
B32 done = 0;
|
||||
for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0 && done == 0; msg_n = msg_n->next)
|
||||
for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0; msg_n = msg_n->next)
|
||||
{
|
||||
CTRL_Msg *msg = &msg_n->v;
|
||||
{
|
||||
@@ -3275,9 +3275,10 @@ ctrl_thread__entry_point(void *p)
|
||||
case CTRL_MsgKind_Launch: {ctrl_thread__launch (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_Attach: {ctrl_thread__attach (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_Kill: {ctrl_thread__kill (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_KillAll: {ctrl_thread__kill_all (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_Detach: {ctrl_thread__detach (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg); done = 1;}break;
|
||||
case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg); done = 1;}break;
|
||||
case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg);}break;
|
||||
case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg);}break;
|
||||
|
||||
//- rjf: configuration
|
||||
case CTRL_MsgKind_SetUserEntryPoints:
|
||||
@@ -4391,6 +4392,7 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, process, exit_code);
|
||||
|
||||
//- rjf: wait for process to be dead
|
||||
CTRL_EventCause cause = CTRL_EventCause_Finished;
|
||||
if(kill_worked)
|
||||
{
|
||||
DMN_RunCtrls run_ctrls = {0};
|
||||
@@ -4401,12 +4403,102 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
for(B32 done = 0; done == 0;)
|
||||
{
|
||||
DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0);
|
||||
if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process))
|
||||
switch(event->kind)
|
||||
{
|
||||
done = 1;
|
||||
default:{}break;
|
||||
case DMN_EventKind_ExitProcess:
|
||||
if(dmn_handle_match(event->process, process))
|
||||
{
|
||||
done = 1;
|
||||
}break;
|
||||
case DMN_EventKind_Error:{done = 1; cause = CTRL_EventCause_Error;}break;
|
||||
case DMN_EventKind_Halt: {done = 1; cause = CTRL_EventCause_InterruptedByHalt;}break;
|
||||
}
|
||||
if(event->kind == DMN_EventKind_Null ||
|
||||
event->kind == DMN_EventKind_Error)
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: record stop
|
||||
{
|
||||
CTRL_EventList evts = {0};
|
||||
CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts);
|
||||
event->kind = CTRL_EventKind_Stopped;
|
||||
event->cause = cause;
|
||||
event->msg_id = msg->msg_id;
|
||||
if(kill_worked)
|
||||
{
|
||||
event->entity = msg->entity;
|
||||
}
|
||||
ctrl_c2u_push_events(&evts);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
U32 exit_code = msg->exit_code;
|
||||
|
||||
//- rjf: gather all currently existing processes
|
||||
CTRL_EntityList initial_processes = ctrl_entity_list_from_kind(ctrl_state->ctrl_thread_entity_store, CTRL_EntityKind_Process);
|
||||
typedef struct Task Task;
|
||||
struct Task
|
||||
{
|
||||
Task *next;
|
||||
Task *prev;
|
||||
CTRL_Entity *process;
|
||||
};
|
||||
Task *first_task = 0;
|
||||
Task *last_task = 0;
|
||||
for(CTRL_EntityNode *n = initial_processes.first; n != 0; n = n->next)
|
||||
{
|
||||
Task *t = push_array(scratch.arena, Task, 1);
|
||||
t->process = n->v;
|
||||
DLLPushBack(first_task, last_task, t);
|
||||
}
|
||||
|
||||
//- rjf: kill processes as needed, wait for all processes to be dead
|
||||
CTRL_EventCause cause = CTRL_EventCause_Finished;
|
||||
if(first_task != 0)
|
||||
{
|
||||
DMN_RunCtrls run_ctrls = {0};
|
||||
for(B32 done = 0; !done;)
|
||||
{
|
||||
// rjf: kill remaining processes
|
||||
for(Task *t = first_task, *next = 0; t != 0; t = next)
|
||||
{
|
||||
next = t->next;
|
||||
B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, t->process->handle.dmn_handle, exit_code);
|
||||
if(kill_worked)
|
||||
{
|
||||
DLLRemove(first_task, last_task, t);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: get next event
|
||||
DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0);
|
||||
|
||||
// rjf: process event
|
||||
switch(event->kind)
|
||||
{
|
||||
default:{}break;
|
||||
case DMN_EventKind_CreateProcess:
|
||||
{
|
||||
CTRL_Entity *new_process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, event->process));
|
||||
Task *t = push_array(scratch.arena, Task, 1);
|
||||
t->process = new_process;
|
||||
DLLPushBack(first_task, last_task, t);
|
||||
}break;
|
||||
case DMN_EventKind_Error:{done = 1; cause = CTRL_EventCause_Error;}break;
|
||||
case DMN_EventKind_Halt: {done = 1; cause = CTRL_EventCause_InterruptedByHalt;}break;
|
||||
}
|
||||
|
||||
// rjf: end if all processes are gone
|
||||
CTRL_EntityList processes = ctrl_entity_list_from_kind(ctrl_state->ctrl_thread_entity_store, CTRL_EntityKind_Process);
|
||||
if(processes.count == 0)
|
||||
{
|
||||
done = 1;
|
||||
}
|
||||
@@ -4418,12 +4510,8 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
CTRL_EventList evts = {0};
|
||||
CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts);
|
||||
event->kind = CTRL_EventKind_Stopped;
|
||||
event->cause = CTRL_EventCause_Finished;
|
||||
event->cause = cause;
|
||||
event->msg_id = msg->msg_id;
|
||||
if(kill_worked)
|
||||
{
|
||||
event->entity = msg->entity;
|
||||
}
|
||||
ctrl_c2u_push_events(&evts);
|
||||
}
|
||||
|
||||
@@ -4623,6 +4711,12 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
switch(event->kind)
|
||||
{
|
||||
default:{}break;
|
||||
case DMN_EventKind_ExitThread:
|
||||
if(dmn_handle_match(event->thread, thread))
|
||||
{
|
||||
stop_cause = CTRL_EventCause_Error;
|
||||
goto stop;
|
||||
}break;
|
||||
case DMN_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop;
|
||||
case DMN_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop;
|
||||
case DMN_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop;
|
||||
|
||||
@@ -517,6 +517,7 @@ typedef enum CTRL_MsgKind
|
||||
CTRL_MsgKind_Launch,
|
||||
CTRL_MsgKind_Attach,
|
||||
CTRL_MsgKind_Kill,
|
||||
CTRL_MsgKind_KillAll,
|
||||
CTRL_MsgKind_Detach,
|
||||
CTRL_MsgKind_Run,
|
||||
CTRL_MsgKind_SingleStep,
|
||||
@@ -1141,6 +1142,7 @@ internal void ctrl_thread__end_and_flush_info_log(void);
|
||||
internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
|
||||
@@ -2108,16 +2108,11 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}break;
|
||||
case D_CmdKind_KillAll:
|
||||
{
|
||||
CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process);
|
||||
for(CTRL_EntityNode *n = processes.first; n != 0; n = n->next)
|
||||
{
|
||||
CTRL_Msg *msg = ctrl_msg_list_push(scratch.arena, &ctrl_msgs);
|
||||
msg->kind = CTRL_MsgKind_Kill;
|
||||
msg->exit_code = 1;
|
||||
msg->entity = n->v->handle;
|
||||
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
|
||||
MemoryCopyStruct(&msg->meta_evals, meta_evals);
|
||||
}
|
||||
CTRL_Msg *msg = ctrl_msg_list_push(scratch.arena, &ctrl_msgs);
|
||||
msg->kind = CTRL_MsgKind_KillAll;
|
||||
msg->exit_code = 1;
|
||||
MemoryCopyArray(msg->exception_code_filters, exception_code_filters);
|
||||
MemoryCopyStruct(&msg->meta_evals, meta_evals);
|
||||
}break;
|
||||
case D_CmdKind_Detach:
|
||||
{
|
||||
@@ -2305,8 +2300,12 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}break;
|
||||
case D_CmdKind_Restart:
|
||||
{
|
||||
d_cmd(D_CmdKind_KillAll);
|
||||
d_cmd(D_CmdKind_LaunchAndRun);
|
||||
CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process);
|
||||
if(processes.count != 0)
|
||||
{
|
||||
d_cmd(D_CmdKind_KillAll);
|
||||
d_cmd(D_CmdKind_LaunchAndRun);
|
||||
}
|
||||
}break;
|
||||
case D_CmdKind_StepInto:
|
||||
case D_CmdKind_StepOver:
|
||||
|
||||
Reference in New Issue
Block a user