rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

commit b12d41f95452f06360d4879bc466469686d167a8
parent 61f3dc4ae75009ba3e8638a7fb7767cdb92c598c
Author: tgoodwin <tgoodwin>
Date:   Thu,  5 Feb 1998 14:51:09 +0000

attempt to fix wait() race

Diffstat:
Mwait.c | 68+++++++++++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 45 insertions(+), 23 deletions(-)

diff --git a/wait.c b/wait.c @@ -2,6 +2,7 @@ #include <errno.h> #include <setjmp.h> +#include <signal.h> #include <sys/wait.h> #include "jbwrap.h" @@ -43,34 +44,42 @@ extern pid_t rc_fork() { extern pid_t rc_wait4(pid_t pid, int *stat, bool nointr) { Pid *r, *prev; - int ret; - /* first look for a child which may already have exited */ -again: for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n) + + /* Find the child on the list. */ + for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n) if (r->pid == pid) break; + + /* Uh-oh, not there. */ if (r == NULL) { errno = ECHILD; /* no children */ uerror("wait"); *stat = 0x100; /* exit(1) */ return -1; } - if (r->alive) { - while (pid != (ret = rc_wait(stat))) { - Pid *q; - if (ret < 0) { - if (nointr) - goto again; + + /* If it's still alive, wait() for it. */ + while (r->alive) { + int ret; + Pid *q; + + ret = rc_wait(stat); + + if (ret < 0) { + if (errno == ECHILD) + panic("lost child"); + if (!nointr) return ret; - } - for (q = plist; q != NULL; q = q->n) - if (q->pid == ret) { - q->alive = FALSE; - q->stat = *stat; - break; - } } - } else - *stat = r->stat; + + for (q = plist; q != NULL; q = q->n) + if (q->pid == ret) { + q->alive = FALSE; + q->stat = *stat; + break; + } + } + *stat = r->stat; if (prev == NULL) plist = r->n; /* remove element from head of list */ else @@ -107,23 +116,36 @@ extern void waitforall() { } } +static int gotint; +void gotint_handler(int s) { + gotint = 1; + signal(s, gotint_handler); +} + /* rc_wait: a wait() wrapper that interfaces wait() w/rc signals. Note that the signal queue is not checked in this fn; someone may want to resume the wait() without delivering any signals. */ +static int r; static pid_t rc_wait(int *stat) { - int r; + void (*old)(int); + interrupt_happened = FALSE; + r = -1; + + gotint = 0; + old = signal(SIGINT, gotint_handler); if (!setjmp(slowbuf.j)) { slow = TRUE; if (!interrupt_happened) r = wait(stat); - else - r = -1; - } else - r = -1; + } slow = FALSE; + signal(SIGINT, old); + if (gotint && old != SIG_DFL && old != SIG_IGN) + (*old)(SIGINT); + return r; }