diff options
-rw-r--r-- | src/lib9/9proc.h | 5 | ||||
-rw-r--r-- | src/lib9/_p9proc.c | 110 | ||||
-rw-r--r-- | src/lib9/notify.c | 5 | ||||
-rw-r--r-- | src/lib9/priv.c | 2 | ||||
-rw-r--r-- | src/lib9/rendez.c | 2 | ||||
-rw-r--r-- | src/lib9/rfork.c | 7 |
6 files changed, 77 insertions, 54 deletions
diff --git a/src/lib9/9proc.h b/src/lib9/9proc.h index 713b9558..663d65b6 100644 --- a/src/lib9/9proc.h +++ b/src/lib9/9proc.h @@ -2,15 +2,12 @@ enum { NPRIV = 16, RENDHASH = 33, - PIDHASH = 33, }; typedef struct Uproc Uproc; struct Uproc { - Uproc *next; int pid; - int pipe[2]; int state; void *priv[NPRIV]; ulong rendval; @@ -19,5 +16,5 @@ struct Uproc p9jmp_buf notejb; }; -extern Uproc *_p9uproc(void); +extern Uproc *_p9uproc(int); extern void _p9uprocdie(void); diff --git a/src/lib9/_p9proc.c b/src/lib9/_p9proc.c index 6e4010cd..374fb089 100644 --- a/src/lib9/_p9proc.c +++ b/src/lib9/_p9proc.c @@ -1,73 +1,95 @@ +/* + * This needs to be callable from a signal handler, so it has been + * written to avoid locks. The only lock is the one used to acquire + * an entry in the table, and we make sure that acquiring is done + * when not in a handler. Lookup and delete do not need locks. + * It's a scan-forward hash table. To avoid breaking chains, + * T ((void*)-1) is used as a non-breaking nil. + */ + #include <u.h> #include <libc.h> #include "9proc.h" +enum { PIDHASH = 1021 }; + +#define T ((void*)-1) +static Uproc *alluproc[PIDHASH]; +static int allupid[PIDHASH]; static Lock uproclock; -static Uproc *phash[PIDHASH]; Uproc* -_p9uproc(void) +_p9uproc(int inhandler) { - /* for now, assume getpid is fast or cached */ - int pid; + int i, h, pid; Uproc *up; + /* for now, assume getpid is fast or cached */ pid = getpid(); -again: -if(0)print("find %d\n", pid); - lock(&uproclock); - for(up=phash[pid%PIDHASH]; up; up=up->next){ - if(up->pid == pid){ -if(0)print("found %d\n", pid); - unlock(&uproclock); + + /* + * this part - the lookup - needs to run without locks + * so that it can safely be called from within the notify handler. + * notify calls _p9uproc, and fork and rfork call _p9uproc + * in both parent and child, so if we're in a signal handler, + * we should find something in the table. + */ + h = pid%PIDHASH; + for(i=0; i<PIDHASH; i++){ + up = alluproc[h]; + if(up == nil) + break; + if(allupid[h] == pid) return up; - } + if(++h == PIDHASH) + h = 0; } - up = mallocz(sizeof(Uproc), 1); - if(up == nil){ -if(0)print("again %d\n", pid); - unlock(&uproclock); - sleep(1000); - goto again; - } + if(inhandler) + sysfatal("did not find uproc in signal handler"); -againpipe: - if(pipe(up->pipe) < 0){ -if(0)print("againpipe %d\n", pid); + /* need to allocate */ + while((up = mallocz(sizeof(Uproc), 1)) == nil) sleep(1000); - goto againpipe; - } - up->pid = pid; - up->next = phash[pid%PIDHASH]; - phash[pid%PIDHASH] = up; -if(0)print("link %d\n", pid); + up = mallocz(sizeof(Uproc), 1); + lock(&uproclock); + h = pid%PIDHASH; + for(i=0; i<PIDHASH; i++){ + if(alluproc[h]==T || alluproc[h]==nil){ + alluproc[h] = up; + allupid[h] = pid; + return up; + } + if(++h == PIDHASH) + h = 0; + } unlock(&uproclock); - return up; + + /* out of pids! */ + sysfatal("too many processes in uproc table"); + return nil; } void _p9uprocdie(void) { - Uproc **l, *up; - int pid; + Uproc *up; + int pid, i, h; pid = getpid(); -if(0)print("die %d\n", pid); - lock(&uproclock); - for(l=&phash[pid%33]; *l; l=&(*l)->next){ - if((*l)->pid == pid){ - up = *l; - *l = up->next; -if(0)print("died %d\n", pid); - unlock(&uproclock); - close(up->pipe[0]); - close(up->pipe[1]); + h = pid%PIDHASH; + for(i=0; i<PIDHASH; i++){ + up = alluproc[h]; + if(up == nil) + break; + if(up == T) + continue; + if(allupid[h] == pid){ + up = alluproc[h]; + alluproc[h] = T; free(up); - return; + allupid[h] = 0; } } -if(0)print("not started %d\n", pid); - unlock(&uproclock); } diff --git a/src/lib9/notify.c b/src/lib9/notify.c index 12edb0e4..79a5e621 100644 --- a/src/lib9/notify.c +++ b/src/lib9/notify.c @@ -49,7 +49,7 @@ notifysigf(int sig) char tmp[64]; Uproc *up; - up = _p9uproc(); + up = _p9uproc(1); v = p9setjmp(up->notejb); if(v == 0 && notifyf) (*notifyf)(nil, _p9sigstr(sig, tmp)); @@ -68,6 +68,7 @@ notify(void (*f)(void*, char*)) int i; struct sigaction sa; + _p9uproc(0); memset(&sa, 0, sizeof sa); if(f == 0) sa.sa_handler = SIG_DFL; @@ -90,7 +91,7 @@ noted(int v) { Uproc *up; - up = _p9uproc(); + up = _p9uproc(1); p9longjmp(up->notejb, v==NCONT ? 2 : 1); abort(); return 0; diff --git a/src/lib9/priv.c b/src/lib9/priv.c index 651c48c1..e64e9194 100644 --- a/src/lib9/priv.c +++ b/src/lib9/priv.c @@ -26,7 +26,7 @@ privmem(int i) { Uproc *up; - up = _p9uproc(); + up = _p9uproc(0); return &up->priv[i]; } diff --git a/src/lib9/rendez.c b/src/lib9/rendez.c index cf23a4e5..2b2c1a19 100644 --- a/src/lib9/rendez.c +++ b/src/lib9/rendez.c @@ -12,7 +12,7 @@ rendezvous(ulong tag, ulong val) ulong ret; Uproc *t, *self, **l; - self = _p9uproc(); + self = _p9uproc(0); lock(&rendlock); l = &rendhash[tag%RENDHASH]; for(t=*l; t; l=&t->rendhash, t=*l){ diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c index f3a21928..21dc17e8 100644 --- a/src/lib9/rfork.c +++ b/src/lib9/rfork.c @@ -1,5 +1,7 @@ -#define NOPLAN9DEFINES -#include <lib9.h> +#include <u.h> +#include <libc.h> +#include "9proc.h" +#undef rfork int p9rfork(int flags) @@ -14,6 +16,7 @@ p9rfork(int flags) return -1; } pid = fork(); + _p9uproc(0); if(pid != 0) return pid; } |