tlibthread: remove Linux 2.4 code - 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 8d82ccefd2b4b058e20ae0a7e3d9ef9b6b8cf8c3
 (DIR) parent c181e39eeab0eb8cad274b7b22ce5343bd55630d
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Sun, 19 Jan 2020 21:03:56 -0500
       
       libthread: remove Linux 2.4 code
       
       Linux.c was for Linux 2.4 and is no longer used directly,
       only indirectly because NetBSD.c was a 1-line file #including Linux.c.
       So mv Linux.c NetBSD.c.
       
       Also rm Linux-*-asm.s which was for Linux 2.4 as well.
       
       Diffstat:
         D src/libthread/Linux-386-asm.s       |       7 -------
         D src/libthread/Linux-arm-asm.s       |      10 ----------
         D src/libthread/Linux-power-asm.s     |      16 ----------------
         D src/libthread/Linux-sparc64-asm.s   |      16 ----------------
         D src/libthread/Linux.c               |     462 -------------------------------
         M src/libthread/NetBSD.c              |     463 ++++++++++++++++++++++++++++++-
         M src/libthread/mkfile                |       1 -
       
       7 files changed, 462 insertions(+), 513 deletions(-)
       ---
 (DIR) diff --git a/src/libthread/Linux-386-asm.s b/src/libthread/Linux-386-asm.s
       t@@ -1,7 +0,0 @@
       -.globl _tas
       -_tas:
       -        movl $0xCAFEBABE, %eax
       -        movl 4(%esp), %ecx
       -        xchgl %eax, 0(%ecx)
       -        ret
       -
 (DIR) diff --git a/src/libthread/Linux-arm-asm.s b/src/libthread/Linux-arm-asm.s
       t@@ -1,10 +0,0 @@
       - 
       -.globl _tas
       -_tas:
       -        mov        r3, #0xCA000000
       -        add        r3, r3, #0xFE0000
       -        add        r3, r3, #0xBA00
       -        add        r3, r3, #0xBE
       -        swp        r3, r3, [r0]
       -        mov        r0, r3
       -        mov        pc, lr
 (DIR) diff --git a/src/libthread/Linux-power-asm.s b/src/libthread/Linux-power-asm.s
       t@@ -1,16 +0,0 @@
       -        .globl        _tas
       -_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
       -
 (DIR) diff --git a/src/libthread/Linux-sparc64-asm.s b/src/libthread/Linux-sparc64-asm.s
       t@@ -1,16 +0,0 @@
       -! Actually sparc32 assembly. 
       -! Debian's sparc64 port is a 32-bit user space.
       -
       -        .section        ".text", #alloc, #execinstr
       -        .align                8
       -        .skip                16
       -        .global _tas
       -!        .type        _tas,2
       -_tas:
       -        or        %g0,1,%o1
       -        swap        [%o0],%o1        ! o0 points to lock; key is first word
       -        retl
       -        mov        %o1, %o0
       -
       -           .size        _tas,(.-_tas)
       -
 (DIR) diff --git a/src/libthread/Linux.c b/src/libthread/Linux.c
       t@@ -1,462 +0,0 @@
       -#include "threadimpl.h"
       -
       -#undef exits
       -#undef _exits
       -
       -static int
       -timefmt(Fmt *fmt)
       -{
       -        static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
       -                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
       -        vlong ns;
       -        Tm tm;
       -        ns = nsec();
       -        tm = *localtime(time(0));
       -        return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
       -                mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
       -                (int)(ns%1000000000)/1000000);
       -}
       -
       -/*
       - * 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;
       -static int first=1;
       -if(first) {first=0; fmtinstall('\001', timefmt);}
       -
       -        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 increasingly slow */
       -        for(i=0; i<10; i++){
       -                if(!_tas(&l->held))
       -                        return 1;
       -                usleep(1);
       -        }
       -fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc);
       -        for(i=0; i<10; i++){
       -                if(!_tas(&l->held))
       -                        return 1;
       -                usleep(10);
       -        }
       -fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc);
       -        for(i=0; i<10; i++){
       -                if(!_tas(&l->held))
       -                        return 1;
       -                usleep(100);
       -        }
       -fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc);
       -        for(i=0; i<10; i++){
       -                if(!_tas(&l->held))
       -                        return 1;
       -                usleep(1000);
       -        }
       -fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc);
       -        for(i=0; i<10; i++){
       -                if(!_tas(&l->held))
       -                        return 1;
       -                usleep(10*1000);
       -        }
       -fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc);
       -        for(i=0; i<1000; i++){
       -                if(!_tas(&l->held))
       -                        return 1;
       -                usleep(100*1000);
       -        }
       -fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc);
       -        /* take your time */
       -        while(_tas(&l->held))
       -                usleep(1000*1000);
       -        return 1;
       -}
       -
       -/*
       - * 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
       -_procwakeupandunlock(_Procrendez *r)
       -{
       -        int pid;
       -
       -        pid = 0;
       -        if(r->asleep){
       -                r->asleep = 0;
       -                assert(r->pid >= 1);
       -                pid = r->pid;
       -        }
       -        assert(r->l);
       -        unlock(r->l);
       -        if(pid)
       -                kill(pid, SIGUSR1);
       -}
       -
       -/*
       - * process creation and exit
       - */
       -typedef struct Stackfree Stackfree;
       -struct Stackfree
       -{
       -        Stackfree        *next;
       -        int        pid;
       -        int        pid1;
       -};
       -static Lock stacklock;
       -static Stackfree *stackfree;
       -
       -static void
       -delayfreestack(uchar *stk, int pid, int pid1)
       -{
       -        Stackfree *sf;
       -
       -        sf = (Stackfree*)stk;
       -        sf->pid = pid;
       -        sf->pid1 = pid1;
       -        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)
       -                if(sf->pid1 >= 1 && kill(sf->pid1, 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;
       -        int pid0, pid1;
       -
       -        a = (void**)v;
       -        fn = a[0];
       -        p = a[1];
       -        stk = a[2];
       -        pid0 = (int)a[4];
       -        pid1 = getpid();
       -        free(a);
       -        p->osprocid = pid1;
       -
       -        (*fn)(p);
       -
       -        delayfreestack(stk, pid0, pid1);
       -        _exit(0);
       -        return 0;
       -}
       -
       -/*
       - * indirect through here so that parent need not wait for child zombie
       - *
       - * slight race - if child exits and then another process starts before we
       - * manage to exit, we'll be running on a freed stack.
       - */
       -static int
       -trampnowait(void *v)
       -{
       -        void **a;
       -        int *kidpid;
       -
       -        a = (void*)v;
       -        kidpid = a[3];
       -        a[4] = (void*)getpid();
       -        *kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
       -        _exit(0);
       -        return 0;
       -}
       -
       -void
       -_procstart(Proc *p, void (*fn)(Proc*))
       -{
       -        void **a;
       -        uchar *stk;
       -        int pid, kidpid, status;
       -
       -        dofreestacks();
       -        a = malloc(5*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;
       -        a[3] = &kidpid;
       -        kidpid = -1;
       -
       -        pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
       -        if(pid > 0)
       -                if(wait4(pid, &status, __WALL, 0) < 0)
       -                        fprint(2, "ffork wait4: %r\n");
       -        if(pid < 0 || kidpid < 0){
       -                fprint(2, "_procstart clone: %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 = "";
       -
       -        /*
       -         * Only one guy, ever, gets to run this.
       -         * If two guys do it, inevitably they end up
       -         * tripping over each other in the underlying
       -         * C library exit() implementation, which is
       -         * trying to run the atexit handlers and apparently
       -         * not thread safe.  This has been observed on
       -         * both Linux and OpenBSD.  Sigh.
       -         */
       -        {
       -                static Lock onelock;
       -                if(!canlock(&onelock))
       -                        _exits(threadexitsmsg);
       -                threadexitsmsg = msg;
       -        }
       -
       -        mypid = getpid();
       -        lock(&_threadprocslock);
       -        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 (%s): cannot find self\n", pid, argv0);
       -        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)
       -{
       -        signal(SIGUSR2, sigusr2handler);
       -}
       -
       -void
       -_threadpexit(void)
       -{
       -        _exit(0);
       -}
       -
       -#ifdef __arm__
       -void
       -makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
       -{
       -        int i, *sp;
       -        va_list arg;
       -
       -        sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4;
       -        va_start(arg, argc);
       -        for(i=0; i<4 && i<argc; i++)
       -                uc->uc_mcontext.gregs[i] = va_arg(arg, uint);
       -        va_end(arg);
       -        uc->uc_mcontext.gregs[13] = (uint)sp;
       -        uc->uc_mcontext.gregs[14] = (uint)fn;
       -}
       -
       -int
       -swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
       -{
       -        if(getcontext(oucp) == 0)
       -                setcontext(ucp);
       -        return 0;
       -}
       -#endif
 (DIR) diff --git a/src/libthread/NetBSD.c b/src/libthread/NetBSD.c
       t@@ -1 +1,462 @@
       -#include "Linux.c"
       +#include "threadimpl.h"
       +
       +#undef exits
       +#undef _exits
       +
       +static int
       +timefmt(Fmt *fmt)
       +{
       +        static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
       +                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
       +        vlong ns;
       +        Tm tm;
       +        ns = nsec();
       +        tm = *localtime(time(0));
       +        return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
       +                mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
       +                (int)(ns%1000000000)/1000000);
       +}
       +
       +/*
       + * 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;
       +static int first=1;
       +if(first) {first=0; fmtinstall('\001', timefmt);}
       +
       +        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 increasingly slow */
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(1);
       +        }
       +fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc);
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(10);
       +        }
       +fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc);
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(100);
       +        }
       +fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc);
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(1000);
       +        }
       +fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc);
       +        for(i=0; i<10; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(10*1000);
       +        }
       +fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc);
       +        for(i=0; i<1000; i++){
       +                if(!_tas(&l->held))
       +                        return 1;
       +                usleep(100*1000);
       +        }
       +fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc);
       +        /* take your time */
       +        while(_tas(&l->held))
       +                usleep(1000*1000);
       +        return 1;
       +}
       +
       +/*
       + * 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
       +_procwakeupandunlock(_Procrendez *r)
       +{
       +        int pid;
       +
       +        pid = 0;
       +        if(r->asleep){
       +                r->asleep = 0;
       +                assert(r->pid >= 1);
       +                pid = r->pid;
       +        }
       +        assert(r->l);
       +        unlock(r->l);
       +        if(pid)
       +                kill(pid, SIGUSR1);
       +}
       +
       +/*
       + * process creation and exit
       + */
       +typedef struct Stackfree Stackfree;
       +struct Stackfree
       +{
       +        Stackfree        *next;
       +        int        pid;
       +        int        pid1;
       +};
       +static Lock stacklock;
       +static Stackfree *stackfree;
       +
       +static void
       +delayfreestack(uchar *stk, int pid, int pid1)
       +{
       +        Stackfree *sf;
       +
       +        sf = (Stackfree*)stk;
       +        sf->pid = pid;
       +        sf->pid1 = pid1;
       +        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)
       +                if(sf->pid1 >= 1 && kill(sf->pid1, 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;
       +        int pid0, pid1;
       +
       +        a = (void**)v;
       +        fn = a[0];
       +        p = a[1];
       +        stk = a[2];
       +        pid0 = (int)a[4];
       +        pid1 = getpid();
       +        free(a);
       +        p->osprocid = pid1;
       +
       +        (*fn)(p);
       +
       +        delayfreestack(stk, pid0, pid1);
       +        _exit(0);
       +        return 0;
       +}
       +
       +/*
       + * indirect through here so that parent need not wait for child zombie
       + *
       + * slight race - if child exits and then another process starts before we
       + * manage to exit, we'll be running on a freed stack.
       + */
       +static int
       +trampnowait(void *v)
       +{
       +        void **a;
       +        int *kidpid;
       +
       +        a = (void*)v;
       +        kidpid = a[3];
       +        a[4] = (void*)getpid();
       +        *kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
       +        _exit(0);
       +        return 0;
       +}
       +
       +void
       +_procstart(Proc *p, void (*fn)(Proc*))
       +{
       +        void **a;
       +        uchar *stk;
       +        int pid, kidpid, status;
       +
       +        dofreestacks();
       +        a = malloc(5*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;
       +        a[3] = &kidpid;
       +        kidpid = -1;
       +
       +        pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
       +        if(pid > 0)
       +                if(wait4(pid, &status, __WALL, 0) < 0)
       +                        fprint(2, "ffork wait4: %r\n");
       +        if(pid < 0 || kidpid < 0){
       +                fprint(2, "_procstart clone: %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 = "";
       +
       +        /*
       +         * Only one guy, ever, gets to run this.
       +         * If two guys do it, inevitably they end up
       +         * tripping over each other in the underlying
       +         * C library exit() implementation, which is
       +         * trying to run the atexit handlers and apparently
       +         * not thread safe.  This has been observed on
       +         * both Linux and OpenBSD.  Sigh.
       +         */
       +        {
       +                static Lock onelock;
       +                if(!canlock(&onelock))
       +                        _exits(threadexitsmsg);
       +                threadexitsmsg = msg;
       +        }
       +
       +        mypid = getpid();
       +        lock(&_threadprocslock);
       +        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 (%s): cannot find self\n", pid, argv0);
       +        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)
       +{
       +        signal(SIGUSR2, sigusr2handler);
       +}
       +
       +void
       +_threadpexit(void)
       +{
       +        _exit(0);
       +}
       +
       +#ifdef __arm__
       +void
       +makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
       +{
       +        int i, *sp;
       +        va_list arg;
       +
       +        sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4;
       +        va_start(arg, argc);
       +        for(i=0; i<4 && i<argc; i++)
       +                uc->uc_mcontext.gregs[i] = va_arg(arg, uint);
       +        va_end(arg);
       +        uc->uc_mcontext.gregs[13] = (uint)sp;
       +        uc->uc_mcontext.gregs[14] = (uint)fn;
       +}
       +
       +int
       +swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
       +{
       +        if(getcontext(oucp) == 0)
       +                setcontext(ucp);
       +        return 0;
       +}
       +#endif
 (DIR) diff --git a/src/libthread/mkfile b/src/libthread/mkfile
       t@@ -16,7 +16,6 @@ OFILES=\
        <$PLAN9/src/mksyslib
        
        HFILES=thread.h threadimpl.h
       -NetBSD.$O: Linux.c
        
        tprimes: test/tprimes.$O
                9l -o $target test/$target.$O