#include <sys/epoll.h>
#include <stdio.h>
#include <sys/wait.h>
+#include <sys/signalfd.h>
#include <sys/resource.h>
#include "process.h"
static int parent_count;
static int job_request_fd[2];
static int job_get_permission_fd[2];
+static int signal_fd;
static int epoll_fd;
static unsigned int max_jobs;
static unsigned int job_count;
return parent_count;
}
-static void sigchild_handler(int signal)
+static int handle_signals(void)
{
- int status;
-
- waitpid(0, &status, 0);
-}
-
-static int setup_sigchild_handler(void)
-{
- struct sigaction sa;
+ struct signalfd_siginfo siginfo;
int ret;
- sa.sa_handler = sigchild_handler;
- sa.sa_flags = SA_NOCLDSTOP;
-
- ret = sigaction(SIGCHLD, &sa, NULL);
- if (ret)
- pr_err("Failed to setup SIGCHLD handler: %m\n");
-
- return ret;
-}
-
-static int cancel_sigchild_handler(void)
-{
- struct sigaction sa;
- int ret;
+ ret = read(signal_fd, &siginfo, sizeof(siginfo));
+ if (ret < sizeof(siginfo)) {
+ pr_err("Expected %zd from read, got %d: %m\n",
+ sizeof(siginfo), ret);
+ return -1;
+ }
- sa.sa_handler = SIG_DFL;
- sa.sa_flags = SA_NOCLDSTOP;
+ if (siginfo.ssi_signo != SIGCHLD) {
+ pr_err("Unexpected signal %d, ignoring\n", siginfo.ssi_signo);
+ return -1;
+ }
- ret = sigaction(SIGCHLD, &sa, NULL);
- if (ret)
- pr_err("Failed to cancel SIGCHLD handler: %m\n");
+ harvest_zombies(siginfo.ssi_pid);
- return ret;
+ return 0;
}
/*
struct epoll_event ev;
FILE *file;
int ret;
+ sigset_t sigmask;
char buf[256];
char match[8];
return -1;
}
- ret = setup_sigchild_handler();
- if (ret)
- return ret;
-
epoll_fd = epoll_create(1);
if (epoll_fd == -1) {
pr_err("Failed to epoll_create(): %m\n");
return -1;
}
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGCHLD);
+
+ /* Block SIGCHLD so that it becomes readable via signalfd */
+ ret = sigprocmask(SIG_BLOCK, &sigmask, NULL);
+ if (ret < 0) {
+ pr_err("Failed to sigprocmask: %m\n");
+ }
+
+ signal_fd = signalfd(-1, &sigmask, SFD_CLOEXEC);
+ if (signal_fd < 0) {
+ pr_err("Failed to create signal_fd: %m\n");
+ return -1;
+ }
+
+ ev.data.fd = signal_fd;
+ ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, signal_fd, &ev);
+ if (ret) {
+ pr_err("Failed to add epoll_fd: %m\n");
+ return -1;
+ }
+
+
if (max_jobs_requested > 0) {
max_jobs = max_jobs_requested;
goto no_count_cpus;
if (event.data.fd == job_request_fd[0])
handle_job_request();
+ else if (event.data.fd == signal_fd)
+ handle_signals();
else
pr_err("Unknown fd: %d\n", event.data.fd);
return child;
}
- /*
- * Child processes may want to use waitpid() for synchronizing
- * with their sub-childs. Disable the signal handler by
- * default
- */
- cancel_sigchild_handler();
-
/*
* Also do not notify the master parent the death of this
* child. Only childs that have been created with