From bf4dc6365a63d6ba38393cc1ec7b09aa8001eaaf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 4 Jun 2022 14:09:23 +0530 Subject: [PATCH] Add support for sigqueue() and also handle SIGUSR2 I anticipate using sigqueue() for simpler handling of SIGCHLD notifications from the prewram process to the its parent. --- kitty/child-monitor.c | 33 ++++++++++++++++++++++++++++++--- kitty/fast_data_types.pyi | 4 ++++ kitty/loop-utils.c | 32 ++++++++++++++++++++++---------- kitty/loop-utils.h | 2 +- 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 0318e8d5f..f56367c7c 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -23,6 +23,10 @@ #include extern PyTypeObject Screen_Type; +#if defined(__APPLE__) || defined(__OpenBSD__) +#define NO_SIGQUEUE 1 +#endif + #ifdef DEBUG_EVENT_LOOP #define EVDBG(...) log_event(__VA_ARGS__) #else @@ -801,11 +805,25 @@ free_twd(ThreadWriteData *x) { free(x); } +static PyObject* +sig_queue(PyObject *self UNUSED, PyObject *args) { + int pid, signal, value; + if (!PyArg_ParseTuple(args, "iii", &pid, &signal, &value)) return NULL; +#ifdef NO_SIGQUEUE + if (kill(pid, signal) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } +#else + union sigval v; + v.sival_int = value; + if (sigqueue(pid, signal, v) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } +#endif + Py_RETURN_NONE; +} + static PyObject* monitor_pid(PyObject *self UNUSED, PyObject *args) { - long pid; + int pid; bool ok = true; - if (!PyArg_ParseTuple(args, "l", &pid)) return NULL; + if (!PyArg_ParseTuple(args, "i", &pid)) return NULL; children_mutex(lock); if (monitored_pids_count >= arraysz(monitored_pids)) { PyErr_SetString(PyExc_RuntimeError, "Too many monitored pids"); @@ -1224,7 +1242,7 @@ read_bytes(int fd, Screen *screen) { typedef struct { bool kill_signal, child_died, reload_config; } SignalSet; static void -handle_signal(int signum, void *data) { +handle_signal(int32_t signum, int32_t sigval, void *data) { SignalSet *ss = data; switch(signum) { case SIGINT: @@ -1237,6 +1255,9 @@ handle_signal(int signum, void *data) { case SIGUSR1: ss->reload_config = true; break; + case SIGUSR2: + printf("Received SIGUSR2: %d\n", sigval); + break; default: break; } @@ -1739,6 +1760,7 @@ static PyMethodDef module_methods[] = { METHODB(monitor_pid, METH_VARARGS), METHODB(send_data_to_peer, METH_VARARGS), METHODB(cocoa_set_menubar_title, METH_VARARGS), + {"sigqueue", (PyCFunction)sig_queue, METH_VARARGS, ""}, {NULL} /* Sentinel */ }; @@ -1748,6 +1770,11 @@ init_child_monitor(PyObject *module) { if (PyModule_AddObject(module, "ChildMonitor", (PyObject *)&ChildMonitor_Type) != 0) return false; Py_INCREF(&ChildMonitor_Type); if (PyModule_AddFunctions(module, module_methods) != 0) return false; +#ifdef NO_SIGQUEUE + PyModule_AddIntConstant(module, "has_sigqueue", 0); +#else + PyModule_AddIntConstant(module, "has_sigqueue", 1); +#endif return true; } diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 894e72112..c1126dc08 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1375,3 +1375,7 @@ def shm_open(name: str, flags: int, mode: int = 0o600) -> int: def shm_unlink(name: str) -> None: pass + + +def sigqueue(pid: int, signal: int, value: int) -> None: + pass diff --git a/kitty/loop-utils.c b/kitty/loop-utils.c index 6b2aff67d..fd9fabdf1 100644 --- a/kitty/loop-utils.c +++ b/kitty/loop-utils.c @@ -29,11 +29,14 @@ init_loop_data(LoopData *ld) { static int signal_write_fd = -1; static void -handle_signal(int sig_num) { +handle_signal(int sig_num, siginfo_t *si, void *ucontext UNUSED) { int save_err = errno; - unsigned char byte = (unsigned char)sig_num; - while(signal_write_fd != -1) { - ssize_t ret = write(signal_write_fd, &byte, 1); + char buf[8]; + int32_t sigval = si->si_value.sival_int, signum = sig_num; + memcpy(buf, &signum, 4); + memcpy(buf + 4, &sigval, 4); + while (signal_write_fd != -1) { + ssize_t ret = write(signal_write_fd, buf, 8); if (ret < 0 && errno == EINTR) continue; break; } @@ -45,7 +48,7 @@ handle_signal(int sig_num) { #define SIGNAL_SET \ sigset_t signals = {0}; \ sigemptyset(&signals); \ - sigaddset(&signals, SIGINT); sigaddset(&signals, SIGTERM); sigaddset(&signals, SIGCHLD); sigaddset(&signals, SIGUSR1); \ + sigaddset(&signals, SIGINT); sigaddset(&signals, SIGTERM); sigaddset(&signals, SIGCHLD); sigaddset(&signals, SIGUSR1); sigaddset(&signals, SIGUSR2); \ void free_loop_data(LoopData *ld) { @@ -68,6 +71,8 @@ free_loop_data(LoopData *ld) { signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGCHLD, SIG_DFL); + signal(SIGUSR1, SIG_DFL); + signal(SIGUSR2, SIG_DFL); } #ifdef HAS_EVENT_FD safe_close(ld->wakeup_read_fd, __FILE__, __LINE__); @@ -104,9 +109,9 @@ install_signal_handlers(LoopData *ld) { #else if (!self_pipe(ld->signal_fds, true)) return false; signal_write_fd = ld->signal_fds[1]; - struct sigaction act = {.sa_handler=handle_signal}; + struct sigaction act = {.sa_sigaction=handle_signal, .sa_flags=SA_SIGINFO}; #define SA(which) { if (sigaction(which, &act, NULL) != 0) return false; if (siginterrupt(which, false) != 0) return false; } - SA(SIGINT); SA(SIGTERM); SA(SIGCHLD); SA(SIGUSR1); + SA(SIGINT); SA(SIGTERM); SA(SIGCHLD); SA(SIGUSR1); SA(SIGUSR2); #undef SA ld->signal_read_fd = ld->signal_fds[0]; #endif @@ -132,18 +137,25 @@ read_signals(int fd, handle_signal_func callback, void *data) { log_error("Incomplete signal read from signalfd"); break; } - for (size_t i = 0; i < num_signals; i++) callback(fdsi[i].ssi_signo, data); + for (size_t i = 0; i < num_signals; i++) callback(fdsi[i].ssi_signo, fdsi[i].ssi_int, data); } #else static char buf[256]; + static size_t buf_pos = 0; while(true) { - ssize_t len = read(fd, buf, sizeof(buf)); + ssize_t len = read(fd, buf + buf_pos, sizeof(buf) - buf_pos); if (len < 0) { if (errno == EINTR) continue; if (errno != EIO && errno != EAGAIN) log_error("Call to read() from read_signals() failed with error: %s", strerror(errno)); break; } - for (ssize_t i = 0; i < len; i++) callback(buf[i], data); + buf_pos += len; + while (buf_pos >= 8) { + int32_t *sdata = (int32_t*)buf; + callback(sdata[0], sdata[1], data); + memmove(buf, buf + 8, 8); + buf_pos -= 8; + } if (len == 0) break; } #endif diff --git a/kitty/loop-utils.h b/kitty/loop-utils.h index 60f2a852e..dcbfdbd68 100644 --- a/kitty/loop-utils.h +++ b/kitty/loop-utils.h @@ -37,7 +37,7 @@ typedef struct { int wakeup_read_fd; int signal_read_fd; } LoopData; -typedef void(*handle_signal_func)(int, void *data); +typedef void(*handle_signal_func)(int32_t, int32_t, void *data); bool init_loop_data(LoopData *ld); void free_loop_data(LoopData *ld);