diff --git a/programs/include/gui/terminal.hpp b/programs/include/gui/terminal.hpp index 8b6c52e..0064cc5 100644 --- a/programs/include/gui/terminal.hpp +++ b/programs/include/gui/terminal.hpp @@ -20,6 +20,7 @@ struct TermCell { }; static constexpr int TERM_MAX_SCROLLBACK = 500; +static constexpr int TERM_MAX_READS_PER_POLL = 8; struct TerminalState { TermCell* cells; @@ -716,8 +717,8 @@ static inline void terminal_handle_key(TerminalState* t, const Montauk::KeyEvent static inline bool terminal_poll(TerminalState* t) { if (t->child_pid <= 0) return false; char buf[4096]; - // Drain all available data so large output renders in one frame - for (;;) { + // Drain a bounded amount per frame so window close/input events stay responsive. + for (int reads = 0; reads < TERM_MAX_READS_PER_POLL; reads++) { int n = montauk::childio_read(t->child_pid, buf, sizeof(buf)); if (n > 0) { terminal_feed(t, buf, n); diff --git a/programs/src/procmgr/main.cpp b/programs/src/procmgr/main.cpp index b35162c..a1790b0 100644 --- a/programs/src/procmgr/main.cpp +++ b/programs/src/procmgr/main.cpp @@ -233,11 +233,14 @@ static int window_visible_rows() { return mtk::table_visible_rows(window_table_layout()); } +static bool process_state_alive(uint8_t state) { + return state == 1 || state == 2 || state == 3; +} + static int live_process_count() { int count = 0; for (int i = 0; i < g_pm.proc_count; i++) { - uint8_t state = g_pm.procs[i].state; - if (state == 1 || state == 2 || state == 3) + if (process_state_alive(g_pm.procs[i].state)) count++; } return count; @@ -246,13 +249,24 @@ static int live_process_count() { static uint64_t total_process_heap() { uint64_t total = 0; for (int i = 0; i < g_pm.proc_count; i++) { - uint8_t state = g_pm.procs[i].state; - if (state == 1 || state == 2 || state == 3) + if (process_state_alive(g_pm.procs[i].state)) total += g_pm.procs[i].heapUsed; } return total; } +static void collect_descendant_pids(int parent_pid, int* pids, int* count, int max_count) { + for (int i = 0; i < g_pm.proc_count; i++) { + if (!process_state_alive(g_pm.procs[i].state)) continue; + if (g_pm.procs[i].parentPid != parent_pid) continue; + + int child_pid = g_pm.procs[i].pid; + collect_descendant_pids(child_pid, pids, count, max_count); + if (*count < max_count) + pids[(*count)++] = child_pid; + } +} + static int find_prev_cpu_snapshot(int pid) { for (int i = 0; i < g_pm.prev_cpu_count; i++) { if (g_pm.prev_cpu[i].pid == pid) @@ -390,7 +404,15 @@ static void kill_selected() { if (!can_kill_selected()) return; - montauk::kill(g_pm.procs[g_pm.selected].pid); + int root_pid = g_pm.procs[g_pm.selected].pid; + int descendants[PM_MAX_PROCS]; + int descendant_count = 0; + collect_descendant_pids(root_pid, descendants, &descendant_count, PM_MAX_PROCS); + + for (int i = 0; i < descendant_count; i++) + montauk::kill(descendants[i]); + + montauk::kill(root_pid); refresh_state(true); } diff --git a/programs/src/shell/main.cpp b/programs/src/shell/main.cpp index b1b8b55..6f68c8f 100644 --- a/programs/src/shell/main.cpp +++ b/programs/src/shell/main.cpp @@ -352,6 +352,25 @@ static constexpr uint8_t SC_DOWN = 0x50; static constexpr uint8_t SC_LEFT = 0x4B; static constexpr uint8_t SC_RIGHT = 0x4D; +static bool empty_key_event(const Montauk::KeyEvent& ev) { + return ev.scancode == 0 && ev.ascii == 0 && !ev.pressed && + !ev.shift && !ev.ctrl && !ev.alt; +} + +static void wait_key_event(Montauk::KeyEvent* out) { + if (!out) return; + + for (;;) { + montauk::getkey(out); + if (!empty_key_event(*out)) + return; + + uint64_t serial = montauk::input_wait(0, 0); + if (!montauk::is_key_available()) + montauk::input_wait(serial, ~0ULL); + } +} + // ---- Entry point ---- extern "C" void _start() { @@ -380,13 +399,8 @@ extern "C" void _start() { prompt(); while (true) { - if (!montauk::is_key_available()) { - montauk::yield(); - continue; - } - Montauk::KeyEvent ev; - montauk::getkey(&ev); + wait_key_event(&ev); if (!ev.pressed) continue; diff --git a/programs/src/terminal/main.cpp b/programs/src/terminal/main.cpp index 6877c86..38b4b5c 100644 --- a/programs/src/terminal/main.cpp +++ b/programs/src/terminal/main.cpp @@ -45,6 +45,9 @@ static bool g_should_exit = false; static bool g_force_redraw = true; static int g_last_win_w = 0; static int g_last_win_h = 0; +static Montauk::ProcInfo g_kill_procs[256]; +static int g_kill_pids[256]; +static int g_kill_pid_count = 0; static bool left_pressed(const Montauk::WinEvent& ev) { return (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1); @@ -54,9 +57,40 @@ static void term_request_redraw() { g_force_redraw = true; } +static bool term_proc_alive(uint8_t state) { + return state == 1 || state == 2 || state == 3; +} + +static void term_collect_child_pids(int parent_pid, int proc_count) { + for (int i = 0; i < proc_count; i++) { + if (!term_proc_alive(g_kill_procs[i].state)) continue; + if (g_kill_procs[i].parentPid != parent_pid) continue; + + int child_pid = g_kill_procs[i].pid; + term_collect_child_pids(child_pid, proc_count); + if (g_kill_pid_count < (int)(sizeof(g_kill_pids) / sizeof(g_kill_pids[0]))) + g_kill_pids[g_kill_pid_count++] = child_pid; + } +} + +static void term_kill_process_tree(int root_pid) { + if (root_pid <= 0) return; + + g_kill_pid_count = 0; + int proc_count = montauk::proclist(g_kill_procs, + (int)(sizeof(g_kill_procs) / sizeof(g_kill_procs[0]))); + if (proc_count > 0) + term_collect_child_pids(root_pid, proc_count); + + for (int i = 0; i < g_kill_pid_count; i++) + montauk::kill(g_kill_pids[i]); + + montauk::kill(root_pid); +} + static void term_free_tab(TerminalState* ts) { if (!ts) return; - if (ts->child_pid > 0) montauk::kill(ts->child_pid); + if (ts->child_pid > 0) term_kill_process_tree(ts->child_pid); if (ts->cells) montauk::free(ts->cells); if (ts->alt_cells) montauk::free(ts->alt_cells); montauk::mfree(ts); @@ -367,9 +401,7 @@ extern "C" void _start() { g_win.present(); while (!g_should_exit) { - bool redraw = term_poll_tabs(); - if (g_should_exit) break; - + bool redraw = false; Montauk::WinEvent ev; bool quit = false; int r = 0; @@ -400,6 +432,9 @@ extern "C" void _start() { if (r < 0 || quit) break; + redraw |= term_poll_tabs(); + if (g_should_exit) break; + if (redraw && term_render()) g_win.present();