From 069b5cac49980f9ff2bb6eaa27a9a91ccfbc7b2f Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Thu, 3 Feb 2022 21:38:47 +0100 Subject: rewrite timedwait using a self-pipe OpenBSD doesn't implement sigtimedwait. --- rvnit.c | 95 ++++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/rvnit.c b/rvnit.c index 1babf0b..52ba9ec 100644 --- a/rvnit.c +++ b/rvnit.c @@ -58,6 +58,7 @@ pthread_t main_thread; pthread_t socket_thread; pthread_t logger_thread; +int selfpipe[2]; int selflogfd[2]; int newlogfd[2]; int globallogfd[2]; @@ -87,6 +88,49 @@ on_signal(int sig) case SIGCONT: /* do nothing, but interrupt the system call */ break; + case SIGCHLD: + write(selfpipe[1], "", 1); + break; + } +} + +pid_t +timedwait(int *wstatus, int secs) +{ + struct pollfd fds[1]; + fds[0].fd = selfpipe[0]; + fds[0].events = POLLIN; + + pid_t pid = waitpid(-1, wstatus, WNOHANG); + if (pid > 0) + return pid; + if (pid < 0 && errno == ECHILD) + return -1; + + while (1) { + int n = poll(fds, 1, secs < 0 ? -1 : secs * 1000); + + if (n < 0 && errno == EINTR) + return -1; + + if (n == 0) // timeout + return 0; + + if (n == 1) { + char trash; + read(selfpipe[0], &trash, 1); + + pid = waitpid(-1, wstatus, WNOHANG); + if (pid < 0) { + if (errno == ECHILD) + return -1; + if (errno == EINTR) + return -1; + } + + if (pid > 0) + return pid; + } } } @@ -520,42 +564,6 @@ reap(pid_t pid, int status) return -1; } -pid_t -timedwait(int *wstatus, int secs) -{ - struct timespec timeout = {secs, 0}; - sigset_t childset; - sigemptyset(&childset); - sigaddset(&childset, SIGCHLD); - - /* we block SIGCHLD here, so that we do not lose the signal - possibly sent between waitpid(-1) and sigtimedwait */ - sigprocmask(SIG_BLOCK, &childset, 0); - - pid_t pid; - - while (1) { - pid = waitpid(-1, wstatus, WNOHANG); - if (pid == 0) { // nothing to reap - if (sigtimedwait(&childset, 0, &timeout) == SIGCHLD) - continue; - if (errno == EAGAIN) // hit timeout, return pid = 0 - break; - } else if (pid < 0) { - if (errno == ECHILD) - break; - if (errno == EINTR) - continue; - } else { - break; // pid > 0 - } - } - - sigprocmask(SIG_UNBLOCK, &childset, 0); - - return pid; -} - /* -1: no error handler, 0: error handler successful, 1: error handler failed */ int on_error() @@ -706,6 +714,12 @@ main(int argc, char *argv[]) return 111; } + pipe(selfpipe); + fcntl(selfpipe[0], F_SETFL, O_NONBLOCK); + fcntl(selfpipe[1], F_SETFL, O_NONBLOCK); + fcntl(selfpipe[0], F_SETFD, FD_CLOEXEC); + fcntl(selfpipe[1], F_SETFD, FD_CLOEXEC); + pipe(selflogfd); fcntl(selflogfd[0], F_SETFL, O_NONBLOCK); fcntl(selflogfd[1], F_SETFL, O_NONBLOCK); @@ -770,6 +784,9 @@ main(int argc, char *argv[]) if (pid1) ioctl(0, TIOCNOTTY); + sigaction(SIGCHLD, &(struct sigaction){ + .sa_handler=on_signal, .sa_mask=allset, + .sa_flags=SA_NOCLDSTOP|SA_RESTART }, 0); sigaction(SIGINT, &(struct sigaction){ .sa_handler=on_signal, .sa_mask=allset }, 0); if (!real_pid1) { @@ -824,7 +841,7 @@ main(int argc, char *argv[]) while (oneshot) { int status = 0; - int pid = wait(&status); + int pid = timedwait(&status, -1); if (pid < 0 && errno == ECHILD) break; @@ -933,7 +950,7 @@ cont1: int status = 0; errno = 0; - int pid = wait(&status); + int pid = timedwait(&status, -1); if (pid < 0) { if (errno == ECHILD) @@ -1019,7 +1036,7 @@ fatal: while (oneshot) { int status = 0; - int pid = wait(&status); + int pid = timedwait(&status, -1); if (pid < 0 && errno == ECHILD) break; -- cgit 1.4.1