diff options
Diffstat (limited to 'wait.c')
| -rw-r--r-- | wait.c | 124 |
1 files changed, 124 insertions, 0 deletions
@@ -0,0 +1,124 @@ +#include <errno.h> +#include <setjmp.h> +#include "rc.h" +#include "jbwrap.h" + +bool forked = FALSE; + +static int rc_wait(int *); + +typedef struct Pid Pid; + +static struct Pid { + int pid, stat; + bool alive; + Pid *n; +} *plist = NULL; + +extern int rc_fork() { + Pid *new = enew(Pid); + int pid = fork(); + switch (pid) { + case -1: + uerror("fork"); + rc_error(NULL); + /* NOTREACHED */ + case 0: + forked = TRUE; + SIGCHK; + return 0; + default: + new->pid = pid; + new->alive = TRUE; + new->n = plist; + plist = new; + return pid; + } +} + +extern int rc_wait4(int 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) + if (r->pid == pid) + break; + 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; + 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; + if (prev == NULL) + plist = r->n; /* remove element from head of list */ + else + prev->n = r->n; + efree(r); + return pid; +} + +extern List *sgetapids() { + List *r; + Pid *p; + for (r = NULL, p = plist; p != NULL; p = p->n) { + List *q; + if (!p->alive) + continue; + q = nnew(List); + q->w = nprint("%d", p->pid); + q->m = NULL; + q->n = r; + r = q; + } + return r; +} + +extern void waitforall() { + int stat; + while (plist != NULL) { + int pid = rc_wait4(plist->pid, &stat, FALSE); + if (pid > 0) + setstatus(pid, stat); + else + set(FALSE); + SIGCHK; + } +} + +/* + 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 rc_wait(int *stat) { + int r; + interrupt_happened = FALSE; + if (!setjmp(slowbuf.j)) { + slow = TRUE; + if (!interrupt_happened) + r = wait(stat); + else + r = -1; + } else + r = -1; + slow = FALSE; + return r; +} |