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.
This commit is contained in:
Kovid Goyal 2022-06-04 14:09:23 +05:30
parent ce3322bf91
commit bf4dc6365a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 57 additions and 14 deletions

View File

@ -23,6 +23,10 @@
#include <signal.h>
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;
}

View File

@ -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

View File

@ -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

View File

@ -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);