mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-01 07:15:32 -04:00
reaper: new module, uses a signalfd to wait() on child processes
Use a signalfd to listen for SIGCHLD signals. When we receive a SIGCHLD over the signalfd, reap all dead children by looping over all registered child PIDs and call waitpid(WNOHANG) on them.
This commit is contained in:
parent
5600cc68c0
commit
f49742ebba
4 changed files with 161 additions and 0 deletions
6
main.c
6
main.c
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fdm.h"
|
#include "fdm.h"
|
||||||
|
#include "reaper.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
|
|
@ -353,6 +354,7 @@ main(int argc, char *const *argv)
|
||||||
conf.hold_at_exit = hold;
|
conf.hold_at_exit = hold;
|
||||||
|
|
||||||
struct fdm *fdm = NULL;
|
struct fdm *fdm = NULL;
|
||||||
|
struct reaper *reaper = NULL;
|
||||||
struct wayland *wayl = NULL;
|
struct wayland *wayl = NULL;
|
||||||
struct renderer *renderer = NULL;
|
struct renderer *renderer = NULL;
|
||||||
struct terminal *term = NULL;
|
struct terminal *term = NULL;
|
||||||
|
|
@ -378,6 +380,9 @@ main(int argc, char *const *argv)
|
||||||
if ((fdm = fdm_init()) == NULL)
|
if ((fdm = fdm_init()) == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if ((reaper = reaper_init(fdm)) == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if ((wayl = wayl_init(&conf, fdm)) == NULL)
|
if ((wayl = wayl_init(&conf, fdm)) == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -429,6 +434,7 @@ out:
|
||||||
shm_fini();
|
shm_fini();
|
||||||
render_destroy(renderer);
|
render_destroy(renderer);
|
||||||
wayl_destroy(wayl);
|
wayl_destroy(wayl);
|
||||||
|
reaper_destroy(reaper);
|
||||||
fdm_destroy(fdm);
|
fdm_destroy(fdm);
|
||||||
|
|
||||||
config_free(conf);
|
config_free(conf);
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ executable(
|
||||||
'misc.c', 'misc.h',
|
'misc.c', 'misc.h',
|
||||||
'osc.c', 'osc.h',
|
'osc.c', 'osc.h',
|
||||||
'quirks.c', 'quirks.h',
|
'quirks.c', 'quirks.h',
|
||||||
|
'reaper.c', 'reaper.h',
|
||||||
'render.c', 'render.h',
|
'render.c', 'render.h',
|
||||||
'search.c', 'search.h',
|
'search.c', 'search.h',
|
||||||
'selection.c', 'selection.h',
|
'selection.c', 'selection.h',
|
||||||
|
|
|
||||||
142
reaper.c
Normal file
142
reaper.c
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
#include "reaper.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/signalfd.h>
|
||||||
|
|
||||||
|
#define LOG_MODULE "reaper"
|
||||||
|
#define LOG_ENABLE_DBG 1
|
||||||
|
#include "log.h"
|
||||||
|
#include "tllist.h"
|
||||||
|
|
||||||
|
struct reaper {
|
||||||
|
struct fdm *fdm;
|
||||||
|
int fd;
|
||||||
|
tll(pid_t) children;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool fdm_reap(struct fdm *fdm, int fd, int events, void *data);
|
||||||
|
|
||||||
|
struct reaper *
|
||||||
|
reaper_init(struct fdm *fdm)
|
||||||
|
{
|
||||||
|
sigset_t mask;
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGCHLD);
|
||||||
|
|
||||||
|
/* Block normal signal handling - we're using a signalfd instead */
|
||||||
|
if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
|
||||||
|
LOG_ERRNO("failed to block SIGCHLD");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_ERRNO("failed to create signal FD");
|
||||||
|
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct reaper *reaper = malloc(sizeof(*reaper));
|
||||||
|
*reaper = (struct reaper){
|
||||||
|
.fdm = fdm,
|
||||||
|
.fd = fd,
|
||||||
|
.children = tll_init(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!fdm_add(fdm, fd, EPOLLIN, &fdm_reap, reaper)){
|
||||||
|
LOG_ERR("failed to register with the FDM");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reaper;
|
||||||
|
|
||||||
|
err:
|
||||||
|
tll_free(reaper->children);
|
||||||
|
close(fd);
|
||||||
|
free(reaper);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
reaper_destroy(struct reaper *reaper)
|
||||||
|
{
|
||||||
|
if (reaper == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fdm_del(reaper->fdm, reaper->fd);
|
||||||
|
tll_free(reaper->children);
|
||||||
|
free(reaper);
|
||||||
|
|
||||||
|
sigset_t mask;
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGCHLD);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
reaper_add(struct reaper *reaper, pid_t pid)
|
||||||
|
{
|
||||||
|
LOG_DBG("adding pid=%d", pid);
|
||||||
|
tll_push_back(reaper->children, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
fdm_reap(struct fdm *fdm, int fd, int events, void *data)
|
||||||
|
{
|
||||||
|
struct reaper *reaper = data;
|
||||||
|
|
||||||
|
bool pollin = events & EPOLLIN;
|
||||||
|
bool hup = events & EPOLLHUP;
|
||||||
|
|
||||||
|
if (hup && !pollin)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
assert(pollin);
|
||||||
|
|
||||||
|
struct signalfd_siginfo info;
|
||||||
|
ssize_t amount = read(reaper->fd, &info, sizeof(info));
|
||||||
|
|
||||||
|
if (amount < 0) {
|
||||||
|
LOG_ERRNO("failed to read");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert((size_t)amount >= sizeof(info));
|
||||||
|
|
||||||
|
if (info.ssi_signo != SIGCHLD) {
|
||||||
|
LOG_WARN("got non-SIGCHLD signal: %d", info.ssi_signo);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tll_foreach(reaper->children, it) {
|
||||||
|
/* Don't use wait() since we don't want to accidentaly reap
|
||||||
|
* the PTS slave */
|
||||||
|
|
||||||
|
pid_t pid = it->item;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
int res = waitpid(pid, &result, WNOHANG);
|
||||||
|
|
||||||
|
if (res <= 0) {
|
||||||
|
if (res < 0)
|
||||||
|
LOG_ERRNO("waitpid failed for pid=%d", pid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (WIFEXITED(result))
|
||||||
|
LOG_DBG("pid=%d: exited with status=%d", pid, WEXITSTATUS(result));
|
||||||
|
else if (WIFSIGNALED(result))
|
||||||
|
LOG_DBG("pid=%d: killed by signal=%d", pid, WTERMSIG(result));
|
||||||
|
else
|
||||||
|
LOG_DBG("pid=%d: died of unknown resason", pid);
|
||||||
|
tll_remove(reaper->children, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
12
reaper.h
Normal file
12
reaper.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "fdm.h"
|
||||||
|
|
||||||
|
struct reaper;
|
||||||
|
|
||||||
|
struct reaper *reaper_init(struct fdm *fdm);
|
||||||
|
void reaper_destroy(struct reaper *reaper);
|
||||||
|
|
||||||
|
void reaper_add(struct reaper *reaper, pid_t pid);
|
||||||
Loading…
Add table
Add a link
Reference in a new issue