promote thread freeze state to ctrl entity tree; communicate via msgs for user -> ctrl, and communicate entity state changes back via events for ctrl -> user

This commit is contained in:
Ryan Fleury
2024-09-08 13:09:52 -07:00
parent fee500578a
commit 6cf0c7ee92
7 changed files with 129 additions and 125 deletions
+83 -38
View File
@@ -178,7 +178,6 @@ ctrl_msg_deep_copy(Arena *arena, CTRL_Msg *dst, CTRL_Msg *src)
dst->env_string_list = str8_list_copy(arena, &src->env_string_list);
dst->traps = ctrl_trap_list_copy(arena, &src->traps);
dst->user_bps = ctrl_user_breakpoint_list_copy(arena, &src->user_bps);
dst->freeze_state_threads = ctrl_machine_id_handle_pair_list_copy(arena, &src->freeze_state_threads);
}
//- rjf: list building
@@ -272,16 +271,6 @@ ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs)
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->condition.size);
str8_serial_push_data(scratch.arena, &msgs_srlzed, bp->condition.str, bp->condition.size);
}
// rjf: write freeze state thread list
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->freeze_state_threads.count);
for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next)
{
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &n->v);
}
// rjf: write freeze state
str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->freeze_state_is_frozen);
}
}
String8 string = str8_serial_end(arena, &msgs_srlzed);
@@ -394,19 +383,6 @@ ctrl_msg_list_from_serialized_string(Arena *arena, String8 string)
bp->condition.str = push_array_no_zero(arena, U8, bp->condition.size);
read_off += str8_deserial_read(string, read_off, bp->condition.str, bp->condition.size, 1);
}
// rjf: read freeze state thread list
U64 frozen_thread_count = 0;
read_off += str8_deserial_read_struct(string, read_off, &frozen_thread_count);
for(U64 idx = 0; idx < frozen_thread_count; idx += 1)
{
CTRL_MachineIDHandlePair pair = {0};
read_off += str8_deserial_read_struct(string, read_off, &pair);
ctrl_machine_id_handle_pair_list_push(arena, &msg->freeze_state_threads, &pair);
}
// rjf: read freeze state
read_off += str8_deserial_read_struct(string, read_off, &msg->freeze_state_is_frozen);
}
}
return msgs;
@@ -510,6 +486,17 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string)
////////////////////////////////
//~ rjf: Entity Type Functions
//- rjf: entity list data structures
internal void
ctrl_entity_list_push(Arena *arena, CTRL_EntityList *list, CTRL_Entity *entity)
{
CTRL_EntityNode *n = push_array(arena, CTRL_EntityNode, 1);
n->v = entity;
SLLQueuePush(list->first, list->last, n);
list->count += 1;
}
//- rjf: cache creation/destruction
internal CTRL_EntityStore *
@@ -944,12 +931,28 @@ ctrl_voff_range_from_vaddr_range(CTRL_Entity *module, Rng1U64 vaddr_range)
return result;
}
internal B32
ctrl_entity_tree_is_frozen(CTRL_Entity *root)
{
B32 is_frozen = 1;
for(CTRL_Entity *e = root; e != &ctrl_entity_nil; e = ctrl_entity_rec_depth_first_pre(e, root).next)
{
if(e->kind == CTRL_EntityKind_Thread && !e->is_frozen)
{
is_frozen = 0;
break;
}
}
return is_frozen;
}
//- rjf: entity tree iteration
internal CTRL_EntityRec
ctrl_entity_rec_depth_first(CTRL_Entity *entity, CTRL_Entity *subtree_root, U64 sib_off, U64 child_off)
{
CTRL_EntityRec result = {0};
result.next = &ctrl_entity_nil;
if((*MemberFromOffset(CTRL_Entity **, entity, child_off)) != &ctrl_entity_nil)
{
result.next = *MemberFromOffset(CTRL_Entity **, entity, child_off);
@@ -1019,6 +1022,16 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list)
CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity);
ctrl_entity_equip_string(store, thread, event->string);
}break;
case CTRL_EventKind_ThreadFrozen:
{
CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity);
thread->is_frozen = 1;
}break;
case CTRL_EventKind_ThreadThawed:
{
CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity);
thread->is_frozen = 0;
}break;
//- rjf: modules
case CTRL_EventKind_NewModule:
@@ -3100,6 +3113,24 @@ ctrl_thread__entry_point(void *p)
evt->timestamp = new_dbgi_timestamp;
ctrl_c2u_push_events(&evts);
}break;
case CTRL_MsgKind_FreezeThread:
{
CTRL_EventList evts = {0};
CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts);
evt->kind = CTRL_EventKind_ThreadFrozen;
evt->machine_id = msg->machine_id;
evt->entity = msg->entity;
ctrl_c2u_push_events(&evts);
}break;
case CTRL_MsgKind_ThawThread:
{
CTRL_EventList evts = {0};
CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts);
evt->kind = CTRL_EventKind_ThreadThawed;
evt->machine_id = msg->machine_id;
evt->entity = msg->entity;
ctrl_c2u_push_events(&evts);
}break;
}
}
}
@@ -4262,18 +4293,10 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
U64 rip = dmn_rip_from_thread(thread->handle);
// rjf: determine if thread is frozen
B32 thread_is_frozen = !msg->freeze_state_is_frozen;
for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next)
{
if(dmn_handle_match(n->v.handle, thread->handle))
{
thread_is_frozen ^= 1;
break;
}
}
B32 thread_is_frozen = thread->is_frozen;
// rjf: not frozen? -> check if stuck & gather if so
if(thread_is_frozen == 0)
if(!thread_is_frozen)
{
for(DMN_TrapChunkNode *n = user_traps.first; n != 0; n = n->next)
{
@@ -4352,6 +4375,28 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
}
}
//////////////////////////////
//- rjf: gather frozen threads
//
CTRL_EntityList frozen_threads = {0};
for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first;
machine != &ctrl_entity_nil;
machine = machine->next)
{
if(machine->kind != CTRL_EntityKind_Machine) { continue; }
for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next)
{
if(process->kind != CTRL_EntityKind_Process) { continue; }
for(CTRL_Entity *thread = process->first; thread != &ctrl_entity_nil; thread = thread->next)
{
if(thread->is_frozen)
{
ctrl_entity_list_push(scratch.arena, &frozen_threads, thread);
}
}
}
}
//////////////////////////////
//- rjf: resolve trap net
//
@@ -4417,14 +4462,14 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
//
DMN_RunCtrls run_ctrls = {0};
run_ctrls.ignore_previous_exception = 1;
run_ctrls.run_entity_count = msg->freeze_state_threads.count;
run_ctrls.run_entity_count = frozen_threads.count;
run_ctrls.run_entities = push_array(scratch.arena, DMN_Handle, run_ctrls.run_entity_count);
run_ctrls.run_entities_are_unfrozen = !msg->freeze_state_is_frozen;
run_ctrls.run_entities_are_unfrozen = 0;
{
U64 idx = 0;
for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next)
for(CTRL_EntityNode *n = frozen_threads.first; n != 0; n = n->next)
{
run_ctrls.run_entities[idx] = n->v.handle;
run_ctrls.run_entities[idx] = n->v->handle;
idx += 1;
}
}
+11 -2
View File
@@ -64,6 +64,7 @@ struct CTRL_Entity
CTRL_Entity *parent;
CTRL_EntityKind kind;
Arch arch;
B32 is_frozen;
CTRL_MachineID machine_id;
DMN_Handle handle;
U64 id;
@@ -278,6 +279,8 @@ typedef enum CTRL_MsgKind
CTRL_MsgKind_SingleStep,
CTRL_MsgKind_SetUserEntryPoints,
CTRL_MsgKind_SetModuleDebugInfoPath,
CTRL_MsgKind_FreezeThread,
CTRL_MsgKind_ThawThread,
CTRL_MsgKind_COUNT,
}
CTRL_MsgKind;
@@ -307,8 +310,6 @@ struct CTRL_Msg
String8List env_string_list;
CTRL_TrapList traps;
CTRL_UserBreakpointList user_bps;
CTRL_MachineIDHandlePairList freeze_state_threads; // NOTE(rjf): can be frozen or unfrozen, depending on `freeze_state_is_frozen`
B32 freeze_state_is_frozen;
};
typedef struct CTRL_MsgNode CTRL_MsgNode;
@@ -346,6 +347,10 @@ typedef enum CTRL_EventKind
CTRL_EventKind_EndThread,
CTRL_EventKind_EndModule,
//- rjf: thread freeze state changes
CTRL_EventKind_ThreadFrozen,
CTRL_EventKind_ThreadThawed,
//- rjf: debug info changes
CTRL_EventKind_ModuleDebugInfoPathChange,
@@ -713,6 +718,9 @@ internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 stri
////////////////////////////////
//~ rjf: Entity Type Functions
//- rjf: entity list data structures
internal void ctrl_entity_list_push(Arena *arena, CTRL_EntityList *list, CTRL_Entity *entity);
//- rjf: cache creation/destruction
internal CTRL_EntityStore *ctrl_entity_store_alloc(void);
internal void ctrl_entity_store_release(CTRL_EntityStore *store);
@@ -742,6 +750,7 @@ internal U64 ctrl_vaddr_from_voff(CTRL_Entity *module, U64 voff);
internal U64 ctrl_voff_from_vaddr(CTRL_Entity *module, U64 vaddr);
internal Rng1U64 ctrl_vaddr_range_from_voff_range(CTRL_Entity *module, Rng1U64 voff_range);
internal Rng1U64 ctrl_voff_range_from_vaddr_range(CTRL_Entity *module, Rng1U64 vaddr_range);
internal B32 ctrl_entity_tree_is_frozen(CTRL_Entity *root);
//- rjf: entity tree iteration
internal CTRL_EntityRec ctrl_entity_rec_depth_first(CTRL_Entity *entity, CTRL_Entity *subtree_root, U64 sib_off, U64 child_off);
+27 -73
View File
@@ -1371,7 +1371,6 @@ d_entity_release(D_Entity *entity)
log_infof("id: $0x%I64x\n", task->e->id);
log_infof("display_string: \"%S\"\n", name);
}
d_set_thread_freeze_state(task->e, 0);
SLLStackPush(d_state->entities_free[free_list_idx], task->e);
d_state->entities_free_count += 1;
d_state->entities_active_count -= 1;
@@ -1991,59 +1990,6 @@ d_entity_from_name_and_kind(String8 string, D_EntityKind kind)
return result;
}
//- rjf: entity freezing state
internal void
d_set_thread_freeze_state(D_Entity *thread, B32 frozen)
{
D_Handle thread_handle = d_handle_from_entity(thread);
D_HandleNode *already_frozen_node = d_handle_list_find(&d_state->frozen_threads, thread_handle);
B32 is_frozen = !!already_frozen_node;
B32 should_be_frozen = frozen;
// rjf: not frozen => frozen
if(!is_frozen && should_be_frozen)
{
D_HandleNode *node = d_state->free_handle_node;
if(node)
{
SLLStackPop(d_state->free_handle_node);
}
else
{
node = push_array(d_state->arena, D_HandleNode, 1);
}
node->handle = thread_handle;
d_handle_list_push_node(&d_state->frozen_threads, node);
}
// rjf: frozen => not frozen
if(is_frozen && !should_be_frozen)
{
d_handle_list_remove(&d_state->frozen_threads, already_frozen_node);
SLLStackPush(d_state->free_handle_node, already_frozen_node);
}
}
internal B32
d_entity_is_frozen(D_Entity *entity)
{
B32 is_frozen = !d_entity_is_nil(entity);
for(D_Entity *e = entity; !d_entity_is_nil(e); e = d_entity_rec_depth_first_pre(e, entity).next)
{
if(e->kind == D_EntityKind_Thread)
{
B32 thread_is_frozen = !!d_handle_list_find(&d_state->frozen_threads, d_handle_from_entity(e));
if(!thread_is_frozen)
{
is_frozen = 0;
break;
}
}
}
return is_frozen;
}
////////////////////////////////
//~ rjf: Command Stateful Functions
@@ -3313,9 +3259,24 @@ d_hash_from_ctrl_param_state(D_BreakpointArray *breakpoints)
// rjf: build data strings of all param data
String8List strings = {0};
{
for(D_HandleNode *n = d_state->frozen_threads.first; n != 0; n = n->next)
for(CTRL_Entity *machine = d_state->ctrl_entity_store->root->first;
machine != &ctrl_entity_nil;
machine = machine->next)
{
str8_list_push(scratch.arena, &strings, str8_struct(&n->handle));
if(machine->kind != CTRL_EntityKind_Machine) { continue; }
for(CTRL_Entity *process = machine->first;
process != &ctrl_entity_nil;
process = process->next)
{
if(process->kind != CTRL_EntityKind_Process) { continue; }
for(CTRL_Entity *thread = process->first;
thread != &ctrl_entity_nil;
thread = thread->next)
{
if(thread->kind != CTRL_EntityKind_Thread) { continue; }
str8_list_push(scratch.arena, &strings, str8_struct(&thread->is_frozen));
}
}
}
for(U64 idx = 0; idx < breakpoints->count; idx += 1)
{
@@ -6515,7 +6476,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, DI_
case CTRL_EventKind_EndThread:
{
D_Entity *thread = d_entity_from_ctrl_handle(event->machine_id, event->entity);
d_set_thread_freeze_state(thread, 0);
d_entity_mark_for_deletion(thread);
}break;
@@ -6961,11 +6921,10 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, DI_
case D_CmdKind_Continue:
{
B32 good_to_run = 0;
D_EntityList machines = d_query_cached_entity_list_with_kind(D_EntityKind_Machine);
for(D_EntityNode *n = machines.first; n != 0; n = n->next)
CTRL_EntityList threads = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Thread);
for(CTRL_EntityNode *n = threads.first; n != 0; n = n->next)
{
D_Entity *machine = n->entity;
if(!d_entity_is_frozen(machine))
if(!n->v->is_frozen)
{
good_to_run = 1;
break;
@@ -7001,7 +6960,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, DI_
d_cmd_list_push(arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_Error));
}
}
else if(d_entity_is_frozen(d_thread))
else if(thread->is_frozen)
{
D_CmdParams p = params;
p.string = str8_lit("Must thaw selected thread before stepping.");
@@ -7928,7 +7887,12 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, DI_
{
if(e->kind == D_EntityKind_Thread)
{
d_set_thread_freeze_state(e, should_freeze);
CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(d_state->ctrl_entity_store, e->ctrl_machine_id, e->ctrl_handle);
thread->is_frozen = should_freeze;
CTRL_Msg msg = {should_freeze ? CTRL_MsgKind_FreezeThread : CTRL_MsgKind_ThawThread};
msg.machine_id = thread->machine_id;
msg.entity = thread->handle;
d_push_ctrl_msg(&msg);
}
}
}break;
@@ -8403,16 +8367,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, DI_
ctrl_user_breakpoint_list_push(scratch.arena, &msg.user_bps, &ctrl_user_bp);
}
}
for(D_HandleNode *n = d_state->frozen_threads.first; n != 0; n = n->next)
{
D_Entity *thread = d_entity_from_handle(n->handle);
if(!d_entity_is_nil(thread))
{
CTRL_MachineIDHandlePair pair = {thread->ctrl_machine_id, thread->ctrl_handle};
ctrl_machine_id_handle_pair_list_push(scratch.arena, &msg.freeze_state_threads, &pair);
}
}
msg.freeze_state_is_frozen = 1;
}
// rjf: push msg
-8
View File
@@ -1047,10 +1047,6 @@ struct D_State
U64 view_rule_spec_table_size;
D_ViewRuleSpec **view_rule_spec_table;
// rjf: freeze state
D_HandleList frozen_threads;
D_HandleNode *free_handle_node;
// rjf: control thread user -> ctrl driving state
Arena *ctrl_last_run_arena;
D_RunKind ctrl_last_run_kind;
@@ -1305,10 +1301,6 @@ internal D_Entity *d_entity_from_ctrl_handle(CTRL_MachineID machine_id, DMN_Hand
internal D_Entity *d_entity_from_ctrl_id(CTRL_MachineID machine_id, U32 id);
internal D_Entity *d_entity_from_name_and_kind(String8 string, D_EntityKind kind);
//- rjf: entity freezing state
internal void d_set_thread_freeze_state(D_Entity *thread, B32 frozen);
internal B32 d_entity_is_frozen(D_Entity *entity);
////////////////////////////////
//~ rjf: Command Stateful Functions
+2 -1
View File
@@ -2166,6 +2166,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, D_CmdList *cmds)
DF_Palette(DF_PaletteCode_ImplicitButton)
{
D_Entity *entity = d_entity_from_handle(ws->entity_ctx_menu_entity);
CTRL_Entity *entity_ctrl = ctrl_entity_from_machine_id_handle(d_state->ctrl_entity_store, entity->ctrl_machine_id, entity->ctrl_handle);
DF_IconKind entity_icon = df_entity_kind_icon_kind_table[entity->kind];
D_EntityKindFlags kind_flags = d_entity_kind_flags_table[entity->kind];
String8 display_name = d_display_string_from_entity(scratch.arena, entity);
@@ -2333,7 +2334,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, D_CmdList *cmds)
// rjf: freezing
if(kind_flags & D_EntityKindFlag_CanFreeze)
{
B32 is_frozen = d_entity_is_frozen(entity);
B32 is_frozen = ctrl_entity_tree_is_frozen(entity_ctrl);
ui_set_next_palette(df_palette_from_code(is_frozen ? DF_PaletteCode_NegativePopButton : DF_PaletteCode_PositivePopButton));
if(is_frozen && ui_clicked(df_icon_buttonf(DF_IconKind_Locked, 0, "Thaw###freeze_thaw")))
{
+2 -1
View File
@@ -5606,6 +5606,7 @@ DF_VIEW_UI_FUNCTION_DEF(scheduler)
idx += 1)
{
D_Entity *entity = items.v[idx].entity;
CTRL_Entity *entity_ctrl = ctrl_entity_from_machine_id_handle(d_state->ctrl_entity_store, entity->ctrl_machine_id, entity->ctrl_handle);
B32 row_is_selected = (cursor.y == (S64)(idx+1));
F32 depth = 0.f;
if(query.size == 0) switch(entity->kind)
@@ -5628,7 +5629,7 @@ DF_VIEW_UI_FUNCTION_DEF(scheduler)
UI_TableCellSized(ui_em(1.5f*depth, 1.f)) {}
UI_TableCellSized(ui_em(2.25f, 1.f)) UI_FocusHot((row_is_selected && cursor.x == 0) ? UI_FocusKind_On : UI_FocusKind_Off)
{
B32 frozen = d_entity_is_frozen(entity);
B32 frozen = ctrl_entity_tree_is_frozen(entity_ctrl);
UI_Palette *palette = ui_top_palette();
if(frozen)
{
+4 -2
View File
@@ -1047,6 +1047,7 @@ df_code_slice(DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
{
continue;
}
CTRL_Entity *thread_ctrl = ctrl_entity_from_machine_id_handle(d_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle);
U64 unwind_count = (thread == selected_thread) ? d_regs()->unwind_count : 0;
U64 thread_rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
@@ -1105,7 +1106,7 @@ df_code_slice(DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
u->thread_color = color;
u->alive_t = thread->alive_t;
u->is_selected = (thread == selected_thread);
u->is_frozen = d_entity_is_frozen(thread);
u->is_frozen = !!thread_ctrl->is_frozen;
u->do_lines = df_setting_val_from_code(DF_SettingCode_ThreadLines).s32;
u->do_glow = df_setting_val_from_code(DF_SettingCode_ThreadGlow).s32;
ui_box_equip_custom_draw(thread_box, df_thread_box_draw_extensions, u);
@@ -1205,6 +1206,7 @@ df_code_slice(DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
{
continue;
}
CTRL_Entity *thread_ctrl = ctrl_entity_from_machine_id_handle(d_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle);
U64 unwind_count = (thread == selected_thread) ? d_regs()->unwind_count : 0;
U64 thread_rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
@@ -1263,7 +1265,7 @@ df_code_slice(DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
u->thread_color = color;
u->alive_t = thread->alive_t;
u->is_selected = (thread == selected_thread);
u->is_frozen = d_entity_is_frozen(thread);
u->is_frozen = !!thread_ctrl->is_frozen;
ui_box_equip_custom_draw(thread_box, df_thread_box_draw_extensions, u);
// rjf: fill out progress t (progress into range of current line's