Continue the pthreads torture.
diff --git a/src/lib9/9proc.h b/src/lib9/9proc.h
index 0eb5f41..0c359c9 100644
--- a/src/lib9/9proc.h
+++ b/src/lib9/9proc.h
@@ -13,9 +13,6 @@
 	int pid;
 	int state;
 	void *priv[NPRIV];
-	ulong rendval;
-	ulong rendtag;
-	Uproc *rendhash;
 	p9jmp_buf notejb;
 };
 
diff --git a/src/lib9/_p9proc-Linux.c b/src/lib9/_p9proc-Linux.c
new file mode 100644
index 0000000..902a957
--- /dev/null
+++ b/src/lib9/_p9proc-Linux.c
@@ -0,0 +1,5 @@
+#ifdef __Linux26__
+#include "_p9proc-pthread.c"
+#else
+#include "_p9proc-getpid.c"
+#endif
diff --git a/src/lib9/_p9proc-getpid.c b/src/lib9/_p9proc-getpid.c
new file mode 100644
index 0000000..9543bf2
--- /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;
+		}
+	}
+}
diff --git a/src/lib9/fork.c b/src/lib9/fork.c
index 4dbff87..841d2c2 100644
--- a/src/lib9/fork.c
+++ b/src/lib9/fork.c
@@ -1,4 +1,5 @@
 #include <u.h>
+#include <signal.h>
 #include <libc.h>
 #include "9proc.h"
 #undef fork
@@ -7,9 +8,15 @@
 p9fork(void)
 {
 	int pid;
+	sigset_t all, old;
 
+	sigfillset(&all);
+	sigprocmask(SIG_SETMASK, &all, &old);
 	pid = fork();
-	_clearuproc();
-	_p9uproc(0);
+	if(pid == 0){
+		_clearuproc();
+		_p9uproc(0);
+	}
+	sigprocmask(SIG_SETMASK, &old, nil);
 	return pid;
 }
diff --git a/src/lib9/lock-Darwin.c b/src/lib9/lock-Darwin.c
new file mode 100644
index 0000000..231ca71
--- /dev/null
+++ b/src/lib9/lock-Darwin.c
@@ -0,0 +1 @@
+#include "lock-pthread.c"
diff --git a/src/lib9/lock-FreeBSD.c b/src/lib9/lock-FreeBSD.c
new file mode 100644
index 0000000..bdd48a2
--- /dev/null
+++ b/src/lib9/lock-FreeBSD.c
@@ -0,0 +1 @@
+#include "lock-tas.c"
diff --git a/src/lib9/lock-Linux.c b/src/lib9/lock-Linux.c
new file mode 100644
index 0000000..c25596b
--- /dev/null
+++ b/src/lib9/lock-Linux.c
@@ -0,0 +1,5 @@
+#ifdef __Linux26__
+#include "lock-pthread.c"
+#else
+#include "lock-tas.c"
+#endif
diff --git a/src/lib9/lock-pthread.c b/src/lib9/lock-pthread.c
new file mode 100644
index 0000000..689261f
--- /dev/null
+++ b/src/lib9/lock-pthread.c
@@ -0,0 +1,54 @@
+#include <u.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sched.h>
+#include <libc.h>
+
+static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+lockinit(Lock *lk)
+{
+	pthread_mutexattr_t attr;
+
+	pthread_mutex_lock(&initmutex);
+	if(lk->init == 0){
+		pthread_mutexattr_init(&attr);
+		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+		pthread_mutex_init(&lk->mutex, &attr);
+		pthread_mutexattr_destroy(&attr);
+		lk->init = 1;
+	}
+	pthread_mutex_unlock(&initmutex);
+}
+
+void
+lock(Lock *lk)
+{
+	if(!lk->init)
+		lockinit(lk);
+	if(pthread_mutex_lock(&lk->mutex) != 0)
+		abort();
+}
+
+int
+canlock(Lock *lk)
+{
+	int r;
+
+	if(!lk->init)
+		lockinit(lk);
+	r = pthread_mutex_trylock(&lk->mutex);
+	if(r == 0)
+		return 1;
+	if(r == EBUSY)
+		return 0;
+	abort();
+}
+
+void
+unlock(Lock *lk)
+{
+	if(pthread_mutex_unlock(&lk->mutex) != 0)
+		abort();
+}
diff --git a/src/lib9/lock-tas.c b/src/lib9/lock-tas.c
new file mode 100644
index 0000000..e6f54de
--- /dev/null
+++ b/src/lib9/lock-tas.c
@@ -0,0 +1,57 @@
+#include <u.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sched.h>
+#include <libc.h>
+
+int _ntas;
+static int
+_xtas(void *v)
+{
+	int x;
+
+	_ntas++;
+	x = _tas(v);
+	if(x != 0 && x != 0xcafebabe){
+		print("bad tas value %d\n", x);
+		abort();
+	}
+	return x;
+}
+
+int
+canlock(Lock *l)
+{
+	return !_xtas(&l->val);
+}
+
+void
+unlock(Lock *l)
+{
+	l->val = 0;
+}
+
+void
+lock(Lock *lk)
+{
+	int i;
+
+	/* once fast */
+	if(!_xtas(&lk->val))
+		return;
+	/* a thousand times pretty fast */
+	for(i=0; i<1000; i++){
+		if(!_xtas(&lk->val))
+			return;
+		sched_yield();
+	}
+	/* now nice and slow */
+	for(i=0; i<1000; i++){
+		if(!_xtas(&lk->val))
+			return;
+		usleep(100*1000);
+	}
+	/* take your time */
+	while(_xtas(&lk->val))
+		usleep(1000*1000);
+}
diff --git a/src/lib9/mkfile b/src/lib9/mkfile
index ed430ff..9200d81 100644
--- a/src/lib9/mkfile
+++ b/src/lib9/mkfile
@@ -67,7 +67,7 @@
 	_exits.$O\
 	_p9dialparse.$O\
 	_p9dir.$O\
-	_p9proc.$O\
+	_p9proc-$SYSNAME.$O\
 	announce.$O\
 	argv0.$O\
 	atexit.$O\
@@ -111,7 +111,7 @@
 	jmp.$O\
 	lrand.$O\
 	lnrand.$O\
-	lock.$O\
+	lock-$SYSNAME.$O\
 	main.$O\
 	malloc.$O\
 	malloctag.$O\
@@ -141,6 +141,7 @@
 	strecpy.$O\
 	sysfatal.$O\
 	sysname.$O\
+	tas-$OBJTYPE.$O\
 	time.$O\
 	tokenize.$O\
 	truerand.$O\
diff --git a/src/lib9/qlock.c b/src/lib9/qlock.c
index 625c100..0eacccd 100644
--- a/src/lib9/qlock.c
+++ b/src/lib9/qlock.c
@@ -18,6 +18,8 @@
 
 static void (*procsleep)(_Procrend*) = _procsleep;
 static void (*procwakeup)(_Procrend*) = _procwakeup;
+#define _procsleep donotcall_procsleep
+#define _procwakeup donotcall_procwakeup
 
 /* this gets called by the thread library ONLY to get us to use its rendezvous */
 void
@@ -73,7 +75,7 @@
 	q->tail = mp;
 	mp->state = Queuing;
 	mp->rend.l = &q->lock;
-	_procsleep(&mp->rend);
+	procsleep(&mp->rend);
 	unlock(&q->lock);
 	assert(mp->state == Waking);
 	unlock(&mp->inuse);
@@ -92,7 +94,7 @@
 		if(q->head == nil)
 			q->tail = nil;
 		p->state = Waking;
-		_procwakeup(&p->rend);
+		procwakeup(&p->rend);
 		unlock(&q->lock);
 		return;
 	}
@@ -137,7 +139,7 @@
 	mp->next = nil;
 	mp->state = QueuingR;
 	mp->rend.l = &q->lock;
-	_procsleep(&mp->rend);
+	procsleep(&mp->rend);
 	unlock(&q->lock);
 	assert(mp->state == Waking);
 	unlock(&mp->inuse);
@@ -181,7 +183,7 @@
 
 	/* wakeup waiter */
 	p->state = Waking;
-	_procwakeup(&p->rend);
+	procwakeup(&p->rend);
 	unlock(&q->lock);
 }
 
@@ -211,7 +213,7 @@
 
 	/* wait in kernel */
 	mp->rend.l = &q->lock;
-	_procsleep(&mp->rend);
+	procsleep(&mp->rend);
 	unlock(&q->lock);
 	assert(mp->state == Waking);
 	unlock(&mp->inuse);
@@ -253,7 +255,7 @@
 		if(q->head == nil)
 			q->tail = nil;
 		p->state = Waking;
-		_procwakeup(&p->rend);
+		procwakeup(&p->rend);
 		unlock(&q->lock);
 		return;
 	}
@@ -269,7 +271,7 @@
 		q->head = p->next;
 		q->readers++;
 		p->state = Waking;
-		_procwakeup(&p->rend);
+		procwakeup(&p->rend);
 	}
 	if(q->head == nil)
 		q->tail = nil;
@@ -310,20 +312,20 @@
 		if(r->l->head == nil)
 			r->l->tail = nil;
 		t->state = Waking;
-		_procwakeup(&t->rend);
+		procwakeup(&t->rend);
 	}else
 		r->l->locked = 0;
 
 	/* wait for a wakeup */
 	me->rend.l = &r->l->lock;
-	_procsleep(&me->rend);
-
+	procsleep(&me->rend);
 	assert(me->state == Waking);
 	unlock(&me->inuse);
 	if(!r->l->locked){
 		fprint(2, "rsleep: not locked after wakeup\n");
 		abort();
 	}
+	unlock(&r->l->lock);
 }
 
 int
diff --git a/src/lib9/rendez-signal.c b/src/lib9/rendez-signal.c
index e2abc3d..744a8fc 100644
--- a/src/lib9/rendez-signal.c
+++ b/src/lib9/rendez-signal.c
@@ -52,6 +52,7 @@
 	 */
 	ignusr1(1);
 	assert(r->asleep == 0);
+	lock(r->l);
 }
 
 void