diff options
author | rsc <devnull@localhost> | 2004-09-21 01:11:28 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-09-21 01:11:28 +0000 |
commit | c6687d4591964cb13df87f55ec4770e778a4a55c (patch) | |
tree | ee669a419904e929ae8ae54fd04c2bb41b5a57b1 /src/lib9/_p9proc-getpid.c | |
parent | 3d5e34e146b5ba5c973230abb624ce9126024569 (diff) | |
download | plan9port-c6687d4591964cb13df87f55ec4770e778a4a55c.tar.gz plan9port-c6687d4591964cb13df87f55ec4770e778a4a55c.tar.bz2 plan9port-c6687d4591964cb13df87f55ec4770e778a4a55c.zip |
Continue the pthreads torture.
Diffstat (limited to 'src/lib9/_p9proc-getpid.c')
-rw-r--r-- | src/lib9/_p9proc-getpid.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/lib9/_p9proc-getpid.c b/src/lib9/_p9proc-getpid.c new file mode 100644 index 00000000..9543bf24 --- /dev/null +++ b/src/lib9/_p9proc-getpid.c @@ -0,0 +1,113 @@ +/* + * 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; + +void +_clearuproc(void) +{ + int i; + + /* called right after fork - no locking needed */ + for(i=0; i<PIDHASH; i++) + if(alluproc[i] != T && alluproc[i] != 0) + free(alluproc[i]); + memset(alluproc, 0, sizeof alluproc); + memset(allupid, 0, sizeof allupid); +} + +Uproc* +_p9uproc(int inhandler) +{ + int i, h, pid; + Uproc *up; + + /* for now, assume getpid is fast or cached */ + pid = getpid(); + + /* + * 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; + } + + if(inhandler){ + fprint(2, "%s: did not find uproc for pid %d in signal handler\n", argv0, pid); + abort(); + } + + /* need to allocate */ + while((up = mallocz(sizeof(Uproc), 1)) == nil) + sleep(1000); + + /* fprint(2, "alloc uproc for pid %d\n", pid); */ + up->pid = pid; + lock(&uproclock); + h = pid%PIDHASH; + for(i=0; i<PIDHASH; i++){ + if(alluproc[h]==T || alluproc[h]==nil){ + alluproc[h] = up; + allupid[h] = pid; + unlock(&uproclock); + return up; + } + if(++h == PIDHASH) + h = 0; + } + unlock(&uproclock); + + /* out of pids! */ + sysfatal("too many processes in uproc table"); + return nil; +} + +void +_p9uprocdie(void) +{ + Uproc *up; + int pid, i, h; + + pid = getpid(); + /* fprint(2, "reap uproc for pid %d\n", pid); */ + 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); + allupid[h] = 0; + } + } +} |