t[merge] - vx32 - Local 9vx git repository for patches.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 8a44751270915a0ad6e86adf68a111dd509be9be
 (DIR) parent ed98fad5e2bfe95b6f631ab547df24e4d575900c
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Fri,  4 Jul 2008 12:06:36 -0400
       
       t[merge]
       
       Diffstat:
         src/9vx/a/dat.h                     |      24 +++++++++++++++---------
         src/9vx/a/fault.c                   |       4 ++--
         src/9vx/a/sysproc.c                 |       2 ++
         src/9vx/devfs-posix.c               |      36 ++++++++++++++++++++++++++------
         src/9vx/main.c                      |      11 ++++++++++-
         src/9vx/mmu.c                       |     195 +++++++++++++++++++++++--------
         src/9vx/osx/screen.c                |      15 +++++++++++++--
         src/9vx/sched.c                     |     114 ++++++++-----------------------
         src/9vx/stub.c                      |      24 ++++++++++++++----------
         src/9vx/term.c                      |       1 +
         src/9vx/trap.c                      |      14 +++++++++-----
         src/9vx/vx32.c                      |     114 ++++++++++++++++---------------
         src/BUGS                            |       2 --
       
       13 files changed, 327 insertions(+), 229 deletions(-)
       ---
 (DIR) diff --git a/src/9vx/a/dat.h b/src/9vx/a/dat.h
       @@ -1,4 +1,5 @@
        #include <ucontext.h>
       +#include "libvx32/vx32.h"
        
        ttypedef struct BIOS32si        BIOS32si;
        ttypedef struct Conf        Conf;
       @@ -114,12 +115,14 @@ struct Conf
         *  MMU stuff in proc
         */
        #define NCOLOR 1
       +ttypedef struct Uspace Uspace;
        struct PMMU
        {
       -        ulong lo;        // Plan 9 VX
       -        ulong hi;        // Plan 9 VX
                struct vxproc *vxproc;        // Plan 9 VX
       -        struct vxmmap *vxmm;        // Plan 9 VX
       +        struct vxmem vxmem;
       +        struct vxmmap vxmm;        // Plan 9 VX
       +        Uspace *us;
       +        uchar *uzero;
        };
        
        /*
       @@ -348,7 +351,6 @@ struct DevConf
        // Plan 9 VX
        extern int traceprocs;
        extern int tracesyscalls;
       -extern uchar *uzero;
        extern int doabort;
        
        /* Pthreads-based sleep and wakeup. */
       @@ -356,12 +358,16 @@ typedef struct Psleep Psleep;
        ttypedef struct Pwaiter Pwaiter;
        struct Psleep
        {
       +        int init;
                pthread_mutex_t mutex;
       -        pthread_cond_t cond;
       -        int condinit;
                Pwaiter *waiter;
       -        int fd[2];
       -        vlong nread;
       -        vlong nwrite;
       +};
       +
       +struct Uspace
       +{
       +        Proc *p;        // proc currently mapped
       +        uchar *uzero;
       +        ulong lo;
       +        ulong hi;
        };
        
 (DIR) diff --git a/src/9vx/a/fault.c b/src/9vx/a/fault.c
       @@ -343,7 +343,7 @@ okaddr(ulong addr, ulong len, int write)
                                        continue;
                                }
                                qunlock(&s->lk);
       -                        return uzero+addr0;
       +                        return up->pmmu.uzero+addr0;
                        }
                }
                pprint("suicide: invalid address 0x%lux/%lud in sys call pc=0x%lux\n", addr, len, userpc());
       @@ -400,7 +400,7 @@ vmemchr(void *s, int c, int n)
                        a += m_;
                        n -= m_;
                        if(isuaddr(a))
       -                        uvalidaddr(a-uzero, 1, 0);
       +                        uvalidaddr(a-up->pmmu.uzero, 1, 0);
                }
        
                /* fits in one page */
 (DIR) diff --git a/src/9vx/a/sysproc.c b/src/9vx/a/sysproc.c
       @@ -379,6 +379,8 @@ sysexec(ulong *arg)
                /*
                 * Top-of-stack structure.
                 */
       +        uchar *uzero;
       +        uzero = up->pmmu.uzero;
                Tos *tos;
                ulong utos;
                utos = USTKTOP - sizeof(Tos);
 (DIR) diff --git a/src/9vx/devfs-posix.c b/src/9vx/devfs-posix.c
       @@ -4,16 +4,23 @@
        #include        <grp.h>        /* going to regret this - getgrgid is a stack smasher */
        #include        <sys/socket.h>
        #include        <sys/un.h>
       +
        #if defined(__FreeBSD__)
       -#include <sys/disk.h>
       -#include <sys/disklabel.h>
       -#include <sys/ioctl.h>
       +#include        <sys/disk.h>
       +#include        <sys/disklabel.h>
       +#include        <sys/ioctl.h>
       +#endif
       +
       +#if defined(__APPLE__)
       +#include        <sys/disk.h>
        #endif
       +
        #if defined(__linux__)
       -#include <linux/hdreg.h>
       -#include <linux/fs.h>
       -#include <sys/ioctl.h>
       +#include        <linux/hdreg.h>
       +#include        <linux/fs.h>
       +#include        <sys/ioctl.h>
        #endif
       +
        #include        "lib.h"
        #include        "mem.h"
        #include        "dat.h"
       @@ -907,6 +914,23 @@ disksize(int fd, struct stat *st)
                return 0;
        }
        
       +#elif defined(__APPLE__)
       +
       +static vlong
       +disksize(int fd, struct stat *st)
       +{
       +        uvlong bc;
       +        unsigned int bs;
       +
       +        bs = 0;
       +        bc = 0;
       +        ioctl(fd, DKIOCGETBLOCKSIZE, &bs);
       +        ioctl(fd, DKIOCGETBLOCKCOUNT, &bc);
       +        if(bs >0 && bc > 0)
       +                return bc*bs;
       +        return 0;
       +}
       +
        #else
        
        static vlong
 (DIR) diff --git a/src/9vx/main.c b/src/9vx/main.c
       @@ -36,7 +36,7 @@ extern Dev drawdevtab;
        extern Dev fsdevtab;
        extern Dev audiodevtab;
        
       -int        doabort;
       +int        doabort = 1;        // for now
        char*        argv0;
        char*        conffile = "9vx";
        Conf        conf;
       @@ -49,6 +49,7 @@ static Mach mach0;
        extern char*        localroot;
        extern int        tracemmu;
        extern int tracekdev;
       +extern int nuspace;
        static int singlethread;
        
        static void        bootinit(void);
       @@ -109,6 +110,9 @@ main(int argc, char **argv)
                case 'S':
                        tracesyscalls++;
                        break;
       +        case 'U':
       +                nuspace = atoi(EARGF(usage()));
       +                break;
                case 'X':
                        vx32_debugxlate++;
                        break;
       @@ -419,7 +423,9 @@ showexec(ulong sp)
        {
                ulong *a, *argv;
                int i, n;
       +        uchar *uzero;
                
       +        uzero = up->pmmu.uzero;
                iprint("showexec %p\n", sp);
                if(sp >= USTKTOP || sp < USTKTOP-USTKSIZE)
                        panic("showexec: bad sp");
       @@ -510,6 +516,7 @@ sigsegv(int signo, siginfo_t *info, void *v)
                int read;
                ulong addr, eip, esp;
                ucontext_t *uc;
       +        uchar *uzero;
        
                if(m == nil)
                        panic("sigsegv: m == nil");
       @@ -518,6 +525,8 @@ sigsegv(int signo, siginfo_t *info, void *v)
                if(up == nil)
                        panic("sigsegv: up == nil");
        
       +        uzero = up->pmmu.uzero;
       +
                uc = v;
        #if defined(__APPLE__)
                mcontext_t mc;
 (DIR) diff --git a/src/9vx/mmu.c b/src/9vx/mmu.c
       @@ -30,14 +30,19 @@ int tracemmu;
        
        static int pagefile;
        static char* pagebase;
       -uchar *uzero;
       +
       +static Uspace uspace[16];
       +static Uspace *ulist[nelem(uspace)];
       +int nuspace = 1;
        
        int
        isuaddr(void *v)
        {
                uchar *p;
       +        uchar *uzero;
                
                p = v;
       +        uzero = up->pmmu.uzero;
                return uzero <= p && p < uzero+USTKTOP;
        }
        
       @@ -46,7 +51,7 @@ isuaddr(void *v)
         * The point is to reserve the space so that
         * nothing else ends up there later.
         */
       -static void
       +static void*
        mapzero(void)
        {
                int fd;
       @@ -55,20 +60,16 @@ mapzero(void)
                /* First try mmaping /dev/zero.  Some OS'es don't allow this. */
                if((fd = open("/dev/zero", O_RDONLY)) >= 0){
                        v = mmap(nil, USTKTOP, PROT_NONE, MAP_PRIVATE, fd, 0);
       -                if(v != MAP_FAILED){
       -                        uzero = v;
       -                        return;
       -                }
       +                if(v != MAP_FAILED)
       +                        return v;
                }
                
                /* Next try an anonymous map. */
                v = mmap(nil, USTKTOP, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
       -        if(v != MAP_FAILED){
       -                uzero = v;
       -                return;
       -        }
       -        
       -        panic("mapzero: cannot reserve process address space");
       +        if(v != MAP_FAILED)
       +                return v;
       +
       +        return nil;
        }
        
        void
       @@ -76,8 +77,8 @@ mmuinit(void)
        {
                char tmp[] = "/var/tmp/9vx.pages.XXXXXX";
                void *v;
       -
       -        mapzero();
       +        int i;
       +        
                if((pagefile = mkstemp(tmp)) < 0)
                        panic("mkstemp: %r");
                if(ftruncate(pagefile, MEMSIZE) < 0)
       @@ -92,6 +93,17 @@ mmuinit(void)
                        panic("mmap pagefile: %r");
                pagebase = v;
        
       +        if(nuspace <= 0)
       +                nuspace = 1;
       +        if(nuspace > nelem(uspace))
       +                nuspace = nelem(uspace);
       +        for(i=0; i<nuspace; i++){
       +                uspace[i].uzero = mapzero();
       +                if(uspace[i].uzero == nil)
       +                        panic("mmap address space %d", i);
       +                ulist[i] = &uspace[i];
       +        }
       +
                conf.mem[0].base = 0;
                conf.mem[0].npage = MEMSIZE / BY2PG;
                
       @@ -128,23 +140,15 @@ kunmap(KMap *k)
        }
        
        /*
       - * The process whose address space we've got mapped.
       - * We cache our own copy so that entering the scheduler
       - * and coming back out running the same process doesn't
       - * cause unnecessary unmapping and remapping.
       - */
       -static Proc *mmup;
       -
       -/*
         * Flush the current address space.
         */
        static void
       -mmapflush(void)
       +mmapflush(Uspace *us)
        {
                m->flushmmu = 0;
        
                /* Nothing mapped? */
       -        if(mmup == nil || mmup->pmmu.lo > mmup->pmmu.hi)
       +        if(us == nil || us->lo > us->hi || us->uzero == nil)
                        return;
        
        #ifdef __FreeBSD__
       @@ -154,20 +158,20 @@ mmapflush(void)
                         * tell whether a page is mapped, so we have to remap
                         * something with no pages here. 
                         */
       -                if(mmap(uzero, mmup->pmmu.hi+BY2PG, PROT_NONE, 
       +                if(mmap(us->uzero, us->hi+BY2PG, PROT_NONE, 
                                        MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) == MAP_FAILED)
                                panic("mmapflush mmap: %r");
       -                mmup->pmmu.lo = 0x80000000UL;
       -                mmup->pmmu.hi = 0;
       +                us->lo = 0x80000000UL;
       +                us->hi = 0;
                        return;
                }
        #endif
        
                /* Clear only as much as got mapped. */
       -        if(mprotect(uzero, mmup->pmmu.hi+BY2PG, PROT_NONE) < 0)
       +        if(mprotect(us->uzero, us->hi+BY2PG, PROT_NONE) < 0)
                        panic("mmapflush mprotect: %r");
       -        mmup->pmmu.lo = 0x80000000UL;
       -        mmup->pmmu.hi = 0;
       +        us->lo = 0x80000000UL;
       +        us->hi = 0;
        }
        
        /*
       @@ -178,13 +182,15 @@ void
        putmmu(ulong va, ulong pa, Page *p)
        {
                int prot;
       -        PMMU *pmmu;
       +        Uspace *us;
        
                if(tracemmu || (pa&~(PTEWRITE|PTEVALID)) != p->pa)
                        print("putmmu va %lux pa %lux p->pa %lux\n", va, pa, p->pa);
        
                assert(p->pa < MEMSIZE && pa < MEMSIZE);
                assert(up);
       +        us = up->pmmu.us;
       +        assert(us);
        
                /* Map the page */
                prot = PROT_READ;
       @@ -192,21 +198,20 @@ putmmu(ulong va, ulong pa, Page *p)
                        prot |= PROT_WRITE;
                pa &= ~(BY2PG-1);
                va  &= ~(BY2PG-1);
       -        if(mmap(uzero+va, BY2PG, prot, MAP_FIXED|MAP_SHARED,
       +        if(mmap(us->uzero+va, BY2PG, prot, MAP_FIXED|MAP_SHARED,
                                pagefile, pa) == MAP_FAILED)
                        panic("putmmu");
                
                /* Record high and low address range for quick unmap. */
       -        pmmu = &up->pmmu;
       -        if(pmmu->lo > va)
       -                pmmu->lo = va;
       -        if(pmmu->hi < va)
       -                pmmu->hi = va;
       +        if(us->lo > va)
       +                us->lo = va;
       +        if(us->hi < va)
       +                us->hi = va;
        //        printlinuxmaps();
        }
        
        /*
       - * The memory maps have changed.  Flush all cached state.
       + * The memory maps have changed for up.  Flush all cached state.
         */
        void
        flushmmu(void)
       @@ -214,9 +219,78 @@ flushmmu(void)
                if(tracemmu)
                        print("flushmmu\n");
        
       -        if(up)
       +        if(up){
                        vxproc_flush(up->pmmu.vxproc);
       -        mmapflush();
       +                mmapflush(up->pmmu.us);
       +        }
       +}
       +
       +void
       +usespace(Uspace *us)
       +{
       +        int i;
       +        
       +        for(i=0; i<nuspace; i++)
       +                if(ulist[i] == us){
       +                        while(i > 0){
       +                                ulist[i] = ulist[i-1];
       +                                i--;
       +                        }
       +                        ulist[0] = us;
       +                        break;
       +                }
       +}
       +
       +Uspace*
       +getspace(Proc *p)
       +{
       +        Uspace *us;
       +        
       +        us = ulist[nuspace-1];
       +        if(us->p){
       +                if(tracemmu)
       +                        print("^^^^^^^^^^ %ld %s [evict %d]\n", us->p->pid, us->p->text, us - uspace);
       +                mmapflush(us);
       +        }
       +        us->p = p;
       +        p->pmmu.vxmm.base = us->uzero;
       +        p->pmmu.uzero = us->uzero;
       +        p->pmmu.us = us;
       +        usespace(us);
       +        return us;
       +}
       +
       +void
       +ttakespace(Proc *p, Uspace *us)
       +{
       +        usespace(us);
       +        if(us->p == p)
       +                return;
       +        if(tracemmu){
       +                if(us->p)
       +                        print("^^^^^^^^^^ %ld %s [steal %d]\n", us->p->pid, us->p->text, us - uspace);
       +        }
       +        us->p = p;
       +        mmapflush(us);
       +}
       +
       +void
       +putspace(Uspace *us)
       +{
       +        int i;
       +
       +        mmapflush(us);
       +        us->p->pmmu.us = nil;
       +        us->p->pmmu.uzero = nil;
       +        us->p->pmmu.vxmm.base = nil;
       +        us->p = nil;
       +        for(i=0; i<nuspace; i++)
       +                if(ulist[i] == us){
       +                        while(++i < nuspace)
       +                                ulist[i-1] = ulist[i];
       +                        ulist[i-1] = us;
       +                        break;
       +                }
        }
        
        /*
       @@ -231,15 +305,31 @@ mmuswitch(Proc *p)
                 * one we were just in.  Also, kprocs don't count --
                 * only the guys on cpu0 do.
                 */
       -        if(!p->kp && (mmup != p || p->newtlb || m->flushmmu)){
       -                if(0) print("^^^^^^^^^^ %ld %s\n========== %ld %s\n",
       -                        mmup ? mmup->pid : 0, mmup? mmup->text : "",
       -                        p->pid, p->text);
       -                /* No vxproc_flush - vxproc cache is okay */
       -                mmapflush();
       +        if(p->kp)
       +                return;
       +        
       +        if(tracemmu)
       +                print("mmuswitch %ld %s\n", p->pid, p->text);
       +
       +        if(p->pmmu.us && p->pmmu.us->p == p){
       +                if(tracemmu) print("---------- %ld %s [%d]\n",
       +                        p->pid, p->text, p->pmmu.us - uspace);
       +                usespace(p->pmmu.us);
       +                if(!p->newtlb && !m->flushmmu){
       +                        usespace(p->pmmu.us);
       +                        return;
       +                }
       +                mmapflush(p->pmmu.us);
                        p->newtlb = 0;
       -                mmup = p;
       +                return;
                }
       +
       +        if(p->pmmu.us == nil)
       +                getspace(p);
       +        else
       +                takespace(p, p->pmmu.us);
       +        if(tracemmu) print("========== %ld %s [%d]\n",
       +                p->pid, p->text, p->pmmu.us - uspace);
        }
        
        /*
       @@ -250,11 +340,16 @@ mmurelease(Proc *p)
        {
                if(p->kp)
                        return;
       +        if(tracemmu)
       +                print("mmurelease %ld %s\n", p->pid, p->text);
                if(p->pmmu.vxproc)
                        vxproc_flush(p->pmmu.vxproc);
       -        if(p == mmup || m->flushmmu){
       -                mmapflush();
       -                mmup = nil;
       +        if(p->pmmu.us){
       +                if(tracemmu)
       +                        print("^^^^^^^^^^ %ld %s [release %d]\n", p->pid, p->text, p->pmmu.us - uspace);
       +                putspace(p->pmmu.us);
       +                if(m->flushmmu)
       +                        mmapflush(p->pmmu.us);
                }
        }
        
 (DIR) diff --git a/src/9vx/osx/screen.c b/src/9vx/osx/screen.c
       @@ -316,7 +316,7 @@ mouseevent(EventRef event)
                        return eventNotHandledErr;
                }
        
       -        mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons, msec());
       +        mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons|wheel, msec());
                return noErr;        
        }
        
       @@ -407,6 +407,15 @@ kbdevent(EventRef event)
                                k = keycvt[code];
                        if(k >= 0)
                                latin1putc(k, kputc);
       +                else{
       +                        UniChar uc;
       +                        OSStatus s;
       +                        
       +                        s = GetEventParameter(event, kEventParamKeyUnicodes,
       +                                typeUnicodeText, nil, sizeof uc, nil, &uc);
       +                        if(s == noErr)
       +                                kputc(uc);
       +                }
                        break;
        
                case kEventRawKeyModifiersChanged:
       @@ -501,6 +510,7 @@ fullscreen(void)
        {
                static Ptr restore;
                static WindowRef oldwindow;
       +        GDHandle device;
        
                if(osx.isfullscreen){
                        EndFullScreen(restore, 0);
       @@ -510,7 +520,8 @@ fullscreen(void)
                }else{
                        HideWindow(osx.window);
                        oldwindow = osx.window;
       -                BeginFullScreen(&restore, 0, 0, 0, &osx.window, 0, 0);
       +                GetWindowGreatestAreaDevice(osx.window, kWindowTitleBarRgn, &device, nil);
       +                BeginFullScreen(&restore, device, 0, 0, &osx.window, 0, 0);
                        osx.isfullscreen = 1;
                        osx.fullscreentime = msec();
                }
 (DIR) diff --git a/src/9vx/sched.c b/src/9vx/sched.c
       @@ -61,7 +61,7 @@ noidlehands(void)
                if(m->machno == 0)
                        return;
                plock(&idling);
       -        idlewakeup++;
       +        idlewakeup = 1;
                pwakeup(&idling);
                punlock(&idling);
        }
       @@ -154,7 +154,8 @@ runproc(void)
                        kprocq.tail = nil;
                kprocq.n--;
                if(traceprocs)
       -                iprint("cpu%d: runproc %ld %s [%d %d]\n", m->machno, p->pid, p->text, kprocq.n, nrunproc);
       +                iprint("cpu%d: runproc %ld %s [%d %d]\n",
       +                        m->machno, p->pid, p->text, kprocq.n, nrunproc);
                unlock(&kprocq.lk);
                punlock(&run);
                return p;
       @@ -162,48 +163,8 @@ runproc(void)
        
        /*
         * Host OS process sleep and wakeup.
       - * This is complicated.
       - *
       - * Ideally, we'd just use a single pthread_cond_t, have everyone
       - * pthread_cond_wait on it, and use pthread_cond_signal
       - * to wake people up.  Unfortunately, that fails miserably
       - * on OS X: sometimes the wakeups just plain get missed.
       - * Perhaps it has something to do with all the signals that
       - * are flying around.
       - *
       - * To work around the OS X pthreads problems, there is a
       - * second implementation turned on by #defining PIPES to 1.
       - * This implementation uses a pipe and reads and writes bytes
       - * from the pipe to implement sleep and wakeup.  Perhaps not
       - * surprisingly, the naive implementation of this hangs:
       - * reads miss writes.  Instead, the actual implementation uses
       - * select to poll whether the read would succeed, and once a
       - * second it tries the read even if select doesn't think it will.
       - * This timeout lets us make progress when an event gets missed
       - * (happens only rarely).  This is enough to get things going on
       - * OS X.
       - *
       - * On my Athlon 64 running Linux,
       - * time to run mk -a in /sys/src/9/pc:
       - *
       - *         90s        default implementation (one pthread_cond_t)
       - *         85s        WAITERS (pthread_cond_t for each waiter)
       - *         88s        PIPES
       - *
       - * I implemented per-thread pthread_cond_t's to see if they
       - * were any faster on non-OS X systems, but I can't see any
       - * difference.  Running the WAITERS version on OS X causes
       - * mysterious crashes.  I'm thoroughly confused.  
         */
       -#define        PIPES        0
       -#define        WAITERS        1
       -
       -#ifdef __APPLE__
       -#undef        PIPES
       -#define        PIPES        1
       -#undef        WAITERS
       -#define        WAITERS        0
       -#endif
       +static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
        
        struct Pwaiter
        {
       @@ -215,78 +176,59 @@ struct Pwaiter
        void
        plock(Psleep *p)
        {
       -        pthread_mutex_lock(&p->mutex);
       -        if(!p->condinit){
       -                p->condinit = 1;
       -                pthread_cond_init(&p->cond, nil);
       -        }
       -#if PIPES
       -        if(p->fd[1] == 0){
       -                pipe(p->fd);
       -                fcntl(p->fd[0], F_SETFL, fcntl(p->fd[0], F_GETFL)|O_NONBLOCK);
       +        int r;
       +
       +        if(!p->init){
       +                if((r = pthread_mutex_lock(&initmutex)) != 0)
       +                        panic("pthread_mutex_lock initmutex: %d", r);
       +                if(!p->init){
       +                        p->init = 1;
       +                        pthread_mutex_init(&p->mutex, nil);
       +                }
       +                if((r = pthread_mutex_unlock(&initmutex)) != 0)
       +                        panic("pthread_mutex_unlock initmutex: %d", r);
                }
       -#endif
       +        if((r = pthread_mutex_lock(&p->mutex)) != 0)
       +                panic("pthread_mutex_lock: %d", r);
        }
        
        void
        punlock(Psleep *p)
        {
       -        pthread_mutex_unlock(&p->mutex);
       +        int r;
       +
       +        if((r = pthread_mutex_unlock(&p->mutex)) != 0)
       +                panic("pthread_mutex_unlock: %d", r);
        }
        
        void
        psleep(Psleep *p)
        {
       -#if PIPES
       -        p->nread++;
       -        punlock(p);
       -        char c;
       -        while(read(p->fd[0], &c, 1) < 1){
       -                struct pollfd pfd;
       -                pfd.fd = p->fd[0];
       -                pfd.events = POLLIN;
       -                pfd.revents = 0;
       -                poll(&pfd, 1, 1000);
       -        }
       -        plock(p);
       -#elif WAITERS
       +        int r;
                Pwaiter w;
       +
                memset(&w, 0, sizeof w);
                pthread_cond_init(&w.cond, nil);
                w.next = p->waiter;
                p->waiter = &w;
                while(!w.awake)
       -                pthread_cond_wait(&w.cond, &p->mutex);
       +                if((r = pthread_cond_wait(&w.cond, &p->mutex)) != 0)
       +                        panic("pthread_cond_wait: %d", r);
                pthread_cond_destroy(&w.cond);
       -#else
       -        pthread_cond_wait(&p->cond, &p->mutex);
       -#endif
        }
        
        void
        pwakeup(Psleep *p)
        {
       -#if PIPES
       -        char c = 0;
       -        int nbad = 0;
       -        if(p->nwrite < p->nread){
       -                p->nwrite++;
       -                while(write(p->fd[1], &c, 1) < 1){
       -                        if(++nbad%100 == 0)
       -                                iprint("pwakeup: write keeps failing\n");
       -                }
       -        }
       -#elif WAITERS
       +        int r;
                Pwaiter *w;
        
                w = p->waiter;
                if(w){
                        p->waiter = w->next;
                        w->awake = 1;
       -                pthread_cond_signal(&w->cond);
       +                if((r = pthread_cond_signal(&w->cond)) != 0)
       +                        panic("pthread_cond_signal: %d", r);
                }
       -#else
       -        pthread_cond_signal(&p->cond);
       -#endif
        }
        
 (DIR) diff --git a/src/9vx/stub.c b/src/9vx/stub.c
       @@ -276,18 +276,19 @@ _tas(void *x)
        int
        lock(Lock *lk)
        {
       -        int i, printed;
       +        int i, j, printed;
                
                for(i=0; i<1000; i++){
                        if(canlock(lk))
                                return 1;
                        sched_yield();
                }
       -        for(i=0; i<100; i++){
       -                if(canlock(lk))
       -                        return 1;
       -                microdelay(10);
       -        }
       +        for(j=10; j<=1000; j*=10)
       +                for(i=0; i<10; i++){
       +                        if(canlock(lk))
       +                                return 1;
       +                        microdelay(j);
       +                }
                printed = 0;
                for(;;){
                        if(canlock(lk))
       @@ -295,7 +296,7 @@ lock(Lock *lk)
                        if(!printed++)
                                iprint("cpu%d deadlock? %p caller=%p\n",
                                        m->machno, lk, getcallerpc(&lk));
       -                microdelay(1000000);
       +                microdelay(10000);
                }
                return 0;
        }
       @@ -497,11 +498,14 @@ panic(char *fmt, ...)
                buf[n] = '\n';
                write(2, buf, n+1);
                if(doabort){
       -#ifndef __APPLE__
       -                abort();
       -#endif
       +#ifdef __APPLE__
       +                fprint(2, "sleeping, so you can attach gdb to pid %d\n", (int)getpid());
                        for(;;)
                                microdelay(1000000);
       +#else
       +                fprint(2, "aborting, to dump core.\n");
       +                abort();
       +#endif
                }
                exit(0);
        }
 (DIR) diff --git a/src/9vx/term.c b/src/9vx/term.c
       @@ -208,6 +208,7 @@ termscroll(void)
                r1.min.y += dy;
                memimagedraw(term.screen, r0, term.screen, r1.min,
                        memopaque, ZP, S);
       +        r1.min.y = r0.max.y;
                memimagedraw(term.screen, r1, term.bg, ZP, memopaque, ZP, S);
                addflush(r0);
                addflush(r1);
 (DIR) diff --git a/src/9vx/trap.c b/src/9vx/trap.c
       @@ -30,7 +30,7 @@ kexit(Ureg *ureg)
                Tos *tos;
        
                /* precise time accounting, kernel exit */
       -        tos = (Tos*)(uzero+USTKTOP-sizeof(Tos));
       +        tos = (Tos*)(up->pmmu.uzero+USTKTOP-sizeof(Tos));
                cycles(&t);
                tos->kcycles += t - up->kentry;
                tos->pcycles = up->pcycles;
       @@ -90,7 +90,7 @@ trap(Ureg *ureg)
                
                case VXTRAP_SOFT+0x40:        /* int $0x40 - system call */
                        if(tracesyscalls){
       -                        ulong *sp = (ulong*)(uzero + ureg->usp);
       +                        ulong *sp = (ulong*)(up->pmmu.uzero + ureg->usp);
                                print("%d [%s] %s %#lux %08lux %08lux %08lux %08lux\n",
                                        up->pid, up->text,
                                        sysctab[ureg->ax], sp[0], sp[1], sp[2], sp[3]);
       @@ -262,7 +262,7 @@ syscall(Ureg *ureg)
                up->psstate = 0;
        
                if(scallnr == NOTED)
       -                noted(ureg, *(ulong*)(uzero + sp+BY2WD));
       +                noted(ureg, *(ulong*)(up->pmmu.uzero + sp+BY2WD));
        
                if(scallnr!=RFORK && (up->procctl || up->nnote)){
                        splhi();
       @@ -335,6 +335,8 @@ notify(Ureg* ureg)
                        pexit("Suicide", 0);
                }
        
       +        uchar *uzero;
       +        uzero = up->pmmu.uzero;
                upureg = (void*)(uzero + sp);
                memmove(upureg, ureg, sizeof(Ureg));
                *(ulong*)(uzero + sp-BY2WD) = up->ureg;        /* word under Ureg is old up->ureg */
       @@ -383,6 +385,8 @@ noted(Ureg* ureg, ulong arg0)
                        pexit("Suicide", 0);
                }
                
       +        uchar *uzero;
       +        uzero = up->pmmu.uzero;
                oureg = up->ureg;
                nureg = (Ureg*)(uzero + up->ureg);
        
       @@ -442,11 +446,11 @@ execregs(ulong entry, ulong ssize, ulong nargs)
                up->fpstate = FPinit;
                fpoff();
        
       -        sp = (ulong*)(uzero + USTKTOP - ssize);
       +        sp = (ulong*)(up->pmmu.uzero + USTKTOP - ssize);
                *--sp = nargs;
        
                ureg = up->dbgreg;
       -        ureg->usp = (uchar*)sp - uzero;
       +        ureg->usp = (uchar*)sp - up->pmmu.uzero;
        //showexec(ureg->usp);
                ureg->pc = entry;
                return USTKTOP-sizeof(Tos);                /* address of kernel/user shared data */
 (DIR) diff --git a/src/9vx/vx32.c b/src/9vx/vx32.c
       @@ -17,7 +17,6 @@
        #include "u.h"
        #include <pthread.h>
        #include <sys/mman.h>
       -#include "libvx32/vx32.h"
        #include "lib.h"
        #include "mem.h"
        #include "dat.h"
       @@ -50,47 +49,6 @@ vx32sysr1(void)
        }
        
        /*
       - * Vxnewproc is called at the end of newproc
       - * to fill in vx32-specific entries in the Proc struct
       - * before it gets used.
       - */
       -void
       -vxnewproc(Proc *p)
       -{
       -        PMMU *pm;
       -        
       -        pm = &p->pmmu;
       -
       -        /*
       -         * Kernel procs don't need vxprocs; if this proc
       -         * already has one, take it away.  Also, give
       -         * kernel procs very large stacks so they can call
       -         * into non-thread-friendly routines like x11 
       -         * and getgrgid.
       -         */
       -        if(p->kp){
       -                if(pm->vxproc){
       -                        pm->vxproc->mem = nil;
       -                        vxproc_free(pm->vxproc);
       -                        pm->vxproc = nil;
       -                }
       -                free(p->kstack);
       -                p->kstack = nil;
       -                p->kstack = smalloc(512*1024);
       -                return;
       -        }
       -
       -        pm->lo = 0x80000000UL;
       -        pm->hi = 0;
       -        if(pm->vxproc == nil){
       -                pm->vxproc = vxproc_alloc();
       -                if(pm->vxproc == nil)
       -                        panic("vxproc_alloc");
       -                pm->vxproc->mem = &thevxmem;
       -        }
       -}
       -
       -/*
         * Vx32 hooks to read, write, map, unmap, and check permissions
         * on user memory.  Normally these are more involved, but we're
         * using the processor to do everything.
       @@ -98,29 +56,21 @@ vxnewproc(Proc *p)
        static ssize_t
        vmread(vxmem *vm, void *data, uint32_t addr, uint32_t len)
        {
       -        memmove(data, uzero+addr, len);
       +        memmove(data, vm->mapped->base+addr, len);
                return len;
        }
        
        static ssize_t
        vmwrite(vxmem *vm, const void *data, uint32_t addr, uint32_t len)
        {
       -        memmove(uzero+addr, data, len);
       +        memmove(vm->mapped->base+addr, data, len);
                return len;
        }
        
       -static vxmmap thevxmmap =
       -{
       -        1,
       -        (void*)-1,        /* to be filled in with user0 */
       -        USTKTOP,
       -};
       -
        static vxmmap*
        vmmap(vxmem *vm, uint32_t flags)
        {
       -        thevxmmap.base = uzero;
       -        return &thevxmmap;
       +        return vm->mapped;
        }
        
        static void
       @@ -131,6 +81,14 @@ vmunmap(vxmem *vm, vxmmap *mm)
        static int
        vmcheckperm(vxmem *vm, uint32_t addr, uint32_t len, uint32_t perm, uint32_t *out_faultva)
        {
       +        if(addr >= USTKTOP){
       +                *out_faultva = addr;
       +                return 0;
       +        }
       +        if(addr+len < addr || addr +len > USTKTOP){
       +                *out_faultva = USTKTOP;
       +                return 0;
       +        }
                /* All is allowed - handle faults as they happen. */
                return 1;
        }
       @@ -164,6 +122,50 @@ static vxmem thevxmem =
                vmfree,
        };
        
       +/*
       + * Vxnewproc is called at the end of newproc
       + * to fill in vx32-specific entries in the Proc struct
       + * before it gets used.
       + */
       +void
       +vxnewproc(Proc *p)
       +{
       +        PMMU *pm;
       +        
       +        pm = &p->pmmu;
       +
       +        /*
       +         * Kernel procs don't need vxprocs; if this proc
       +         * already has one, take it away.  Also, give
       +         * kernel procs very large stacks so they can call
       +         * into non-thread-friendly routines like x11 
       +         * and getgrgid.
       +         */
       +        if(p->kp){
       +                if(pm->vxproc){
       +                //        vxunmap(p);
       +                        assert(pm->uzero == nil);
       +                        pm->vxproc->mem = nil;
       +                        vxproc_free(pm->vxproc);
       +                        pm->vxproc = nil;
       +                }
       +                free(p->kstack);
       +                p->kstack = nil;
       +                p->kstack = smalloc(512*1024);
       +                return;
       +        }
       +
       +        if(pm->vxproc == nil){
       +                pm->vxproc = vxproc_alloc();
       +                if(pm->vxproc == nil)
       +                        panic("vxproc_alloc");
       +                pm->vxproc->mem = &pm->vxmem;
       +                pm->vxmem = thevxmem;
       +                pm->vxmem.mapped = &pm->vxmm;
       +                memset(&pm->vxmm, 0, sizeof pm->vxmm);
       +        }
       +}
       +
        static void
        setclock(int start)
        {
       @@ -224,7 +226,7 @@ touser(void *initsp)
                         * Optimization: try to fault in code page and stack
                         * page right now, since we're likely to need them.
                         */
       -                if(up->pmmu.hi == 0){
       +                if(up->pmmu.us->hi == 0){
                                fault(vp->cpu->eip, 1);
                                fault(vp->cpu->reg[ESP], 0);
                        }
       @@ -267,11 +269,11 @@ touser(void *initsp)
                                addr = (uchar*)vp->cpu->trapva;
                                if(traceprocs)
                                        print("fault %p read=%d\n", addr, read);
       -                        if(isuaddr(addr) && fault(addr - uzero, read) >= 0)
       +                        if(isuaddr(addr) && fault(addr - up->pmmu.uzero, read) >= 0)
                                        continue;
                                print("%ld %s: unhandled fault va=%lux [%lux] eip=%lux\n",
                                        up->pid, up->text,
       -                                addr - uzero, vp->cpu->trapva, vp->cpu->eip);
       +                                addr - up->pmmu.uzero, vp->cpu->trapva, vp->cpu->eip);
                                proc2ureg(vp, &u);
                                dumpregs(&u);
                                if(doabort)
 (DIR) diff --git a/src/BUGS b/src/BUGS
       @@ -9,6 +9,4 @@ need to do a better job mapping SIGFPE back to hardware floating-point errors
        ---
        gs spins on startup, cause unknown.  (run "gs", no arguments)
        
       -blank line inserted when kernel terminal scrolls
       -
        can cause sigsegv panic resizing the window, rarely