aboutsummaryrefslogtreecommitdiff
path: root/src/lib9/_p9proc-getpid.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-09-21 01:11:28 +0000
committerrsc <devnull@localhost>2004-09-21 01:11:28 +0000
commitc6687d4591964cb13df87f55ec4770e778a4a55c (patch)
treeee669a419904e929ae8ae54fd04c2bb41b5a57b1 /src/lib9/_p9proc-getpid.c
parent3d5e34e146b5ba5c973230abb624ce9126024569 (diff)
downloadplan9port-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.c113
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;
+ }
+ }
+}