cleanups - lots of removed files now in thread library.
qlock.c - stubs to thread library
notify.c - clean interface slightly.
diff --git a/src/lib9/ffork-Darwin.c b/src/lib9/ffork-Darwin.c
deleted file mode 100644
index 5e677f7..0000000
--- a/src/lib9/ffork-Darwin.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "ffork-pthread.c"
diff --git a/src/lib9/ffork-FreeBSD.c b/src/lib9/ffork-FreeBSD.c
deleted file mode 100644
index 476ce7a..0000000
--- a/src/lib9/ffork-FreeBSD.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <lib9.h>
-#include "9proc.h"
-
-extern int __isthreaded;
-int
-ffork(int flags, void(*fn)(void*), void *arg)
-{
-	int pid;
-	void *p;
-
-	_p9uproc(0);
-	__isthreaded = 1;
-	p = malloc(16384);
-	if(p == nil)
-		return -1;
-	memset(p, 0xFE, 16384);
-	pid = rfork_thread(RFPROC|flags, (char*)p+16000, (int(*)(void*))fn, arg);
-	if(pid == 0)
-		_p9uproc(0);
-	return pid;
-}
-
-/*
- * For FreeBSD libc.
- */
-
-typedef struct {
-	volatile long	access_lock;
-	volatile long	lock_owner;
-	volatile char	*fname;
-	volatile int	lineno;
-} spinlock_t;
-
-void
-_spinlock(spinlock_t *lk)
-{
-	lock((Lock*)&lk->access_lock);
-}
-
-int
-getfforkid(void)
-{
-	return getpid();
-}
-
diff --git a/src/lib9/ffork-Linux-clone.c b/src/lib9/ffork-Linux-clone.c
deleted file mode 100644
index f4704c6..0000000
--- a/src/lib9/ffork-Linux-clone.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Is nothing simple?
- *
- * We can't free the stack until we've finished executing,
- * but once we've finished executing, we can't do anything
- * at all, including call free.  So instead we keep a linked list
- * of all stacks for all processes, and every few times we try
- * to allocate a new stack we scan the current stack list for
- * dead processes and reclaim those stacks.
- */
-
-#include <u.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sched.h>
-#include <signal.h>
-#include <errno.h>
-#include <libc.h>
-#include "9proc.h"
-
-int fforkstacksize = 16384;
-
-typedef struct Stack Stack;
-struct Stack
-{
-	Stack *next;
-	Stack *fnext;
-	int pid;
-};
-
-static Lock stacklock;
-static Stack *freestacks;
-static Stack *allstacks;
-static int stackmallocs;
-static void gc(void);
-
-static void*
-mallocstack(void)
-{
-	Stack *p;
-
-	lock(&stacklock);
-top:
-	p = freestacks;
-	if(p)
-		freestacks = p->fnext;
-	else{
-		if(stackmallocs++%1 == 0)
-			gc();
-		if(freestacks)
-			goto top;
-		p = malloc(fforkstacksize);
-		p->next = allstacks;
-		allstacks = p;
-	}
-	if(p)
-		p->pid = 1;
-	unlock(&stacklock);
-	return p;
-}
-
-static void
-gc(void)
-{
-	Stack *p;
-
-	for(p=allstacks; p; p=p->next){
-		if(p->pid > 1)
-		if(kill(p->pid, 0) < 0 && errno == ESRCH){
-			if(0) fprint(2, "reclaim stack from %d\n", p->pid);
-			p->pid = 0;
-		}
-		if(p->pid == 0){
-			p->fnext = freestacks;
-			freestacks = p;
-		}
-	}
-}
-
-static void
-freestack(void *v)
-{
-	Stack *p;
-
-	p = v;
-	if(p == nil)
-		return;
-	lock(&stacklock);
-	p->fnext = freestacks;
-	p->pid = 0;
-	freestacks = p;
-	unlock(&stacklock);
-	return;
-}
-
-static int
-tramp(void *v)
-{
-	void (*fn)(void*), *arg;
-	void **v2;
-	void *p;
-
-	_p9uproc(0);
-	v2 = v;
-	fn = v2[0];
-	arg = v2[1];
-	p = v2[2];
-	free(v2);
-	fn(arg);
-	_exit(0);
-	return 0;
-}
-	
-static int
-trampnowait(void *v)
-{
-	int pid;
-	int cloneflag;
-	void **v2;
-	int *pidp;
-	void *p;
-
-	v2 = v;
-	cloneflag = (int)v2[4];
-	pidp = v2[3];
-	p = v2[2];
-	pid = clone(tramp, p+fforkstacksize-512, cloneflag, v);
-	*pidp = pid;
-	_exit(0);
-	return 0;
-}
-
-int
-ffork(int flags, void (*fn)(void*), void *arg)
-{
-	void **v;
-	char *p;
-	int cloneflag, pid, thepid, status, nowait;
-
-	_p9uproc(0);
-	p = mallocstack();
-	v = malloc(sizeof(void*)*5);
-	if(p==nil || v==nil){
-		freestack(p);
-		free(v);
-		return -1;
-	}
-	cloneflag = 0;
-	flags &= ~RFPROC;
-	if(flags&RFMEM){
-		cloneflag |= CLONE_VM;
-		flags &= ~RFMEM;
-	}
-	if(!(flags&RFFDG))
-		cloneflag |= CLONE_FILES;
-	else
-		flags &= ~RFFDG;
-	nowait = flags&RFNOWAIT;
-	if(!(flags&RFNOWAIT))
-		cloneflag |= SIGCHLD;
-	else
-		flags &= ~RFNOWAIT;
-	if(flags){
-		fprint(2, "unknown rfork flags %x\n", flags);
-		freestack(p);
-		free(v);
-		return -1;
-	}
-	v[0] = fn;
-	v[1] = arg;
-	v[2] = p;
-	v[3] = &thepid;
-	v[4] = (void*)cloneflag;
-	thepid = -1;
-	pid = clone(nowait ? trampnowait : tramp, p+fforkstacksize-16, cloneflag, v);
-	if(pid > 0 && nowait){
-		if(wait4(pid, &status, __WALL, 0) < 0)
-			fprint(2, "ffork wait4: %r\n");
-	}else
-		thepid = pid;
-	if(thepid == -1)
-		freestack(p);
-	else
-		((Stack*)p)->pid = thepid;
-	return thepid;
-}
-
-int
-getfforkid(void)
-{
-	return getpid();
-}
-
diff --git a/src/lib9/ffork-Linux.c b/src/lib9/ffork-Linux.c
deleted file mode 100644
index b433ec4..0000000
--- a/src/lib9/ffork-Linux.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __Linux26__
-#include "ffork-pthread.c"
-#else
-#include "ffork-Linux-clone.c"
-#endif
diff --git a/src/lib9/ffork-OpenBSD.c b/src/lib9/ffork-OpenBSD.c
deleted file mode 100644
index 5e677f7..0000000
--- a/src/lib9/ffork-OpenBSD.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "ffork-pthread.c"
diff --git a/src/lib9/ffork-SunOS.c b/src/lib9/ffork-SunOS.c
deleted file mode 100644
index 5e677f7..0000000
--- a/src/lib9/ffork-SunOS.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "ffork-pthread.c"
diff --git a/src/lib9/ffork-pthread.c b/src/lib9/ffork-pthread.c
deleted file mode 100644
index c89ad13..0000000
--- a/src/lib9/ffork-pthread.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#define NOPLAN9DEFINES
-#include <u.h>
-#include <libc.h>
-#include <pthread.h>
-#include "9proc.h"
-
-extern int __isthreaded;
-int
-ffork(int flags, void(*fn)(void*), void *arg)
-{
-	pthread_t tid;
-
-	if(flags != (RFMEM|RFNOWAIT)){
-		werrstr("ffork unsupported");
-		return -1;
-	}
-
-	_p9uproc(0);
-	if(pthread_create(&tid, NULL, (void*(*)(void*))fn, arg) < 0)
-		return -1;
-	if((int)tid == 0)
-		_p9uproc(0);
-	return (int)tid;
-}
-
-int
-getfforkid(void)
-{
-	return (int)pthread_self();
-}
-
diff --git a/src/lib9/lock-Darwin.c b/src/lib9/lock-Darwin.c
deleted file mode 100644
index 231ca71..0000000
--- a/src/lib9/lock-Darwin.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "lock-pthread.c"
diff --git a/src/lib9/lock-FreeBSD.c b/src/lib9/lock-FreeBSD.c
deleted file mode 100644
index bdd48a2..0000000
--- a/src/lib9/lock-FreeBSD.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "lock-tas.c"
diff --git a/src/lib9/lock-Linux.c b/src/lib9/lock-Linux.c
deleted file mode 100644
index c25596b..0000000
--- a/src/lib9/lock-Linux.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#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
deleted file mode 100644
index eb3ea21..0000000
--- a/src/lib9/lock-pthread.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <u.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sched.h>
-#include <errno.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
deleted file mode 100644
index e6f54de..0000000
--- a/src/lib9/lock-tas.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#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 133fcf4..0c1c302 100644
--- a/src/lib9/mkfile
+++ b/src/lib9/mkfile
@@ -108,7 +108,6 @@
 	jmp.$O\
 	lrand.$O\
 	lnrand.$O\
-	lock-$SYSNAME.$O\
 	main.$O\
 	malloc.$O\
 	malloctag.$O\
@@ -129,7 +128,6 @@
 	quote.$O\
 	read9pmsg.$O\
 	readn.$O\
-	rendez-$SYSNAME.$O\
 	rfork.$O\
 	seek.$O\
 	sendfd.$O\
@@ -138,7 +136,6 @@
 	strecpy.$O\
 	sysfatal.$O\
 	sysname.$O\
-	tas-$OBJTYPE.$O\
 	time.$O\
 	tokenize.$O\
 	truerand.$O\
@@ -164,5 +161,3 @@
 
 %.$O: utf/%.c
 	$CC $CFLAGS utf/$stem.c
-
-rendez-Linux.$O: rendez-signal.c
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
index 2b95e09..faf1392 100644
--- a/src/lib9/notify.c
+++ b/src/lib9/notify.c
@@ -7,9 +7,9 @@
  * There is no equivalent note to Unix's SIGKILL, since
  * it's not a deliverable signal anyway.
  *
- * We do not handle SIGABRT or SIGSEGV, mainly so that
- * stack traces show the original source of the signal instead
- * of notifysigf.
+ * We do not handle SIGABRT or SIGSEGV, mainly because
+ * the thread library queues its notes for later, and we want
+ * to dump core with the state at time of delivery.
  *
  * We have to add some extra entry points to provide the
  * ability to tweak which signals are deliverable and which
@@ -112,7 +112,6 @@
 static void
 signotify(int sig)
 {
-	int v;
 	char tmp[64];
 	Jmp *j;
 
@@ -150,7 +149,6 @@
 int
 notify(void (*f)(void*, char*))
 {
-	int i;
 	static int init;
 
 	notifyf = f;
@@ -164,7 +162,8 @@
 /*
  * Nonsense about enabling and disabling signals.
  */
-static void(*)(int)
+typedef void Sighandler(int);
+static Sighandler*
 handler(int s)
 {
 	struct sigaction sa;
@@ -174,7 +173,7 @@
 }
 
 static void
-notifysetenable(int sig, int enabled)
+notesetenable(int sig, int enabled)
 {
 	sigset_t mask;
 
@@ -187,15 +186,15 @@
 }
 
 void
-notifyenable(char *msg)
+noteenable(char *msg)
 {
-	notifyenablex(_p9strsig(msg), 1);
+	notesetenable(_p9strsig(msg), 1);
 }
 
 void
-notifydisable(char *msg)
+notedisable(char *msg)
 {
-	notifyenablex(_p9strsig(msg), 0);
+	notesetenable(_p9strsig(msg), 0);
 }
 
 static void
@@ -207,7 +206,8 @@
 	sig = findsig(s);
 	if(sig == nil)
 		return;
-	notifyenable(msg);
+	if(on)
+		notesetenable(s, 1);
 	memset(&sa, 0, sizeof sa);
 	sa.sa_handler = on ? signotify : signonotify;
 	if(sig->restart)
@@ -234,7 +234,7 @@
 void
 notifyoff(char *msg)
 {
-	notifysetoff(_p9strsig(msg), 0);
+	notifyseton(_p9strsig(msg), 0);
 }
 
 /*
@@ -252,6 +252,7 @@
 		 * If someone has already installed a handler,
 		 * It's probably some ld preload nonsense,
 		 * like pct (a SIGVTALRM-based profiler).
+		 * Or maybe someone has already called notifyon/notifyoff.
 		 * Leave it alone.
 		 */
 		if(handler(sig->sig) != SIG_DFL)
@@ -261,7 +262,7 @@
 		 * (I.e. if parent has disabled for us, should we still enable?)
 		 * Right now we always initialize to the state we want.
 		 */
-		notifysetenable(sig->sig, sig->enabled);
+		notesetenable(sig->sig, sig->enabled);
 		notifyseton(sig->sig, sig->notified);
 	}
 }
diff --git a/src/lib9/qlock.c b/src/lib9/qlock.c
index 0eacccd..a979c44 100644
--- a/src/lib9/qlock.c
+++ b/src/lib9/qlock.c
@@ -1,379 +1,167 @@
-#include <lib9.h>
+#include <u.h>
+#include <libc.h>
 
-static struct {
-	QLp	*p;
-	QLp	x[1024];
-} ql = {
-	ql.x
-};
+/*
+ * The function pointers are supplied by the thread
+ * library during its initialization.  If there is no thread
+ * library, there is no multithreading.
+ */
 
-enum
-{
-	Queuing,
-	QueuingR,
-	QueuingW,
-	Sleeping,
-	Waking,
-};
-
-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
-_qlockinit(void (*sleep)(_Procrend*), void (*wakeup)(_Procrend*))
-{
-	procsleep = sleep;
-	procwakeup = wakeup;
-}
-
-/* find a free shared memory location to queue ourselves in */
-static QLp*
-getqlp(void)
-{
-	QLp *p, *op;
-
-	op = ql.p;
-	for(p = op+1; ; p++){
-		if(p == &ql.x[nelem(ql.x)])
-			p = ql.x;
-		if(p == op){
-			fprint(2, "qlock: out of qlp\n");
-			abort();
-		}
-		if(canlock(&p->inuse)){
-			ql.p = p;
-			p->next = nil;
-			break;
-		}
-	}
-	return p;
-}
+int	(*_lock)(Lock*, int, ulong);
+void	(*_unlock)(Lock*, ulong);
+int	(*_qlock)(QLock*, int, ulong);	/* do not use */
+void	(*_qunlock)(QLock*, ulong);
+void	(*_rsleep)(Rendez*, ulong);	/* do not use */
+int	(*_rwakeup)(Rendez*, int, ulong);
+int	(*_rlock)(RWLock*, int, ulong);	/* do not use */
+int	(*_wlock)(RWLock*, int, ulong);
+void	(*_runlock)(RWLock*, ulong);
+void	(*_wunlock)(RWLock*, ulong);
 
 void
-qlock(QLock *q)
+lock(Lock *l)
 {
-	QLp *p, *mp;
-
-	lock(&q->lock);
-	if(!q->locked){
-		q->locked = 1;
-		unlock(&q->lock);
-		return;
-	}
-
-
-	/* chain into waiting list */
-	mp = getqlp();
-	p = q->tail;
-	if(p == nil)
-		q->head = mp;
+	if(_lock)
+		(*_lock)(l, 1, getcallerpc(&l));
 	else
-		p->next = mp;
-	q->tail = mp;
-	mp->state = Queuing;
-	mp->rend.l = &q->lock;
-	procsleep(&mp->rend);
-	unlock(&q->lock);
-	assert(mp->state == Waking);
-	unlock(&mp->inuse);
-}
-
-void
-qunlock(QLock *q)
-{
-	QLp *p;
-
-	lock(&q->lock);
-	p = q->head;
-	if(p != nil){
-		/* wakeup head waiting process */
-		q->head = p->next;
-		if(q->head == nil)
-			q->tail = nil;
-		p->state = Waking;
-		procwakeup(&p->rend);
-		unlock(&q->lock);
-		return;
-	}
-	q->locked = 0;
-	unlock(&q->lock);
+		l->held = 1;
 }
 
 int
-canqlock(QLock *q)
+canlock(Lock *l)
 {
-	if(!canlock(&q->lock))
-		return 0;
-	if(!q->locked){
-		q->locked = 1;
-		unlock(&q->lock);
+	if(_lock)
+		return (*_lock)(l, 0, getcallerpc(&l));
+	else{
+		if(l->held)
+			return 0;
+		l->held = 1;
 		return 1;
 	}
-	unlock(&q->lock);
-	return 0;
 }
 
 void
-rlock(RWLock *q)
+unlock(Lock *l)
 {
-	QLp *p, *mp;
-
-	lock(&q->lock);
-	if(q->writer == 0 && q->head == nil){
-		/* no writer, go for it */
-		q->readers++;
-		unlock(&q->lock);
-		return;
-	}
-
-	mp = getqlp();
-	p = q->tail;
-	if(p == 0)
-		q->head = mp;
+	if(_unlock)
+		(*_unlock)(l, getcallerpc(&l));
 	else
-		p->next = mp;
-	q->tail = mp;
-	mp->next = nil;
-	mp->state = QueuingR;
-	mp->rend.l = &q->lock;
-	procsleep(&mp->rend);
-	unlock(&q->lock);
-	assert(mp->state == Waking);
-	unlock(&mp->inuse);
+		l->held = 0;
+}
+
+void
+qlock(QLock *l)
+{
+	if(_qlock)
+		(*_qlock)(l, 1, getcallerpc(&l));
+	else
+		l->l.held = 1;
 }
 
 int
-canrlock(RWLock *q)
+canqlock(QLock *l)
 {
-	lock(&q->lock);
-	if (q->writer == 0 && q->head == nil) {
-		/* no writer; go for it */
-		q->readers++;
-		unlock(&q->lock);
+	if(_qlock)
+		return (*_qlock)(l, 0, getcallerpc(&l));
+	else{
+		if(l->l.held)
+			return 0;
+		l->l.held = 1;
 		return 1;
 	}
-	unlock(&q->lock);
-	return 0;
 }
 
 void
-runlock(RWLock *q)
+qunlock(QLock *l)
 {
-	QLp *p;
-
-	lock(&q->lock);
-	if(q->readers <= 0)
-		abort();
-	p = q->head;
-	if(--(q->readers) > 0 || p == nil){
-		unlock(&q->lock);
-		return;
-	}
-
-	/* start waiting writer */
-	if(p->state != QueuingW)
-		abort();
-	q->head = p->next;
-	if(q->head == 0)
-		q->tail = 0;
-	q->writer = 1;
-
-	/* wakeup waiter */
-	p->state = Waking;
-	procwakeup(&p->rend);
-	unlock(&q->lock);
-}
-
-void
-wlock(RWLock *q)
-{
-	QLp *p, *mp;
-
-	lock(&q->lock);
-	if(q->readers == 0 && q->writer == 0){
-		/* noone waiting, go for it */
-		q->writer = 1;
-		unlock(&q->lock);
-		return;
-	}
-
-	/* wait */
-	p = q->tail;
-	mp = getqlp();
-	if(p == nil)
-		q->head = mp;
+	if(_qunlock)
+		(*_qunlock)(l, getcallerpc(&l));
 	else
-		p->next = mp;
-	q->tail = mp;
-	mp->next = nil;
-	mp->state = QueuingW;
+		l->l.held = 0;
+}
 
-	/* wait in kernel */
-	mp->rend.l = &q->lock;
-	procsleep(&mp->rend);
-	unlock(&q->lock);
-	assert(mp->state == Waking);
-	unlock(&mp->inuse);
+void
+rlock(RWLock *l)
+{
+	if(_rlock)
+		(*_rlock)(l, 1, getcallerpc(&l));
+	else
+		l->readers++;
 }
 
 int
-canwlock(RWLock *q)
+canrlock(RWLock *l)
 {
-	lock(&q->lock);
-	if (q->readers == 0 && q->writer == 0) {
-		/* no one waiting; go for it */
-		q->writer = 1;
-		unlock(&q->lock);
+	if(_rlock)
+		return (*_rlock)(l, 0, getcallerpc(&l));
+	else{
+		if(l->writer)
+			return 0;
+		l->readers++;
 		return 1;
 	}
-	unlock(&q->lock);
-	return 0;
+	return 1;
 }
 
 void
-wunlock(RWLock *q)
+runlock(RWLock *l)
 {
-	QLp *p;
+	if(_runlock)
+		(*_runlock)(l, getcallerpc(&l));
+	else
+		l->readers--;
+}
 
-	lock(&q->lock);
-	if(q->writer == 0){
-		fprint(2, "wunlock: not holding lock\n");
-		abort();
-	}
-	p = q->head;
-	if(p == nil){
-		q->writer = 0;
-		unlock(&q->lock);
-		return;
-	}
-	if(p->state == QueuingW){
-		/* start waiting writer */
-		q->head = p->next;
-		if(q->head == nil)
-			q->tail = nil;
-		p->state = Waking;
-		procwakeup(&p->rend);
-		unlock(&q->lock);
-		return;
-	}
+void
+wlock(RWLock *l)
+{
+	if(_wlock)
+		(*_wlock)(l, 1, getcallerpc(&l));
+	else
+		l->writer = (void*)1;
+}
 
-	if(p->state != QueuingR){
-		fprint(2, "wunlock: bad state\n");
-		abort();
+int
+canwlock(RWLock *l)
+{
+	if(_wlock)
+		return (*_wlock)(l, 0, getcallerpc(&l));
+	else{
+		if(l->writer || l->readers)
+			return 0;
+		l->writer = (void*)1;
+		return 1;
 	}
+}
 
-	/* wake waiting readers */
-	while(q->head != nil && q->head->state == QueuingR){
-		p = q->head;
-		q->head = p->next;
-		q->readers++;
-		p->state = Waking;
-		procwakeup(&p->rend);
-	}
-	if(q->head == nil)
-		q->tail = nil;
-	q->writer = 0;
-	unlock(&q->lock);
+void
+wunlock(RWLock *l)
+{
+	if(_wunlock)
+		(*_wunlock)(l, getcallerpc(&l));
+	else
+		l->writer = nil;
 }
 
 void
 rsleep(Rendez *r)
 {
-	QLp *t, *me;
-
-	if(!r->l){
-		fprint(2, "rsleep: no lock\n");
-		abort();
-	}
-	lock(&r->l->lock);
-	/* we should hold the qlock */
-	if(!r->l->locked){
-		fprint(2, "rsleep: not locked\n");
-		abort();
-	}
-
-	/* add ourselves to the wait list */
-	me = getqlp();
-	me->state = Sleeping;
-	if(r->head == nil)
-		r->head = me;
-	else
-		r->tail->next = me;
-	me->next = nil;
-	r->tail = me;
-
-	/* pass the qlock to the next guy */
-	t = r->l->head;
-	if(t){
-		r->l->head = t->next;
-		if(r->l->head == nil)
-			r->l->tail = nil;
-		t->state = Waking;
-		procwakeup(&t->rend);
-	}else
-		r->l->locked = 0;
-
-	/* wait for a wakeup */
-	me->rend.l = &r->l->lock;
-	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);
+	if(_rsleep)
+		(*_rsleep)(r, getcallerpc(&r));
 }
 
 int
 rwakeup(Rendez *r)
 {
-	QLp *t;
-
-	/*
-	 * take off wait and put on front of queue
-	 * put on front so guys that have been waiting will not get starved
-	 */
-	
-	if(!r->l){
-		fprint(2, "rwakeup: no lock\n");
-		abort();
-	}
-	lock(&r->l->lock);
-	if(!r->l->locked){
-		fprint(2, "rwakeup: not locked\n");
-		abort();
-	}
-
-	t = r->head;
-	if(t == nil){
-		unlock(&r->l->lock);
-		return 0;
-	}
-
-	r->head = t->next;
-	if(r->head == nil)
-		r->tail = nil;
-
-	t->next = r->l->head;
-	r->l->head = t;
-	if(r->l->tail == nil)
-		r->l->tail = t;
-
-	t->state = Queuing;
-	unlock(&r->l->lock);
-	return 1;
+	if(_rwakeup)
+		return (*_rwakeup)(r, 0, getcallerpc(&r));
+	return 0;
 }
 
 int
 rwakeupall(Rendez *r)
 {
-	int i;
-
-	for(i=0; rwakeup(r); i++)
-		;
-	return i;
+	if(_rwakeup)
+		return (*_rwakeup)(r, 1, getcallerpc(&r));
+	return 0;
 }
diff --git a/src/lib9/rendez-Darwin.c b/src/lib9/rendez-Darwin.c
deleted file mode 100644
index 2f099fc..0000000
--- a/src/lib9/rendez-Darwin.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "rendez-pthread.c"
-
diff --git a/src/lib9/rendez-FreeBSD.c b/src/lib9/rendez-FreeBSD.c
deleted file mode 100644
index 05c52ae..0000000
--- a/src/lib9/rendez-FreeBSD.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "rendez-signal.c"
diff --git a/src/lib9/rendez-Linux.c b/src/lib9/rendez-Linux.c
deleted file mode 100644
index c86fb5b..0000000
--- a/src/lib9/rendez-Linux.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __Linux26__
-#include "rendez-pthread.c"
-#else
-#include "rendez-signal.c"
-#endif
diff --git a/src/lib9/rendez-OpenBSD.c b/src/lib9/rendez-OpenBSD.c
deleted file mode 100644
index 05c52ae..0000000
--- a/src/lib9/rendez-OpenBSD.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "rendez-signal.c"
diff --git a/src/lib9/rendez-SunOS.c b/src/lib9/rendez-SunOS.c
deleted file mode 100644
index eabb9a7..0000000
--- a/src/lib9/rendez-SunOS.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "rendez-pthread.c"
diff --git a/src/lib9/rendez-pthread.c b/src/lib9/rendez-pthread.c
deleted file mode 100644
index 2d08e0c..0000000
--- a/src/lib9/rendez-pthread.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <u.h>
-#include <pthread.h>
-#include <libc.h>
-
-void
-_procsleep(_Procrend *rend)
-{
-//print("sleep %p %d\n", rend, getpid());
-	pthread_cond_init(&rend->cond, 0);
-	rend->asleep = 1;
-	while(rend->asleep)
-		pthread_cond_wait(&rend->cond, &rend->l->mutex);
-	pthread_cond_destroy(&rend->cond);
-}
-
-void
-_procwakeup(_Procrend *rend)
-{
-//print("wakeup %p\n", rend);
-	rend->asleep = 0;
-	pthread_cond_signal(&rend->cond);
-}
-
diff --git a/src/lib9/rendez-signal.c b/src/lib9/rendez-signal.c
deleted file mode 100644
index 744a8fc..0000000
--- a/src/lib9/rendez-signal.c
+++ /dev/null
@@ -1,64 +0,0 @@
-#include <u.h>
-#include <signal.h>
-#include <libc.h>
-
-#define DBG 0
-
-static void
-ign(int x)
-{
-	USED(x);
-}
-
-void /*__attribute__((constructor))*/
-ignusr1(int restart)
-{
-	struct sigaction sa;
-
-	memset(&sa, 0, sizeof sa);
-	sa.sa_handler = ign;
-	sigemptyset(&sa.sa_mask);
-	sigaddset(&sa.sa_mask, SIGUSR1);
-	if(restart)
-		sa.sa_flags = SA_RESTART;
-	sigaction(SIGUSR1, &sa, nil);
-}
-
-void
-_procsleep(_Procrend *r)
-{
-	sigset_t mask;
-
-	/*
-	 * Go to sleep.
-	 *
-	 * Block USR1, set the handler to interrupt system calls,
-	 * unlock the vouslock so our waker can wake us,
-	 * and then suspend.
-	 */
-	r->asleep = 1;
-	r->pid = getpid();
-
-	sigprocmask(SIG_SETMASK, nil, &mask);
-	sigaddset(&mask, SIGUSR1);
-	sigprocmask(SIG_SETMASK, &mask, nil);
-	ignusr1(0);
-	unlock(r->l);
-	sigdelset(&mask, SIGUSR1);
-	sigsuspend(&mask);
-
-	/*
-	 * We're awake.  Make USR1 not interrupt system calls.
-	 */
-	ignusr1(1);
-	assert(r->asleep == 0);
-	lock(r->l);
-}
-
-void
-_procwakeup(_Procrend *r)
-{
-	r->asleep = 0;
-	assert(r->pid >= 1);
-	kill(r->pid, SIGUSR1);
-}
diff --git a/src/lib9/rendez.c b/src/lib9/rendez.c
deleted file mode 100644
index 2b2c1a1..0000000
--- a/src/lib9/rendez.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include "9proc.h"
-
-static Lock rendlock;
-static Uproc *rendhash[RENDHASH];
-
-ulong
-rendezvous(ulong tag, ulong val)
-{
-	char c;
-	ulong ret;
-	Uproc *t, *self, **l;
-
-	self = _p9uproc(0);
-	lock(&rendlock);
-	l = &rendhash[tag%RENDHASH];
-	for(t=*l; t; l=&t->rendhash, t=*l){
-		if(t->rendtag==tag){
-			*l = t->rendhash;
-			ret = t->rendval;
-			t->rendval = val;
-			t->rendtag++;
-			c = 0;
-			unlock(&rendlock);
-			write(t->pipe[1], &c, 1);
-			return ret;
-		}
-	}
-
-	/* Going to sleep here. */
-	t = self;
-	t->rendtag = tag;
-	t->rendval = val;
-	t->rendhash = *l;
-	*l = t;
-	unlock(&rendlock);
-	do
-		read(t->pipe[0], &c, 1);
-	while(t->rendtag == tag);
-	return t->rendval;
-}
diff --git a/src/lib9/tas-386.s b/src/lib9/tas-386.s
deleted file mode 100644
index 7a62d2d..0000000
--- a/src/lib9/tas-386.s
+++ /dev/null
@@ -1,6 +0,0 @@
-.globl _tas
-_tas:
-	movl $0xCAFEBABE, %eax
-	movl 4(%esp), %ecx
-	xchgl %eax, 0(%ecx)
-	ret
diff --git a/src/lib9/tas-PowerMacintosh.c b/src/lib9/tas-PowerMacintosh.c
deleted file mode 100644
index d7a8610..0000000
--- a/src/lib9/tas-PowerMacintosh.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "u.h"
-#include "libc.h"
-
-/*
- * first argument (l) is in r3 at entry.
- * r3 contains return value upon return.
- */
-int
-_tas(int *x)
-{
-	int     v;
-	/*
-	 * this __asm__ works with gcc 2.95.2 (mac os x 10.1).
-	 * this assembly language destroys r0 (0), some other register (v),
-	 * r4 (x) and r5 (temp).
-	 */
-	__asm__("\n	sync\n"
-	"	li	r0,0\n"
-	"	mr	r4,%1		/* &l->val */\n"
-	"	lis	r5,0xdead	/* assemble constant 0xdeaddead */\n"
-	"	ori	r5,r5,0xdead	/* \" */\n"
-	"tas1:\n"
-	"	dcbf	r4,r0	/* cache flush; \"fix for 603x bug\" */\n"
-	"	lwarx	%0,r4,r0	/* v = l->val with reservation */\n"
-	"	cmp	cr0,0,%0,r0	/* v == 0 */\n"
-	"	bne	tas0\n"
-	"	stwcx.	r5,r4,r0   /* if (l->val same) l->val = 0xdeaddead */\n"
-	"	bne	tas1\n"
-	"tas0:\n"
-	"	sync\n"
-	"	isync\n"
-	: "=r" (v)
-	: "r"  (x)
-	: "cc", "memory", "r0", "r4", "r5"
-	);
-	switch(v) {
-	case 0:		return 0;
-	case 0xdeaddead: return 1;
-	default:	fprint(2, "tas: corrupted 0x%lux\n", v);
-	}
-	return 0;
-}
diff --git a/src/lib9/tas-power.c b/src/lib9/tas-power.c
deleted file mode 100644
index 2ed71d4..0000000
--- a/src/lib9/tas-power.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "u.h"
-#include "libc.h"
-
-/*
- * first argument (l) is in r3 at entry.
- * r3 contains return value upon return.
- */
-int
-_tas(int *x)
-{
-	int     v;
-	int	tmp, tmp2, tmp3;
-
-	/*
-	 * this __asm__ works with gcc on linux
-	 */
-	__asm__("\n	sync\n"
-	"	li	%1,0\n"
-	"	mr	%2,%4		/* &x->val */\n"
-	"	lis	%3,0xdead	/* assemble constant 0xdeaddead */\n"
-	"	ori	%3,%3,0xdead	/* \" */\n"
-	"tas1:\n"
-	"	dcbf	%2,%1	/* cache flush; \"fix for 603x bug\" */\n"
-	"	lwarx	%0,%2,%1	/* v = x->val with reservation */\n"
-	"	cmp	cr0,0,%0,%1	/* v == 0 */\n"
-	"	bne	tas0\n"
-	"	stwcx.	%3,%2,%1   /* if (x->val same) x->val = 0xdeaddead */\n"
-	"	bne	tas1\n"
-	"tas0:\n"
-	"	sync\n"
-	"	isync\n"
-	: "=r" (v), "=&r" (tmp), "=&r"(tmp2), "=&r"(tmp3)
-	: "r"  (x)
-	: "cr0", "memory"
-	);
-	switch(v) {
-	case 0:		return 0;
-	case 0xdeaddead: return 1;
-	default:	fprint(2, "tas: corrupted 0x%lux\n", v);
-	}
-	return 0;
-}
diff --git a/src/lib9/tas-sun4u.s b/src/lib9/tas-sun4u.s
deleted file mode 100644
index b960a26..0000000
--- a/src/lib9/tas-sun4u.s
+++ /dev/null
@@ -1,4 +0,0 @@
-.globl _tas
-_tas:
-	retl
-	ldstub [%o0], %o0