From 41906cf7dbd75bc461548fbefce70356b0413068 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 31 Jan 2019 20:43:50 +0530 Subject: [PATCH] Infrastructure to monitor child processes for death --- kitty/child-monitor.c | 58 +++++++++++++++++++++++++++++++++++++++++++ kitty/data-types.h | 5 ++++ kitty/timers.c | 5 +--- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 5a9a59af1..bb380d3ad 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -80,6 +80,17 @@ static uint8_t drain_buf[1024]; static int signal_fds[2], wakeup_fds[2]; +typedef struct { + pid_t pid; + int status; +} ReapedPID; + +static pid_t monitored_pids[256] = {0}; +static size_t monitored_pids_count = 0; +static ReapedPID reaped_pids[arraysz(monitored_pids)] = {{0}}; +static size_t reaped_pids_count = 0; + + // Main thread functions {{{ @@ -699,6 +710,35 @@ free_twd(ThreadWriteData *x) { free(x); } +static PyObject* +monitor_pid(PyObject *self UNUSED, PyObject *args) { + long pid; + bool ok = true; + if (!PyArg_ParseTuple(args, "l", &pid)) return NULL; + children_mutex(lock); + if (monitored_pids_count >= arraysz(monitored_pids)) { + PyErr_SetString(PyExc_RuntimeError, "Too many monitored pids"); + ok = false; + } else { + monitored_pids[monitored_pids_count++] = pid; + } + children_mutex(unlock); + if (!ok) return NULL; + Py_RETURN_NONE; +} + +static inline void +report_reaped_pids() { + children_mutex(lock); + if (reaped_pids_count) { + for (size_t i = 0; i < reaped_pids_count; i++) { + call_boss(on_monitored_pid_death, "ii", (int)reaped_pids[i].pid, reaped_pids[i].status); + } + reaped_pids_count = 0; + } + children_mutex(unlock); +} + static void* thread_write(void *x) { ThreadWriteData *data = (ThreadWriteData*)x; @@ -864,6 +904,7 @@ main_loop(ChildMonitor *self, PyObject *a UNUSED) { request_application_quit(); #endif } + report_reaped_pids(); has_open_windows = process_pending_closes(self); } remove_all_timers(&main_event_loop); @@ -1015,6 +1056,21 @@ mark_child_for_removal(ChildMonitor *self, pid_t pid) { children_mutex(unlock); } +static inline void +mark_monitored_pids(pid_t pid, int status) { + children_mutex(lock); + for (ssize_t i = monitored_pids_count - 1; i >= 0; i--) { + if (pid == monitored_pids[i]) { + if (reaped_pids_count < arraysz(reaped_pids)) { + reaped_pids[reaped_pids_count].status = status; + reaped_pids[reaped_pids_count++].pid = pid; + } + remove_from_array(monitored_pids, (size_t)i, monitored_pids_count); + } + } + children_mutex(unlock); +} + static inline void reap_children(ChildMonitor *self, bool enable_close_on_child_death) { int status; @@ -1026,6 +1082,7 @@ reap_children(ChildMonitor *self, bool enable_close_on_child_death) { if (errno != EINTR) break; } else if (pid > 0) { if (enable_close_on_child_death) mark_child_for_removal(self, pid); + mark_monitored_pids(pid, status); } else break; } } @@ -1457,6 +1514,7 @@ static PyMethodDef module_methods[] = { {"add_timer", (PyCFunction)add_python_timer, METH_VARARGS, ""}, {"remove_timer", (PyCFunction)remove_python_timer, METH_VARARGS, ""}, {"change_timer_interval", (PyCFunction)change_python_timer_interval, METH_VARARGS, ""}, + METHODB(monitor_pid, METH_VARARGS), {"set_iutf8", (PyCFunction)pyset_iutf8, METH_VARARGS, ""}, {NULL} /* Sentinel */ }; diff --git a/kitty/data-types.h b/kitty/data-types.h index 27697f6ec..d76dbc44a 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -257,6 +257,11 @@ typedef struct {FONTS_DATA_HEAD} *FONTS_DATA_HANDLE; (base)->capacity = _newcap; \ } +#define remove_from_array(array, i, count) { \ + count--; \ + if (i < count) { \ + memmove(array + i, array + i + 1, sizeof(array[0]) * (count - 1)); \ + }} // Global functions const char* base64_decode(const uint32_t *src, size_t src_sz, uint8_t *dest, size_t dest_capacity, size_t *dest_sz); diff --git a/kitty/timers.c b/kitty/timers.c index 16f988b1a..54421c092 100644 --- a/kitty/timers.c +++ b/kitty/timers.c @@ -45,10 +45,7 @@ remove_timer(EventLoopData *eld, id_type timer_id) { for (nfds_t i = 0; i < eld->timers_count; i++) { if (eld->timers[i].id == timer_id) { if (eld->timers[i].cleanup) eld->timers[i].cleanup(timer_id, eld->timers[i].callback_data); - eld->timers_count--; - if (i < eld->timers_count) { - memmove(eld->timers + i, eld->timers + i + 1, sizeof(eld->timers[0]) * (eld->timers_count - i)); - } + remove_from_array(eld->timers, i, eld->timers_count); update_timers(eld); break; }