URI: 
       tcleanups - lots of removed files now in thread library. qlock.c - stubs to thread library notify.c - clean interface slightly. - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 5f8fa94796903bf81db4f1dc76d433a80308b3d4
   DIR parent b2ff5382580e13d82ca48966c9d79d3318865cba
  HTML Author: rsc <devnull@localhost>
       Date:   Sun, 26 Dec 2004 21:51:15 +0000
       
       cleanups - lots of removed files now in thread library.
       qlock.c - stubs to thread library
       notify.c - clean interface slightly.
       
       Diffstat:
         D src/lib9/ffork-Darwin.c             |       1 -
         D src/lib9/ffork-FreeBSD.c            |      45 -------------------------------
         D src/lib9/ffork-Linux-clone.c        |     193 -------------------------------
         D src/lib9/ffork-Linux.c              |       5 -----
         D src/lib9/ffork-OpenBSD.c            |       1 -
         D src/lib9/ffork-SunOS.c              |       1 -
         D src/lib9/ffork-pthread.c            |      31 -------------------------------
         D src/lib9/lock-Darwin.c              |       1 -
         D src/lib9/lock-FreeBSD.c             |       1 -
         D src/lib9/lock-Linux.c               |       5 -----
         D src/lib9/lock-pthread.c             |      55 -------------------------------
         D src/lib9/lock-tas.c                 |      57 -------------------------------
         M src/lib9/mkfile                     |       5 -----
         M src/lib9/notify.c                   |      29 +++++++++++++++--------------
         M src/lib9/qlock.c                    |     408 ++++++++-----------------------
         D src/lib9/rendez-Darwin.c            |       2 --
         D src/lib9/rendez-FreeBSD.c           |       1 -
         D src/lib9/rendez-Linux.c             |       5 -----
         D src/lib9/rendez-OpenBSD.c           |       1 -
         D src/lib9/rendez-SunOS.c             |       1 -
         D src/lib9/rendez-pthread.c           |      23 -----------------------
         D src/lib9/rendez-signal.c            |      64 -------------------------------
         D src/lib9/rendez.c                   |      42 -------------------------------
         D src/lib9/tas-386.s                  |       6 ------
         D src/lib9/tas-PowerMacintosh.c       |      42 -------------------------------
         D src/lib9/tas-power.c                |      42 -------------------------------
         D src/lib9/tas-sun4u.s                |       4 ----
       
       27 files changed, 113 insertions(+), 958 deletions(-)
       ---
   DIR diff --git a/src/lib9/ffork-Darwin.c b/src/lib9/ffork-Darwin.c
       t@@ -1 +0,0 @@
       -#include "ffork-pthread.c"
   DIR diff --git a/src/lib9/ffork-FreeBSD.c b/src/lib9/ffork-FreeBSD.c
       t@@ -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();
       -}
       -
   DIR diff --git a/src/lib9/ffork-Linux-clone.c b/src/lib9/ffork-Linux-clone.c
       t@@ -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();
       -}
       -
   DIR diff --git a/src/lib9/ffork-Linux.c b/src/lib9/ffork-Linux.c
       t@@ -1,5 +0,0 @@
       -#ifdef __Linux26__
       -#include "ffork-pthread.c"
       -#else
       -#include "ffork-Linux-clone.c"
       -#endif
   DIR diff --git a/src/lib9/ffork-OpenBSD.c b/src/lib9/ffork-OpenBSD.c
       t@@ -1 +0,0 @@
       -#include "ffork-pthread.c"
   DIR diff --git a/src/lib9/ffork-SunOS.c b/src/lib9/ffork-SunOS.c
       t@@ -1 +0,0 @@
       -#include "ffork-pthread.c"
   DIR diff --git a/src/lib9/ffork-pthread.c b/src/lib9/ffork-pthread.c
       t@@ -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();
       -}
       -
   DIR diff --git a/src/lib9/lock-Darwin.c b/src/lib9/lock-Darwin.c
       t@@ -1 +0,0 @@
       -#include "lock-pthread.c"
   DIR diff --git a/src/lib9/lock-FreeBSD.c b/src/lib9/lock-FreeBSD.c
       t@@ -1 +0,0 @@
       -#include "lock-tas.c"
   DIR diff --git a/src/lib9/lock-Linux.c b/src/lib9/lock-Linux.c
       t@@ -1,5 +0,0 @@
       -#ifdef __Linux26__
       -#include "lock-pthread.c"
       -#else
       -#include "lock-tas.c"
       -#endif
   DIR diff --git a/src/lib9/lock-pthread.c b/src/lib9/lock-pthread.c
       t@@ -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();
       -}
   DIR diff --git a/src/lib9/lock-tas.c b/src/lib9/lock-tas.c
       t@@ -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);
       -}
   DIR diff --git a/src/lib9/mkfile b/src/lib9/mkfile
       t@@ -108,7 +108,6 @@ LIB9OFILES=\
                jmp.$O\
                lrand.$O\
                lnrand.$O\
       -        lock-$SYSNAME.$O\
                main.$O\
                malloc.$O\
                malloctag.$O\
       t@@ -129,7 +128,6 @@ LIB9OFILES=\
                quote.$O\
                read9pmsg.$O\
                readn.$O\
       -        rendez-$SYSNAME.$O\
                rfork.$O\
                seek.$O\
                sendfd.$O\
       t@@ -138,7 +136,6 @@ LIB9OFILES=\
                strecpy.$O\
                sysfatal.$O\
                sysname.$O\
       -        tas-$OBJTYPE.$O\
                time.$O\
                tokenize.$O\
                truerand.$O\
       t@@ -164,5 +161,3 @@ HFILES=\
        
        %.$O: utf/%.c
                $CC $CFLAGS utf/$stem.c
       -
       -rendez-Linux.$O: rendez-signal.c
   DIR diff --git a/src/lib9/notify.c b/src/lib9/notify.c
       t@@ -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
       t@@ -112,7 +112,6 @@ static void (*notifyf)(void*, char*);        /* Plan 9 handler */
        static void
        signotify(int sig)
        {
       -        int v;
                char tmp[64];
                Jmp *j;
        
       t@@ -150,7 +149,6 @@ noted(int v)
        int
        notify(void (*f)(void*, char*))
        {
       -        int i;
                static int init;
        
                notifyf = f;
       t@@ -164,7 +162,8 @@ notify(void (*f)(void*, char*))
        /*
         * Nonsense about enabling and disabling signals.
         */
       -static void(*)(int)
       +typedef void Sighandler(int);
       +static Sighandler*
        handler(int s)
        {
                struct sigaction sa;
       t@@ -174,7 +173,7 @@ handler(int s)
        }
        
        static void
       -notifysetenable(int sig, int enabled)
       +notesetenable(int sig, int enabled)
        {
                sigset_t mask;
        
       t@@ -187,15 +186,15 @@ notifysetenable(int sig, int enabled)
        }
        
        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
       t@@ -207,7 +206,8 @@ notifyseton(int s, int on)
                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)
       t@@ -234,7 +234,7 @@ notifyon(char *msg)
        void
        notifyoff(char *msg)
        {
       -        notifysetoff(_p9strsig(msg), 0);
       +        notifyseton(_p9strsig(msg), 0);
        }
        
        /*
       t@@ -252,6 +252,7 @@ noteinit(void)
                         * 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)
       t@@ -261,7 +262,7 @@ noteinit(void)
                         * (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);
                }
        }
   DIR diff --git a/src/lib9/qlock.c b/src/lib9/qlock.c
       t@@ -1,379 +1,167 @@
       -#include <lib9.h>
       +#include <u.h>
       +#include <libc.h>
       +
       +/*
       + * The function pointers are supplied by the thread
       + * library during its initialization.  If there is no thread
       + * library, there is no multithreading.
       + */
       +
       +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);
        
       -static struct {
       -        QLp        *p;
       -        QLp        x[1024];
       -} ql = {
       -        ql.x
       -};
       -
       -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*))
       +lock(Lock *l)
        {
       -        procsleep = sleep;
       -        procwakeup = wakeup;
       +        if(_lock)
       +                (*_lock)(l, 1, getcallerpc(&l));
       +        else
       +                l->held = 1;
        }
        
       -/* find a free shared memory location to queue ourselves in */
       -static QLp*
       -getqlp(void)
       +int
       +canlock(Lock *l)
        {
       -        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;
       -                }
       +        if(_lock)
       +                return (*_lock)(l, 0, getcallerpc(&l));
       +        else{
       +                if(l->held)
       +                        return 0;
       +                l->held = 1;
       +                return 1;
                }
       -        return p;
        }
        
        void
       -qlock(QLock *q)
       +unlock(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(_unlock)
       +                (*_unlock)(l, 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);
       +                l->held = 0;
        }
        
        void
       -qunlock(QLock *q)
       +qlock(QLock *l)
        {
       -        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);
       +        if(_qlock)
       +                (*_qlock)(l, 1, getcallerpc(&l));
       +        else
       +                l->l.held = 1;
        }
        
        int
       -canqlock(QLock *q)
       +canqlock(QLock *l)
        {
       -        if(!canlock(&q->lock))
       -                return 0;
       -        if(!q->locked){
       -                q->locked = 1;
       -                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
       -rlock(RWLock *q)
       +qunlock(QLock *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;
       -        }
       +        if(_qunlock)
       +                (*_qunlock)(l, getcallerpc(&l));
       +        else
       +                l->l.held = 0;
       +}
        
       -        mp = getqlp();
       -        p = q->tail;
       -        if(p == 0)
       -                q->head = mp;
       +void
       +rlock(RWLock *l)
       +{
       +        if(_rlock)
       +                (*_rlock)(l, 1, 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->readers++;
        }
        
        int
       -canrlock(RWLock *q)
       +canrlock(RWLock *l)
        {
       -        lock(&q->lock);
       -        if (q->writer == 0 && q->head == nil) {
       -                /* no writer; go for it */
       -                q->readers++;
       -                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
       -runlock(RWLock *q)
       +runlock(RWLock *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);
       +        if(_runlock)
       +                (*_runlock)(l, getcallerpc(&l));
       +        else
       +                l->readers--;
        }
        
        void
       -wlock(RWLock *q)
       +wlock(RWLock *l)
        {
       -        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(_wlock)
       +                (*_wlock)(l, 1, getcallerpc(&l));
                else
       -                p->next = mp;
       -        q->tail = mp;
       -        mp->next = nil;
       -        mp->state = QueuingW;
       -
       -        /* wait in kernel */
       -        mp->rend.l = &q->lock;
       -        procsleep(&mp->rend);
       -        unlock(&q->lock);
       -        assert(mp->state == Waking);
       -        unlock(&mp->inuse);
       +                l->writer = (void*)1;
        }
        
        int
       -canwlock(RWLock *q)
       +canwlock(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(_wlock)
       +                return (*_wlock)(l, 0, getcallerpc(&l));
       +        else{
       +                if(l->writer || l->readers)
       +                        return 0;
       +                l->writer = (void*)1;
                        return 1;
                }
       -        unlock(&q->lock);
       -        return 0;
        }
        
        void
       -wunlock(RWLock *q)
       +wunlock(RWLock *l)
        {
       -        QLp *p;
       -
       -        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;
       -        }
       -
       -        if(p->state != QueuingR){
       -                fprint(2, "wunlock: bad state\n");
       -                abort();
       -        }
       -
       -        /* 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);
       +        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;
        }
   DIR diff --git a/src/lib9/rendez-Darwin.c b/src/lib9/rendez-Darwin.c
       t@@ -1,2 +0,0 @@
       -#include "rendez-pthread.c"
       -
   DIR diff --git a/src/lib9/rendez-FreeBSD.c b/src/lib9/rendez-FreeBSD.c
       t@@ -1 +0,0 @@
       -#include "rendez-signal.c"
   DIR diff --git a/src/lib9/rendez-Linux.c b/src/lib9/rendez-Linux.c
       t@@ -1,5 +0,0 @@
       -#ifdef __Linux26__
       -#include "rendez-pthread.c"
       -#else
       -#include "rendez-signal.c"
       -#endif
   DIR diff --git a/src/lib9/rendez-OpenBSD.c b/src/lib9/rendez-OpenBSD.c
       t@@ -1 +0,0 @@
       -#include "rendez-signal.c"
   DIR diff --git a/src/lib9/rendez-SunOS.c b/src/lib9/rendez-SunOS.c
       t@@ -1 +0,0 @@
       -#include "rendez-pthread.c"
   DIR diff --git a/src/lib9/rendez-pthread.c b/src/lib9/rendez-pthread.c
       t@@ -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);
       -}
       -
   DIR diff --git a/src/lib9/rendez-signal.c b/src/lib9/rendez-signal.c
       t@@ -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);
       -}
   DIR diff --git a/src/lib9/rendez.c b/src/lib9/rendez.c
       t@@ -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;
       -}
   DIR diff --git a/src/lib9/tas-386.s b/src/lib9/tas-386.s
       t@@ -1,6 +0,0 @@
       -.globl _tas
       -_tas:
       -        movl $0xCAFEBABE, %eax
       -        movl 4(%esp), %ecx
       -        xchgl %eax, 0(%ecx)
       -        ret
   DIR diff --git a/src/lib9/tas-PowerMacintosh.c b/src/lib9/tas-PowerMacintosh.c
       t@@ -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;
       -}
   DIR diff --git a/src/lib9/tas-power.c b/src/lib9/tas-power.c
       t@@ -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;
       -}
   DIR diff --git a/src/lib9/tas-sun4u.s b/src/lib9/tas-sun4u.s
       t@@ -1,4 +0,0 @@
       -.globl _tas
       -_tas:
       -        retl
       -        ldstub [%o0], %o0