tOpenBSD/power support. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit cea10000c59882b43525e4fd4fb17a55b7dba1c1
 (DIR) parent e9ad899486adb4c561e682ced74ac0cb1c4539fc
 (HTM) Author: rsc <devnull@localhost>
       Date:   Sun,  1 May 2005 18:38:12 +0000
       
       OpenBSD/power support.
       
       Diffstat:
         A src/libthread/BSD.c                 |     384 +++++++++++++++++++++++++++++++
         M src/libthread/FreeBSD.c             |     364 +------------------------------
         A src/libthread/OpenBSD-power-asm.S   |     125 +++++++++++++++++++++++++++++++
         A src/libthread/OpenBSD-power.c       |      38 +++++++++++++++++++++++++++++++
         A src/libthread/OpenBSD.c             |       4 ++++
         M src/libthread/mkfile                |       7 +++----
         R src/libthread/Darwin-ucontext.h ->… |       0 
         M src/libthread/sysofiles.sh          |       3 +++
         M src/libthread/threadimpl.h          |      11 +++++++++--
       
       9 files changed, 567 insertions(+), 369 deletions(-)
       ---
 (DIR) diff --git a/src/libthread/BSD.c b/src/libthread/BSD.c
       t@@ -0,0 +1,384 @@
       +#undef exits
       +#undef _exits
       +
       +extern int __isthreaded;
       +
       +/*
       + * spin locks
       + */
       +extern int _tas(int*);
       +
       +void
       +_threadunlock(Lock *l, ulong pc)
       +{
       +        USED(pc);
       +
       +        l->held = 0;
       +}
       +
       +int
       +_threadlock(Lock *l, int block, ulong pc)
       +{
       +        int i;
       +
       +        USED(pc);
       +
       +        /* once fast */
       +        if(!_tas(&l->held))
       +                return 1;
       +        if(!block)
       +                return 0;
       +
       +        /* a thousand times pretty fast */
       +        for(i=0; i<1000; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                sched_yield();
       +        }
       +        /* increasingly slow */
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(1);
       +        }
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(10);
       +        }
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(100);
       +        }
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(1000);
       +        }
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(10*1000);
       +        }
       +        /* now nice and slow */
       +        for(i=0; i<1000; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(100*1000);
       +        }
       +        /* take your time */
       +        while(_tas(&l->held))
       +                usleep(1000*1000);
       +        return 1;
       +}
       +
       +/*
       + * For 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);
       +}
       +
       +/*
       + * sleep and wakeup
       + */
       +static void
       +ign(int x)
       +{
       +        USED(x);
       +}
       +
       +static 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(_Procrendez *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.
       +         */
       +again:
       +        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.
       +         */
       +        lock(r->l);
       +        ignusr1(1);
       +        if(r->asleep && r->pid == getpid()){
       +                /* Didn't really wake up - signal from something else */
       +                goto again;
       +        }
       +}
       +
       +void
       +_procwakeup(_Procrendez *r)
       +{
       +        if(r->asleep){
       +                r->asleep = 0;
       +                assert(r->pid >= 1);
       +                kill(r->pid, SIGUSR1);
       +        }
       +}
       +
       +void
       +_procwakeupandunlock(_Procrendez *r)
       +{
       +        _procwakeup(r);
       +        unlock(r->l);
       +}
       +
       +
       +/*
       + * process creation and exit
       + */
       +typedef struct Stackfree Stackfree;
       +struct Stackfree
       +{
       +        Stackfree        *next;
       +        int        pid;
       +};
       +static Lock stacklock;
       +static Stackfree *stackfree;
       +
       +static void
       +delayfreestack(uchar *stk)
       +{
       +        Stackfree *sf;
       +
       +        sf = (Stackfree*)stk;
       +        sf->pid = getpid();
       +        lock(&stacklock);
       +        sf->next = stackfree;
       +        stackfree = sf;
       +        unlock(&stacklock);
       +}
       +
       +static void
       +dofreestacks(void)
       +{
       +        Stackfree *sf, *last, *next;
       +
       +        if(stackfree==nil || !canlock(&stacklock))
       +                return;
       +
       +        for(last=nil,sf=stackfree; sf; last=sf,sf=next){
       +                next = sf->next;
       +                if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
       +                        free(sf);
       +                        if(last)
       +                                last->next = next;
       +                        else
       +                                stackfree = next;
       +                        sf = last;
       +                }
       +        }
       +        unlock(&stacklock);
       +}
       +
       +static int
       +startprocfn(void *v)
       +{
       +        void **a;
       +        uchar *stk;
       +        void (*fn)(void*);
       +        Proc *p;
       +
       +        a = (void**)v;
       +        fn = a[0];
       +        p = a[1];
       +        stk = a[2];
       +        free(a);
       +        p->osprocid = getpid();
       +
       +        (*fn)(p);
       +
       +        delayfreestack(stk);
       +        _exit(0);
       +        return 0;
       +}
       +
       +void
       +_procstart(Proc *p, void (*fn)(Proc*))
       +{
       +        void **a;
       +        uchar *stk;
       +        int pid;
       +
       +        dofreestacks();
       +        a = malloc(3*sizeof a[0]);
       +        if(a == nil)
       +                sysfatal("_procstart malloc: %r");
       +        stk = malloc(65536);
       +        if(stk == nil)
       +                sysfatal("_procstart malloc stack: %r");
       +
       +        a[0] = fn;
       +        a[1] = p;
       +        a[2] = stk;
       +
       +        pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);
       +        if(pid < 0){
       +                fprint(2, "_procstart rfork_thread: %r\n");
       +                abort();
       +        }
       +}
       +
       +static char *threadexitsmsg;
       +void
       +sigusr2handler(int s)
       +{
       +/*        fprint(2, "%d usr2 %d\n", time(0), getpid()); */
       +        if(threadexitsmsg)
       +                _exits(threadexitsmsg);
       +}
       +
       +void
       +threadexitsall(char *msg)
       +{
       +        static int pid[1024];
       +        int i, npid, mypid;
       +        Proc *p;
       +
       +        if(msg == nil)
       +                msg = "";
       +        mypid = getpid();
       +        lock(&_threadprocslock);
       +        threadexitsmsg = msg;
       +        npid = 0;
       +        for(p=_threadprocs; p; p=p->next)
       +                if(p->osprocid != mypid && p->osprocid >= 1)
       +                        pid[npid++] = p->osprocid;
       +        for(i=0; i<npid; i++)
       +                kill(pid[i], SIGUSR2);
       +        unlock(&_threadprocslock);
       +        exits(msg);
       +}
       +
       +/*
       + * per-process data, indexed by pid
       + */
       +typedef struct Perproc Perproc;
       +struct Perproc
       +{
       +        int                pid;
       +        Proc        *proc;
       +};
       +
       +static Lock perlock;
       +static Perproc perproc[1024];
       +#define P ((Proc*)-1)
       +
       +static Perproc*
       +myperproc(void)
       +{
       +        int i, pid, h;
       +        Perproc *p;
       +
       +        pid = getpid();
       +        h = pid%nelem(perproc);
       +        for(i=0; i<nelem(perproc); i++){
       +                p = &perproc[(i+h)%nelem(perproc)];
       +                if(p->pid == pid)
       +                        return p;
       +                if(p->pid == 0){
       +                        print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
       +                        break;
       +                }
       +        }
       +        fprint(2, "myperproc %d: cannot find self\n", pid);
       +        abort();
       +        return nil;
       +}
       +
       +static Perproc*
       +newperproc(void)
       +{
       +        int i, pid, h;
       +        Perproc *p;
       +
       +        lock(&perlock);
       +        pid = getpid();
       +        h = pid%nelem(perproc);
       +        for(i=0; i<nelem(perproc); i++){
       +                p = &perproc[(i+h)%nelem(perproc)];
       +                if(p->pid == pid || p->pid == -1 || p->pid == 0){
       +                        p->pid = pid;
       +                        unlock(&perlock);
       +                        return p;
       +                }
       +        }
       +        fprint(2, "newperproc %d: out of procs\n", pid);
       +        abort();
       +        return nil;
       +}
       +
       +Proc*
       +_threadproc(void)
       +{
       +        return myperproc()->proc;
       +}
       +
       +void
       +_threadsetproc(Proc *p)
       +{
       +        Perproc *pp;
       +
       +        if(p)
       +                p->osprocid = getpid();
       +        pp = newperproc();
       +        pp->proc = p;
       +        if(p == nil)
       +                pp->pid = -1;
       +}
       +
       +void
       +_pthreadinit(void)
       +{
       +        __isthreaded = 1;
       +        signal(SIGUSR2, sigusr2handler);
       +}
       +
       +void
       +_threadpexit(void)
       +{
       +        _exit(0);
       +}
       +
 (DIR) diff --git a/src/libthread/FreeBSD.c b/src/libthread/FreeBSD.c
       t@@ -1,368 +1,6 @@
        #include "threadimpl.h"
        
       -#undef exits
       -#undef _exits
       -
       -extern int __isthreaded;
       -
       -/*
       - * spin locks
       - */
       -extern int _tas(int*);
       -
       -void
       -_threadunlock(Lock *l, ulong pc)
       -{
       -        USED(pc);
       -
       -        l->held = 0;
       -}
       -
       -int
       -_threadlock(Lock *l, int block, ulong pc)
       -{
       -        int i;
       -
       -        USED(pc);
       -
       -        /* once fast */
       -        if(!_tas(&l->held))
       -                return 1;
       -        if(!block)
       -                return 0;
       -
       -        /* a thousand times pretty fast */
       -        for(i=0; i<1000; i++){
       -                if(!_tas(&l->held))
       -                        return 1;
       -                sched_yield();
       -        }
       -        /* now nice and slow */
       -        for(i=0; i<1000; i++){
       -                if(!_tas(&l->held))
       -                        return 1;
       -                usleep(100*1000);
       -        }
       -        /* take your time */
       -        while(_tas(&l->held))
       -                usleep(1000*1000);
       -        return 1;
       -}
       -
       -/*
       - * 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);
       -}
       -
       -/*
       - * sleep and wakeup
       - */
       -static void
       -ign(int x)
       -{
       -        USED(x);
       -}
       -
       -static 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(_Procrendez *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.
       -         */
       -again:
       -        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.
       -         */
       -        lock(r->l);
       -        ignusr1(1);
       -        if(r->asleep && r->pid == getpid()){
       -                /* Didn't really wake up - signal from something else */
       -                goto again;
       -        }
       -}
       -
       -void
       -_procwakeup(_Procrendez *r)
       -{
       -        if(r->asleep){
       -                r->asleep = 0;
       -                assert(r->pid >= 1);
       -                kill(r->pid, SIGUSR1);
       -        }
       -}
       -
       -void
       -_procwakeupandunlock(_Procrendez *r)
       -{
       -        _procwakeup(r);
       -        unlock(r->l);
       -}
       -
       -
       -/*
       - * process creation and exit
       - */
       -typedef struct Stackfree Stackfree;
       -struct Stackfree
       -{
       -        Stackfree        *next;
       -        int        pid;
       -};
       -static Lock stacklock;
       -static Stackfree *stackfree;
       -
       -static void
       -delayfreestack(uchar *stk)
       -{
       -        Stackfree *sf;
       -
       -        sf = (Stackfree*)stk;
       -        sf->pid = getpid();
       -        lock(&stacklock);
       -        sf->next = stackfree;
       -        stackfree = sf;
       -        unlock(&stacklock);
       -}
       -
       -static void
       -dofreestacks(void)
       -{
       -        Stackfree *sf, *last, *next;
       -
       -        if(stackfree==nil || !canlock(&stacklock))
       -                return;
       -
       -        for(last=nil,sf=stackfree; sf; last=sf,sf=next){
       -                next = sf->next;
       -                if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
       -                        free(sf);
       -                        if(last)
       -                                last->next = next;
       -                        else
       -                                stackfree = next;
       -                        sf = last;
       -                }
       -        }
       -        unlock(&stacklock);
       -}
       -
       -static int
       -startprocfn(void *v)
       -{
       -        void **a;
       -        uchar *stk;
       -        void (*fn)(void*);
       -        Proc *p;
       -
       -        a = (void**)v;
       -        fn = a[0];
       -        p = a[1];
       -        stk = a[2];
       -        free(a);
       -        p->osprocid = getpid();
       -
       -        (*fn)(p);
       -
       -        delayfreestack(stk);
       -        _exit(0);
       -        return 0;
       -}
       -
       -void
       -_procstart(Proc *p, void (*fn)(Proc*))
       -{
       -        void **a;
       -        uchar *stk;
       -        int pid;
       -
       -        dofreestacks();
       -        a = malloc(3*sizeof a[0]);
       -        if(a == nil)
       -                sysfatal("_procstart malloc: %r");
       -        stk = malloc(65536);
       -        if(stk == nil)
       -                sysfatal("_procstart malloc stack: %r");
       -
       -        a[0] = fn;
       -        a[1] = p;
       -        a[2] = stk;
       -
       -        pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);
       -        if(pid < 0){
       -                fprint(2, "_procstart rfork_thread: %r\n");
       -                abort();
       -        }
       -}
       -
       -static char *threadexitsmsg;
       -void
       -sigusr2handler(int s)
       -{
       -/*        fprint(2, "%d usr2 %d\n", time(0), getpid()); */
       -        if(threadexitsmsg)
       -                _exits(threadexitsmsg);
       -}
       -
       -void
       -threadexitsall(char *msg)
       -{
       -        static int pid[1024];
       -        int i, npid, mypid;
       -        Proc *p;
       -
       -        if(msg == nil)
       -                msg = "";
       -        mypid = getpid();
       -        lock(&_threadprocslock);
       -        threadexitsmsg = msg;
       -        npid = 0;
       -        for(p=_threadprocs; p; p=p->next)
       -                if(p->osprocid != mypid && p->osprocid >= 1)
       -                        pid[npid++] = p->osprocid;
       -        for(i=0; i<npid; i++)
       -                kill(pid[i], SIGUSR2);
       -        unlock(&_threadprocslock);
       -        exits(msg);
       -}
       -
       -/*
       - * per-process data, indexed by pid
       - *
       - * could use modify_ldt and a segment register
       - * to avoid the many calls to getpid(), but i don't
       - * care -- this is compatibility code.  linux 2.6 with
       - * nptl is a good enough pthreads to avoid this whole file.
       - */
       -typedef struct Perproc Perproc;
       -struct Perproc
       -{
       -        int                pid;
       -        Proc        *proc;
       -};
       -
       -static Lock perlock;
       -static Perproc perproc[1024];
       -#define P ((Proc*)-1)
       -
       -static Perproc*
       -myperproc(void)
       -{
       -        int i, pid, h;
       -        Perproc *p;
       -
       -        pid = getpid();
       -        h = pid%nelem(perproc);
       -        for(i=0; i<nelem(perproc); i++){
       -                p = &perproc[(i+h)%nelem(perproc)];
       -                if(p->pid == pid)
       -                        return p;
       -                if(p->pid == 0){
       -                        print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
       -                        break;
       -                }
       -        }
       -        fprint(2, "myperproc %d: cannot find self\n", pid);
       -        abort();
       -        return nil;
       -}
       -
       -static Perproc*
       -newperproc(void)
       -{
       -        int i, pid, h;
       -        Perproc *p;
       -
       -        lock(&perlock);
       -        pid = getpid();
       -        h = pid%nelem(perproc);
       -        for(i=0; i<nelem(perproc); i++){
       -                p = &perproc[(i+h)%nelem(perproc)];
       -                if(p->pid == pid || p->pid == -1 || p->pid == 0){
       -                        p->pid = pid;
       -                        unlock(&perlock);
       -                        return p;
       -                }
       -        }
       -        fprint(2, "newperproc %d: out of procs\n", pid);
       -        abort();
       -        return nil;
       -}
       -
       -Proc*
       -_threadproc(void)
       -{
       -        return myperproc()->proc;
       -}
       -
       -void
       -_threadsetproc(Proc *p)
       -{
       -        Perproc *pp;
       -
       -        if(p)
       -                p->osprocid = getpid();
       -        pp = newperproc();
       -        pp->proc = p;
       -        if(p == nil)
       -                pp->pid = -1;
       -}
       -
       -void
       -_pthreadinit(void)
       -{
       -        __isthreaded = 1;
       -        signal(SIGUSR2, sigusr2handler);
       -}
       -
       -void
       -_threadpexit(void)
       -{
       -        _exit(0);
       -}
       -
       +#include "BSD.c"
        
        /*
         * FreeBSD 4 and earlier needs the context functions.
 (DIR) diff --git a/src/libthread/OpenBSD-power-asm.S b/src/libthread/OpenBSD-power-asm.S
       t@@ -0,0 +1,125 @@
       +#include <sys/syscall.h>
       +#include <machine/asm.h>
       +
       +ENTRY(_tas)
       +        li        %r0, 0
       +        mr        %r4, %r3
       +        lis        %r5, 0xcafe
       +        ori        %r5, %r5, 0xbabe
       +1:
       +        lwarx        %r3, %r0, %r4
       +        cmpwi        %r3, 0
       +        bne        2f
       +        stwcx.        %r5, %r0, %r4
       +        bne-        1b
       +2:
       +        sync
       +        blr
       +
       +ENTRY(_getmcontext)                                /* xxx: instruction scheduling */
       +        mflr        %r0
       +        mfcr        %r5
       +        mfctr        %r6
       +        mfxer        %r7
       +        stw        %r0, 0*4(%r3)
       +        stw        %r5, 1*4(%r3)
       +        stw        %r6, 2*4(%r3)
       +        stw        %r7, 3*4(%r3)
       +
       +        stw        %r1, 4*4(%r3)
       +        stw        %r2, 5*4(%r3)
       +        li        %r5, 1                        /* return value for setmcontext */
       +        stw        %r5, 6*4(%r3)
       +
       +        stw        %r13, (0+7)*4(%r3)        /* callee-save GPRs */
       +        stw        %r14, (1+7)*4(%r3)        /* xxx: block move */
       +        stw        %r15, (2+7)*4(%r3)
       +        stw        %r16, (3+7)*4(%r3)
       +        stw        %r17, (4+7)*4(%r3)
       +        stw        %r18, (5+7)*4(%r3)
       +        stw        %r19, (6+7)*4(%r3)
       +        stw        %r20, (7+7)*4(%r3)
       +        stw        %r21, (8+7)*4(%r3)
       +        stw        %r22, (9+7)*4(%r3)
       +        stw        %r23, (10+7)*4(%r3)
       +        stw        %r24, (11+7)*4(%r3)
       +        stw        %r25, (12+7)*4(%r3)
       +        stw        %r26, (13+7)*4(%r3)
       +        stw        %r27, (14+7)*4(%r3)
       +        stw        %r28, (15+7)*4(%r3)
       +        stw        %r29, (16+7)*4(%r3)
       +        stw        %r30, (17+7)*4(%r3)
       +        stw        %r31, (18+7)*4(%r3)
       +
       +        li        %r3, 0                        /* return */
       +        blr
       +
       +ENTRY(_setmcontext)
       +        lwz        %r13, (0+7)*4(%r3)        /* callee-save GPRs */
       +        lwz        %r14, (1+7)*4(%r3)        /* xxx: block move */
       +        lwz        %r15, (2+7)*4(%r3)
       +        lwz        %r16, (3+7)*4(%r3)
       +        lwz        %r17, (4+7)*4(%r3)
       +        lwz        %r18, (5+7)*4(%r3)
       +        lwz        %r19, (6+7)*4(%r3)
       +        lwz        %r20, (7+7)*4(%r3)
       +        lwz        %r21, (8+7)*4(%r3)
       +        lwz        %r22, (9+7)*4(%r3)
       +        lwz        %r23, (10+7)*4(%r3)
       +        lwz        %r24, (11+7)*4(%r3)
       +        lwz        %r25, (12+7)*4(%r3)
       +        lwz        %r26, (13+7)*4(%r3)
       +        lwz        %r27, (14+7)*4(%r3)
       +        lwz        %r28, (15+7)*4(%r3)
       +        lwz        %r29, (16+7)*4(%r3)
       +        lwz        %r30, (17+7)*4(%r3)
       +        lwz        %r31, (18+7)*4(%r3)
       +
       +        lwz        %r1, 4*4(%r3)
       +        lwz        %r2, 5*4(%r3)
       +
       +        lwz        %r0, 0*4(%r3)
       +        mtlr        %r0
       +        lwz        %r0, 1*4(%r3)
       +        mtcr        %r0                        /* mtcrf 0xFF, %r0 */
       +        lwz        %r0, 2*4(%r3)
       +        mtctr        %r0
       +        lwz        %r0, 3*4(%r3)
       +        mtxer        %r0
       +
       +        lwz        %r3,        6*4(%r3)
       +        blr
       +
       +ENTRY(rfork_thread)
       +        /* sanity check */
       +        cmpwi        %r4, 0
       +        beq        1f
       +        cmpwi        %r5, 0
       +        beq        1f
       +        
       +        mr        %r7,%r4
       +        
       +        /* call rfork */
       +        li        %r0, SYS_rfork
       +        sc
       +        cmpwi        %r0, 0
       +        bne        2f
       +        
       +        /* check if we are parent or child */
       +        cmpwi        %r3, 0
       +        bnelr
       +        
       +        /* child */
       +        mtlr        %r5        /* fp */
       +        mr        %r3, %r6        /* arg */
       +        mr        %r1, %r7        /* new sp */
       +        blrl
       +        
       +        /* child returned, call _exit */
       +        li        %r0, SYS_exit
       +        sc
       +1:
       +        li        %r3, -1
       +2:
       +        b PIC_PLT(_C_LABEL(__cerror))
       +
 (DIR) diff --git a/src/libthread/OpenBSD-power.c b/src/libthread/OpenBSD-power.c
       t@@ -0,0 +1,38 @@
       +#include "threadimpl.h"
       +
       +void
       +makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
       +{
       +        ulong *sp, *tos;
       +        va_list arg;
       +
       +        tos = (ulong*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(ulong);
       +        sp = (ulong*)((ulong)(tos-16) & ~15);
       +        ucp->mc.pc = (long)func;
       +        ucp->mc.sp = (long)sp;
       +        va_start(arg, argc);
       +        ucp->mc.r3 = va_arg(arg, long);
       +        va_end(arg);
       +}
       +
       +int
       +getcontext(ucontext_t *uc)
       +{
       +        return _getmcontext(&uc->mc);
       +}
       +
       +int
       +setcontext(ucontext_t *uc)
       +{
       +        _setmcontext(&uc->mc);
       +        return 0;
       +}
       +
       +int
       +swapcontext(ucontext_t *oucp, ucontext_t *ucp)
       +{
       +        if(getcontext(oucp) == 0)
       +                setcontext(ucp);
       +        return 0;
       +}
       +
 (DIR) diff --git a/src/libthread/OpenBSD.c b/src/libthread/OpenBSD.c
       t@@ -0,0 +1,4 @@
       +#include "threadimpl.h"
       +
       +#include "BSD.c"
       +
 (DIR) diff --git a/src/libthread/mkfile b/src/libthread/mkfile
       t@@ -15,6 +15,8 @@ OFILES=\
        <$PLAN9/src/mksyslib
        
        HFILES=thread.h threadimpl.h
       +OpenBSD.$O FreeBSD.$O: BSD.c
       +NetBSD.$O: Linux.c
        
        tprimes: tprimes.$O
                9l -o $target $target.$O $PLAN9/lib/$LIB -l9 -lpthread
       t@@ -24,9 +26,8 @@ tspawnloop: tspawnloop.$O
                9l -o $target $target.$O $PLAN9/lib/$LIB -l9 -lpthread
        
        %.$O: %.c
       -        $CC -I. $stem.c
       +        $CC $CFLAGS -I. $stem.c
        
       -NetBSD.$O: Linux.c
        
        test:V: tprimes tspawn
                primes 1 10007 >p1.txt
       t@@ -40,5 +41,3 @@ test:V: tprimes tspawn
        
        CLEANFILES=p1.txt p2.txt tp1.txt tp2.txt
        
       -
       -
 (DIR) diff --git a/src/libthread/Darwin-ucontext.h b/src/libthread/power-ucontext.h
 (DIR) diff --git a/src/libthread/sysofiles.sh b/src/libthread/sysofiles.sh
       t@@ -23,6 +23,9 @@ case "$tag" in
        *-Darwin-*)
                echo ${SYSNAME}-${OBJTYPE}-asm.o ${SYSNAME}-${OBJTYPE}.o pthread.o
                ;;
       +*-OpenBSD-*)
       +        echo ${SYSNAME}-${OBJTYPE}-asm.o ${SYSNAME}-${OBJTYPE}.o $SYSNAME.o
       +        ;;
        *)
                echo pthread.o
        esac
 (DIR) diff --git a/src/libthread/threadimpl.h b/src/libthread/threadimpl.h
       t@@ -5,7 +5,9 @@
        #include <sys/wait.h>
        #include <sched.h>
        #include <signal.h>
       -#include <ucontext.h>
       +#if !defined(_OpenBSD__)
       +#        include <ucontext.h>
       +#endif
        #include <sys/utsname.h>
        #include "libc.h"
        #include "thread.h"
       t@@ -22,7 +24,12 @@ extern        void                makecontext(ucontext_t*, void(*)(), int, ...);
        #        define mcontext_t libthread_mcontext_t
        #        define ucontext libthread_ucontext
        #        define ucontext_t libthread_ucontext_t
       -#        include "Darwin-ucontext.h"
       +#        include "power-ucontext.h"
       +#endif
       +
       +#if defined(__OpenBSD__)
       +#        include "power-ucontext.h"
       +extern pid_t rfork_thread(int, void*, int(*)(void*), void*);
        #endif
        
        typedef struct Context Context;