tNew thread library - 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 1544f90960275dc9211bde30329c3258e0e1bf38
 (DIR) parent 7788fd54094693384ef5c92c475656dba8819feb
 (HTM) Author: rsc <devnull@localhost>
       Date:   Sat, 25 Dec 2004 21:56:33 +0000
       
       New thread library
       
       Diffstat:
         D src/libthread/386.c                 |      62 -------------------------------
         D src/libthread/FreeBSD-386.s         |      18 ------------------
         D src/libthread/Linux-clone.c         |     185 ------------------------------
         D src/libthread/NOTICE                |      19 -------------------
         D src/libthread/PowerMacintosh.c      |      39 -------------------------------
         D src/libthread/README                |      19 -------------------
         D src/libthread/asm-Darwin-PowerMaci… |      80 -------------------------------
         D src/libthread/asm-FreeBSD-386.s     |      55 -------------------------------
         D src/libthread/asm-Linux-386.s       |       1 -
         D src/libthread/asm-Linux-power.s     |      80 -------------------------------
         D src/libthread/asm-OpenBSD-386.s     |      49 -------------------------------
         D src/libthread/asm-SunOS-sun4u.s     |      51 -------------------------------
         D src/libthread/channel.c             |     500 -------------------------------
         D src/libthread/chanprint.c           |      20 --------------------
         D src/libthread/create.c              |     211 -------------------------------
         D src/libthread/debug.c               |      48 -------------------------------
         D src/libthread/exec-unix.c           |     147 -------------------------------
         A src/libthread/exec.c                |     153 +++++++++++++++++++++++++++++++
         D src/libthread/execproc.ch           |     183 -------------------------------
         D src/libthread/exit-getpid.ch        |      25 -------------------------
         D src/libthread/exit.c                |      44 -------------------------------
         D src/libthread/fdwait.c              |     241 -------------------------------
         D src/libthread/getpid.c              |       7 -------
         D src/libthread/id.c                  |     136 -------------------------------
         D src/libthread/iocall.c              |      55 -------------------------------
         D src/libthread/ioclose.c             |      16 ----------------
         D src/libthread/iodial.c              |      24 ------------------------
         D src/libthread/ioopen.c              |      21 ---------------------
         D src/libthread/ioproc.c              |      77 -------------------------------
         D src/libthread/ioproc.h              |      14 --------------
         D src/libthread/ioread.c              |      20 --------------------
         D src/libthread/ioreadn.c             |      21 ---------------------
         A src/libthread/iorw.c                |     178 +++++++++++++++++++++++++++++++
         D src/libthread/iosleep.c             |      16 ----------------
         D src/libthread/iowrite.c             |      22 ----------------------
         D src/libthread/kill.c                |      90 -------------------------------
         D src/libthread/label.h               |      68 -------------------------------
         D src/libthread/lib.c                 |      35 -------------------------------
         D src/libthread/main.c                |      98 -------------------------------
         D src/libthread/memset.c              |       8 --------
         D src/libthread/memsetd.c             |       8 --------
         D src/libthread/mkfile                |      73 -------------------------------
         D src/libthread/note.c                |     145 -------------------------------
         D src/libthread/pid.c                 |      25 -------------------------
         D src/libthread/power.c               |      40 -------------------------------
         D src/libthread/procstack.ch          |      75 -------------------------------
         D src/libthread/proctab.c             |      75 -------------------------------
         D src/libthread/proctab.ch            |      97 ------------------------------
         D src/libthread/pthread.c             |     271 -------------------------------
         A src/libthread/qlock.c               |       3 +++
         D src/libthread/read9pmsg.c           |      32 -------------------------------
         D src/libthread/ref.c                 |      26 --------------------------
         D src/libthread/sched.c               |     343 -------------------------------
         D src/libthread/setproc.c             |      36 -------------------------------
         D src/libthread/sleep.c               |      39 -------------------------------
         D src/libthread/sun4u.c               |      53 ------------------------------
         D src/libthread/sysofiles.sh          |      11 -----------
         A src/libthread/test/pthreadloop.c    |      38 +++++++++++++++++++++++++++++++
         A src/libthread/test/tprimes.c        |      80 +++++++++++++++++++++++++++++++
         A src/libthread/test/tspawn.c         |      39 +++++++++++++++++++++++++++++++
         A src/libthread/test/tspawnloop.c     |      41 +++++++++++++++++++++++++++++++
         D src/libthread/texec.c               |      45 -------------------------------
         D src/libthread/tfork.c               |      23 -----------------------
         A src/libthread/thread.c              |     535 +++++++++++++++++++++++++++++++
         D src/libthread/thread.sh             |      15 ---------------
         D src/libthread/threadimpl.h          |     241 -------------------------------
         D src/libthread/tprimes.c             |      68 -------------------------------
         D src/libthread/trend.c               |      31 -------------------------------
         D src/libthread/tsignal.c             |      43 ------------------------------
         D src/libthread/tspawn.c              |      41 -------------------------------
         D src/libthread/ucontext.c            |      49 -------------------------------
       
       71 files changed, 1067 insertions(+), 4710 deletions(-)
       ---
 (DIR) diff --git a/src/libthread/386.c b/src/libthread/386.c
       t@@ -1,62 +0,0 @@
       -#if defined(__linux__)
       -#include "ucontext.c"
       -#else
       -
       -#include "threadimpl.h"
       -/*
       - * To use this you need some patches to Valgrind that
       - * let it help out with detecting stack overflow. 
       - */
       -#ifdef USEVALGRIND
       -#include <valgrind/memcheck.h>
       -#endif
       -
       -static void
       -launcher386(void (*f)(void *arg), void *arg)
       -{
       -        Proc *p;
       -        Thread *t;
       -
       -        p = _threadgetproc();
       -        t = p->thread;
       -        _threadstacklimit(t->stk, t->stk+t->stksize);
       -
       -        (*f)(arg);
       -        threadexits(nil);
       -}
       -
       -void
       -_threadinitstack(Thread *t, void (*f)(void*), void *arg)
       -{
       -        ulong *tos;
       -
       -        tos = (ulong*)&t->stk[t->stksize&~7];
       -        *--tos = (ulong)arg;
       -        *--tos = (ulong)f;
       -        t->sched.pc = (ulong)launcher386;
       -        t->sched.sp = (ulong)tos - 8;                /* old PC and new PC */
       -}
       -
       -void
       -_threadinswitch(int enter)
       -{
       -        USED(enter);
       -#ifdef USEVALGRIND
       -        if(enter)
       -                VALGRIND_SET_STACK_LIMIT(0, 0, 0);
       -        else
       -                VALGRIND_SET_STACK_LIMIT(0, 0, 1);
       -#endif
       -}
       -
       -void
       -_threadstacklimit(void *bottom, void *top)
       -{
       -        USED(bottom);
       -        USED(top);
       -
       -#ifdef USEVALGRIND
       -        VALGRIND_SET_STACK_LIMIT(1, bottom, top);
       -#endif
       -}
       -#endif
 (DIR) diff --git a/src/libthread/FreeBSD-386.s b/src/libthread/FreeBSD-386.s
       t@@ -1,18 +0,0 @@
       -
       -.globl        _xinc
       -_xinc:
       -        movl 4(%esp), %eax
       -        lock incl 0(%eax)
       -        ret
       -
       -.globl        _xdec
       -_xdec:
       -        movl 4(%esp), %eax
       -        lock decl 0(%eax)
       -        jz iszero
       -        movl %eax, 1
       -        ret
       -iszero:
       -        movl %eax, 0
       -        ret
       -
 (DIR) diff --git a/src/libthread/Linux-clone.c b/src/libthread/Linux-clone.c
       t@@ -1,185 +0,0 @@
       -#include <u.h>
       -#include <errno.h>
       -#include <sched.h>
       -#include <sys/signal.h>
       -#include <sys/wait.h>
       -#include "threadimpl.h"
       -
       -#define procid()                getpid()
       -#define procexited(id)        (kill((id), 0) < 0 && errno==ESRCH)
       -
       -static int multi;
       -static Proc *theproc;
       -
       -/*
       - * Run all execs forked from a special exec proc.
       - */
       -#include "execproc.ch"
       -
       -/*
       - * Use _exits to exit one proc, and signals to tear everyone else down.
       - */
       -#include "exit-getpid.ch"
       -
       -/*
       - * Use table for _threadmultiproc, _threadsetproc, _threadgetproc.
       - */
       -#include "proctab.ch"
       -
       -/*
       - * Use per-process stack allocation code.
       - */
       -#include "procstack.ch"
       -
       -/*
       - * Implement _threadstartproc using clone.
       - * 
       - * Cannot use this on newer kernels (2.6+) because
       - * on those kernels clone allows you to set up a per-thread
       - * segment using %gs, and the C library and compilers
       - * assume that you've done this.  I don't want to learn
       - * how to do this (the code below is scary enough),
       - * so on those more recent kernels we use nptl (the
       - * pthreads implementation), which is finally good enough.
       - */
       -
       -/*
       - * Trampoline to run f(arg).
       - */
       -static int
       -tramp(void *v)
       -{
       -        void (*fn)(void*), *arg;
       -        void **v2;
       -        void *p;
       -
       -        v2 = v;
       -        fn = v2[0];
       -        arg = v2[1];
       -        p = v2[2];
       -        free(v2);
       -        fn(arg);
       -        abort();        /* not reached! */
       -        return 0;
       -}
       -
       -/*
       - * Trampnowait runs in the child, and starts a granchild to run f(arg).
       - * When trampnowait proc exits, the connection between the
       - * grandchild running f(arg) and the parent/grandparent is lost, so the
       - * grandparent need not worry about cleaning up a zombie
       - * when the grandchild finally exits.
       - */
       -static int
       -trampnowait(void *v)
       -{
       -        int pid;
       -        int cloneflag;
       -        void **v2;
       -        int *pidp;
       -        void *p;
       -
       -        v2 = v;
       -        cloneflag = (int)v2[4];
       -        pidp = v2[3];
       -        p = v2[2];
       -        pid = clone(tramp, p+fforkstacksize-512, cloneflag, v);
       -        *pidp = pid;
       -        _exit(0);
       -        return 0;
       -}
       -
       -static int
       -ffork(int flags, void (*fn)(void*), void *arg)
       -{
       -        void **v;
       -        char *p;
       -        int cloneflag, pid, thepid, status, nowait;
       -
       -        p = mallocstack();
       -        v = malloc(sizeof(void*)*5);
       -        if(p==nil || v==nil){
       -                freestack(p);
       -                free(v);
       -                return -1;
       -        }
       -        cloneflag = 0;
       -        flags &= ~RFPROC;
       -        if(flags&RFMEM){
       -                cloneflag |= CLONE_VM;
       -                flags &= ~RFMEM;
       -        }
       -        if(!(flags&RFFDG))
       -                cloneflag |= CLONE_FILES;
       -        else
       -                flags &= ~RFFDG;
       -        nowait = flags&RFNOWAIT;
       -//        if(!(flags&RFNOWAIT))
       -//                cloneflag |= SIGCHLD;
       -//        else
       -                flags &= ~RFNOWAIT;
       -        if(flags){
       -                fprint(2, "unknown rfork flags %x\n", flags);
       -                freestack(p);
       -                free(v);
       -                return -1;
       -        }
       -        v[0] = fn;
       -        v[1] = arg;
       -        v[2] = p;
       -        v[3] = &thepid;
       -        v[4] = (void*)cloneflag;
       -        thepid = -1;
       -        pid = clone(nowait ? trampnowait : tramp, p+fforkstacksize-16, cloneflag, v);
       -        if(pid > 0 && nowait){
       -                if(wait4(pid, &status, __WALL, 0) < 0)
       -                        fprint(2, "ffork wait4: %r\n");
       -        }else
       -                thepid = pid;
       -        if(thepid == -1)
       -                freestack(p);
       -        else{
       -                ((Stack*)p)->pid = thepid;
       -        }
       -        return thepid;
       -}
       -
       -/*
       - * Called to start a new proc.
       - */
       -void
       -_threadstartproc(Proc *p)
       -{
       -        int pid;
       -        Proc *np;
       -
       -        np = p->newproc;
       -        pid = ffork(RFPROC|RFMEM|RFNOWAIT, _threadscheduler, np);
       -        if(pid == -1)
       -                sysfatal("starting new proc: %r");
       -        np->pid = pid;
       -}
       -
       -/*
       - * Called to associate p with the current pthread.
       - */
       -void
       -_threadinitproc(Proc *p)
       -{
       -        sigset_t mask;
       -
       -        p->pid = getpid();
       -        sigemptyset(&mask);
       -        sigaddset(&mask, WAITSIG);
       -        sigprocmask(SIG_BLOCK, &mask, nil);
       -        _threadsetproc(p);
       -}
       -
       -/*
       - * Called from mainlauncher before threadmain.
       - */
       -void
       -_threadmaininit(void)
       -{
       -}
       -
 (DIR) diff --git a/src/libthread/NOTICE b/src/libthread/NOTICE
       t@@ -1,19 +0,0 @@
       -/*
       - * The authors of this software are Russ Cox, Sape Mullender, and Rob Pike.
       - *                Copyright (c) 2003 by Lucent Technologies.
       - * Permission to use, copy, modify, and distribute this software for any
       - * purpose without fee is hereby granted, provided that this entire notice
       - * is included in all copies of any software which is or includes a copy
       - * or modification of this software and in all copies of the supporting
       - * documentation for such software.
       - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
       - * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
       - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
       - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
       -*/
       -
       -This is a Unix port of the Plan 9 thread library.
       -
       -Please send comments about the packaging
       -to Russ Cox <rsc@post.harvard.edu>.
       -
 (DIR) diff --git a/src/libthread/PowerMacintosh.c b/src/libthread/PowerMacintosh.c
       t@@ -1,39 +0,0 @@
       -#include "threadimpl.h"
       -
       -static void
       -launcherpower(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
       -        void (*f)(void *arg), void *arg)
       -{
       -        (*f)(arg);
       -        threadexits(nil);
       -}
       -
       -void
       -_threadinitstack(Thread *t, void (*f)(void*), void *arg)
       -{
       -        ulong *tos, *stk;
       -
       -        tos = (ulong*)&t->stk[t->stksize&~7];
       -        stk = tos;
       -        --stk;
       -        --stk;
       -        --stk;
       -        --stk;
       -        *--stk = (ulong)arg;
       -        *--stk = (ulong)f;
       -        t->sched.pc = (ulong)launcherpower+LABELDPC;
       -        t->sched.sp = (ulong)tos-80;
       -}
       -
       -void
       -_threadinswitch(int enter)
       -{
       -        USED(enter);
       -}
       -
       -void
       -_threadstacklimit(void *addr, void *addr2)
       -{
       -        USED(addr);
       -}
       -
 (DIR) diff --git a/src/libthread/README b/src/libthread/README
       t@@ -1,19 +0,0 @@
       -/*
       - * The authors of this software are Russ Cox, Sape Mullender, and Rob Pike.
       - *                Copyright (c) 2003 by Lucent Technologies.
       - * Permission to use, copy, modify, and distribute this software for any
       - * purpose without fee is hereby granted, provided that this entire notice
       - * is included in all copies of any software which is or includes a copy
       - * or modification of this software and in all copies of the supporting
       - * documentation for such software.
       - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
       - * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
       - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
       - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
       -*/
       -
       -This is a Unix port of the Plan 9 thread library.
       -
       -Please send comments about the packaging
       -to Russ Cox <rsc@post.harvard.edu>.
       -
 (DIR) diff --git a/src/libthread/asm-Darwin-PowerMacintosh.s b/src/libthread/asm-Darwin-PowerMacintosh.s
       t@@ -1,80 +0,0 @@
       -/* get FPR and VR use flags with sc 0x7FF3 */
       -/* get vsave with mfspr reg, 256 */
       -
       -.text
       -.align 2
       -
       -.globl        __setlabel
       -
       -__setlabel:                                /* 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)
       -
       -        stw        r13, (0+6)*4(r3)        /* callee-save GPRs */
       -        stw        r14, (1+6)*4(r3)        /* xxx: block move */
       -        stw        r15, (2+6)*4(r3)
       -        stw        r16, (3+6)*4(r3)
       -        stw        r17, (4+6)*4(r3)
       -        stw        r18, (5+6)*4(r3)
       -        stw        r19, (6+6)*4(r3)
       -        stw        r20, (7+6)*4(r3)
       -        stw        r21, (8+6)*4(r3)
       -        stw        r22, (9+6)*4(r3)
       -        stw        r23, (10+6)*4(r3)
       -        stw        r24, (11+6)*4(r3)
       -        stw        r25, (12+6)*4(r3)
       -        stw        r26, (13+6)*4(r3)
       -        stw        r27, (14+6)*4(r3)
       -        stw        r28, (15+6)*4(r3)
       -        stw        r29, (16+6)*4(r3)
       -        stw        r30, (17+6)*4(r3)
       -        stw        r31, (18+6)*4(r3)
       -
       -        li        r3, 0                        /* return */
       -        blr
       -
       -.globl        __gotolabel
       -
       -__gotolabel:
       -        lwz        r13, (0+6)*4(r3)        /* callee-save GPRs */
       -        lwz        r14, (1+6)*4(r3)        /* xxx: block move */
       -        lwz        r15, (2+6)*4(r3)
       -        lwz        r16, (3+6)*4(r3)
       -        lwz        r17, (4+6)*4(r3)
       -        lwz        r18, (5+6)*4(r3)
       -        lwz        r19, (6+6)*4(r3)
       -        lwz        r20, (7+6)*4(r3)
       -        lwz        r21, (8+6)*4(r3)
       -        lwz        r22, (9+6)*4(r3)
       -        lwz        r23, (10+6)*4(r3)
       -        lwz        r24, (11+6)*4(r3)
       -        lwz        r25, (12+6)*4(r3)
       -        lwz        r26, (13+6)*4(r3)
       -        lwz        r27, (14+6)*4(r3)
       -        lwz        r28, (15+6)*4(r3)
       -        lwz        r29, (16+6)*4(r3)
       -        lwz        r30, (17+6)*4(r3)
       -        lwz        r31, (18+6)*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
       -        li        r3, 1
       -        blr
 (DIR) diff --git a/src/libthread/asm-FreeBSD-386.s b/src/libthread/asm-FreeBSD-386.s
       t@@ -1,55 +0,0 @@
       -.globl        _setlabel
       -.type        _setlabel,@function
       -
       -_setlabel:
       -        movl        4(%esp), %eax
       -        movl        0(%esp), %edx
       -        movl        %edx, 0(%eax)
       -        movl        %ebx, 4(%eax)
       -        movl        %esp, 8(%eax)
       -        movl        %ebp, 12(%eax)
       -        movl        %esi, 16(%eax)
       -        movl        %edi, 20(%eax)
       -        xorl        %eax, %eax
       -        ret
       -
       -.globl        _gotolabel
       -.type        _gotolabel,@function
       -
       -_gotolabel:
       -        pushl $1
       -        call _threadinswitch
       -        popl %eax
       -        movl        4(%esp), %edx
       -        movl        0(%edx), %ecx
       -        movl        4(%edx), %ebx
       -        movl        8(%edx), %esp
       -        movl        12(%edx), %ebp
       -        movl        16(%edx), %esi
       -        movl        20(%edx), %edi
       -        movl        %ecx, 0(%esp)
       -        pushl $0
       -        call _threadinswitch
       -        popl %eax
       -        xorl        %eax, %eax
       -        incl        %eax
       -        ret
       -
       -
       -# .globl        _xinc
       -# _xinc:
       -#         movl 4(%esp), %eax
       -#         lock incl 0(%eax)
       -#         ret
       -# 
       -# .globl        _xdec
       -# _xdec:
       -#         movl 4(%esp), %eax
       -#         lock decl 0(%eax)
       -#         jz iszero
       -#         movl $1, %eax
       -#         ret
       -# iszero:
       -#         movl $0, %eax
       -#         ret
       -# 
 (DIR) diff --git a/src/libthread/asm-Linux-386.s b/src/libthread/asm-Linux-386.s
       t@@ -1 +0,0 @@
       -.include "asm-FreeBSD-386.s"
 (DIR) diff --git a/src/libthread/asm-Linux-power.s b/src/libthread/asm-Linux-power.s
       t@@ -1,80 +0,0 @@
       -/* get FPR and VR use flags with sc 0x7FF3 */
       -/* get vsave with mfspr reg, 256 */
       -
       -.text
       -.align 2
       -
       -.globl        _setlabel
       -
       -_setlabel:                                /* xxx: instruction scheduling */
       -        mflr        0
       -        mfcr        5
       -        mfctr        6
       -        mfxer        7
       -        stw        0, 0*4(3)
       -        stw        5, 1*4(3)
       -        stw        6, 2*4(3)
       -        stw        7, 3*4(3)
       -
       -        stw        1, 4*4(3)
       -        stw        2, 5*4(3)
       -
       -        stw        13, (0+6)*4(3)        /* callee-save GPRs */
       -        stw        14, (1+6)*4(3)        /* xxx: block move */
       -        stw        15, (2+6)*4(3)
       -        stw        16, (3+6)*4(3)
       -        stw        17, (4+6)*4(3)
       -        stw        18, (5+6)*4(3)
       -        stw        19, (6+6)*4(3)
       -        stw        20, (7+6)*4(3)
       -        stw        21, (8+6)*4(3)
       -        stw        22, (9+6)*4(3)
       -        stw        23, (10+6)*4(3)
       -        stw        24, (11+6)*4(3)
       -        stw        25, (12+6)*4(3)
       -        stw        26, (13+6)*4(3)
       -        stw        27, (14+6)*4(3)
       -        stw        28, (15+6)*4(3)
       -        stw        29, (16+6)*4(3)
       -        stw        30, (17+6)*4(3)
       -        stw        31, (18+6)*4(3)
       -
       -        li        3, 0                        /* return */
       -        blr
       -
       -.globl        _gotolabel
       -
       -_gotolabel:
       -        lwz        13, (0+6)*4(3)        /* callee-save GPRs */
       -        lwz        14, (1+6)*4(3)        /* xxx: block move */
       -        lwz        15, (2+6)*4(3)
       -        lwz        16, (3+6)*4(3)
       -        lwz        17, (4+6)*4(3)
       -        lwz        18, (5+6)*4(3)
       -        lwz        19, (6+6)*4(3)
       -        lwz        20, (7+6)*4(3)
       -        lwz        21, (8+6)*4(3)
       -        lwz        22, (9+6)*4(3)
       -        lwz        23, (10+6)*4(3)
       -        lwz        24, (11+6)*4(3)
       -        lwz        25, (12+6)*4(3)
       -        lwz        26, (13+6)*4(3)
       -        lwz        27, (14+6)*4(3)
       -        lwz        28, (15+6)*4(3)
       -        lwz        29, (16+6)*4(3)
       -        lwz        30, (17+6)*4(3)
       -        lwz        31, (18+6)*4(3)
       -
       -        lwz        1, 4*4(3)
       -        lwz        2, 5*4(3)
       -
       -        lwz        0, 0*4(3)
       -        mtlr        0
       -        lwz        0, 1*4(3)
       -        mtcr        0                        /* mtcrf 0xFF, r0 */
       -        lwz        0, 2*4(3)
       -        mtctr        0
       -        lwz        0, 3*4(3)
       -        mtxer        0
       -        li        3, 1
       -        blr
 (DIR) diff --git a/src/libthread/asm-OpenBSD-386.s b/src/libthread/asm-OpenBSD-386.s
       t@@ -1,49 +0,0 @@
       -.globl        _setlabel
       -.type        _setlabel,@function
       -
       -_setlabel:
       -        movl        4(%esp), %eax
       -        movl        0(%esp), %edx
       -        movl        %edx, 0(%eax)
       -        movl        %ebx, 4(%eax)
       -        movl        %esp, 8(%eax)
       -        movl        %ebp, 12(%eax)
       -        movl        %esi, 16(%eax)
       -        movl        %edi, 20(%eax)
       -        xorl        %eax, %eax
       -        ret
       -
       -.globl        _gotolabel
       -.type        _gotolabel,@function
       -
       -_gotolabel:
       -        movl        4(%esp), %edx
       -        movl        0(%edx), %ecx
       -        movl        4(%edx), %ebx
       -        movl        8(%edx), %esp
       -        movl        12(%edx), %ebp
       -        movl        16(%edx), %esi
       -        movl        20(%edx), %edi
       -        xorl        %eax, %eax
       -        incl        %eax
       -        movl        %ecx, 0(%esp)
       -        ret
       -
       -
       -# .globl        _xinc
       -# _xinc:
       -#         movl 4(%esp), %eax
       -#         lock incl 0(%eax)
       -#         ret
       -# 
       -# .globl        _xdec
       -# _xdec:
       -#         movl 4(%esp), %eax
       -#         lock decl 0(%eax)
       -#         jz iszero
       -#         movl $1, %eax
       -#         ret
       -# iszero:
       -#         movl $0, %eax
       -#         ret
       -# 
 (DIR) diff --git a/src/libthread/asm-SunOS-sun4u.s b/src/libthread/asm-SunOS-sun4u.s
       t@@ -1,51 +0,0 @@
       -.globl _setlabel
       -.type  _setlabel,#function
       -
       -_setlabel:
       -        ta        3
       -        st        %i0, [%o0]
       -        st        %i1, [%o0+4]
       -        st        %i2, [%o0+8]
       -        st        %i3, [%o0+12]
       -        st        %i4, [%o0+16]
       -        st        %i5, [%o0+20]
       -        st        %i6, [%o0+24]
       -        st        %i7, [%o0+28]
       -        st        %l0, [%o0+32]
       -        st        %l1, [%o0+36]
       -        st        %l2, [%o0+40]
       -        st        %l3, [%o0+44]
       -        st        %l4, [%o0+48]
       -        st        %l5, [%o0+52]
       -        st        %l6, [%o0+56]
       -        st        %l7, [%o0+60]
       -        st        %sp, [%o0+64]
       -        st        %o7, [%o0+68]
       -        jmpl        %o7+8, %g0
       -        or        %g0, %g0, %o0
       -
       -.globl _gotolabel
       -.type        _gotolabel,#function
       -
       -_gotolabel:
       -        ta        3
       -        ld        [%o0], %i0
       -        ld        [%o0+4], %i1
       -        ld        [%o0+8], %i2
       -        ld        [%o0+12], %i3
       -        ld        [%o0+16], %i4
       -        ld        [%o0+20], %i5
       -        ld        [%o0+24], %i6
       -        ld        [%o0+28], %i7
       -        ld        [%o0+32], %l0
       -        ld        [%o0+36], %l1
       -        ld        [%o0+40], %l2
       -        ld        [%o0+44], %l3
       -        ld        [%o0+48], %l4
       -        ld        [%o0+52], %l5
       -        ld        [%o0+56], %l6
       -        ld        [%o0+60], %l7
       -        ld        [%o0+64], %sp
       -        ld        [%o0+68], %o7
       -        jmpl        %o7+8, %g0
       -        or        %g0, 1, %o0
 (DIR) diff --git a/src/libthread/channel.c b/src/libthread/channel.c
       t@@ -1,500 +0,0 @@
       -#include "threadimpl.h"
       -
       -static Lock chanlock;                /* central channel access lock */
       -
       -static void enqueue(Alt*, Thread*);
       -static void dequeue(Alt*);
       -static int altexec(Alt*);
       -
       -int _threadhighnentry;
       -int _threadnalt;
       -
       -static void
       -setuserpc(ulong pc)
       -{
       -        Thread *t;
       -
       -        t = _threadgetproc()->thread;
       -        if(t)
       -                t->userpc = pc;
       -}
       -
       -static int
       -canexec(Alt *a)
       -{
       -        int i, otherop;
       -        Channel *c;
       -
       -        c = a->c;
       -        /* are there senders or receivers blocked? */
       -        otherop = (CHANSND+CHANRCV) - a->op;
       -        for(i=0; i<c->nentry; i++)
       -                if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->thread->altc==nil){
       -                        _threaddebug(DBGCHAN, "can rendez alt %p chan %p", a, c);
       -                        return 1;
       -                }
       -
       -        /* is there room in the channel? */
       -        if((a->op==CHANSND && c->n < c->s)
       -        || (a->op==CHANRCV && c->n > 0)){
       -                _threaddebug(DBGCHAN, "can buffer alt %p chan %p", a, c);
       -                return 1;
       -        }
       -
       -        return 0;
       -}
       -
       -static void
       -_chanfree(Channel *c)
       -{
       -        int i, inuse;
       -
       -        inuse = 0;
       -        for(i = 0; i < c->nentry; i++)
       -                if(c->qentry[i])
       -                        inuse = 1;
       -        if(inuse)
       -                c->freed = 1;
       -        else{
       -                if(c->qentry)
       -                        free(c->qentry);
       -                free(c);
       -        }
       -}
       -
       -void
       -chanfree(Channel *c)
       -{
       -        lock(&chanlock);
       -        _chanfree(c);
       -        unlock(&chanlock);
       -}
       -
       -int
       -chaninit(Channel *c, int elemsize, int elemcnt)
       -{
       -        if(elemcnt < 0 || elemsize <= 0 || c == nil)
       -                return -1;
       -        memset(c, 0, sizeof *c);
       -        c->e = elemsize;
       -        c->s = elemcnt;
       -        _threaddebug(DBGCHAN, "chaninit %p", c);
       -        return 1;
       -}
       -
       -Channel*
       -chancreate(int elemsize, int elemcnt)
       -{
       -        Channel *c;
       -
       -        if(elemcnt < 0 || elemsize <= 0)
       -                return nil;
       -        c = _threadmalloc(sizeof(Channel)+elemsize*elemcnt, 1);
       -        c->e = elemsize;
       -        c->s = elemcnt;
       -        _threaddebug(DBGCHAN, "chancreate %p", c);
       -        return c;
       -}
       -
       -static int
       -_alt(Alt *alts)
       -{
       -        Alt *a, *xa;
       -        Channel *c;
       -        int n;
       -        Thread *t;
       -
       -        /*
       -         * The point of going splhi here is that note handlers
       -         * might reasonably want to use channel operations,
       -         * but that will hang if the note comes while we hold the
       -         * chanlock.  Instead, we delay the note until we've dropped
       -         * the lock.
       -         */
       -
       -        /*
       -         * T might be nil here -- the scheduler sends on threadwaitchan
       -         * directly (in non-blocking mode, of course!).
       -         */
       -        t = _threadgetproc()->thread;
       -        if((t && t->moribund) || _threadexitsallstatus)
       -                yield();        /* won't return */
       -        lock(&chanlock);
       -
       -        /* test whether any channels can proceed */
       -        n = 0;
       -        a = nil;
       -
       -        for(xa=alts; xa->op!=CHANEND && xa->op!=CHANNOBLK; xa++){
       -                xa->entryno = -1;
       -                if(xa->op == CHANNOP)
       -                        continue;
       -
       -                c = xa->c;
       -                if(c==nil){
       -                        unlock(&chanlock);
       -                        return -1;
       -                }
       -                if(canexec(xa))
       -                        if(nrand(++n) == 0)
       -                                a = xa;
       -        }
       -
       -        if(a==nil){
       -                /* nothing can proceed */
       -                if(xa->op == CHANNOBLK){
       -                        unlock(&chanlock);
       -                        _threadnalt++;
       -                        return xa - alts;
       -                }
       -
       -                /* enqueue on all channels. */
       -                t->altc = nil;
       -                for(xa=alts; xa->op!=CHANEND; xa++){
       -                        if(xa->op==CHANNOP)
       -                                continue;
       -                        enqueue(xa, t);
       -                }
       -
       -                /*
       -                 * wait for successful rendezvous.
       -                 * we can't just give up if the rendezvous
       -                 * is interrupted -- someone else might come
       -                 * along and try to rendezvous with us, so
       -                 * we need to be here.
       -                 *
       -                 * actually, now we're assuming no interrupts.
       -                 */
       -            /*Again:*/
       -                t->alt = alts;
       -                t->chan = Chanalt;
       -                t->altrend.l = &chanlock;
       -                _threadsleep(&t->altrend);
       -
       -                /* dequeue from channels, find selected one */
       -                a = nil;
       -                c = t->altc;
       -                for(xa=alts; xa->op!=CHANEND; xa++){
       -                        if(xa->op==CHANNOP)
       -                                continue;
       -                        if(xa->c == c)
       -                                a = xa;
       -                        dequeue(xa);
       -                }
       -                unlock(&chanlock);
       -                if(a == nil){        /* we were interrupted */
       -                        assert(c==(Channel*)~0);
       -                        return -1;
       -                }
       -        }else{
       -                altexec(a);        /* unlocks chanlock, does splx */
       -        }
       -        if(t)
       -                t->chan = Channone;
       -        return a - alts;
       -}
       -
       -int
       -alt(Alt *alts)
       -{
       -        setuserpc(getcallerpc(&alts));
       -        return _alt(alts);
       -}
       -
       -static int
       -runop(int op, Channel *c, void *v, int nb)
       -{
       -        int r;
       -        Alt a[2];
       -
       -        /*
       -         * we could do this without calling alt,
       -         * but the only reason would be performance,
       -         * and i'm not convinced it matters.
       -         */
       -        a[0].op = op;
       -        a[0].c = c;
       -        a[0].v = v;
       -        a[1].op = CHANEND;
       -        if(nb)
       -                a[1].op = CHANNOBLK;
       -        switch(r=_alt(a)){
       -        case -1:        /* interrupted */
       -                return -1;
       -        case 1:        /* nonblocking, didn't accomplish anything */
       -                assert(nb);
       -                return 0;
       -        case 0:
       -                return 1;
       -        default:
       -                fprint(2, "ERROR: channel alt returned %d\n", r);
       -                abort();
       -                return -1;
       -        }
       -}
       -
       -int
       -recv(Channel *c, void *v)
       -{
       -        setuserpc(getcallerpc(&c));
       -        return runop(CHANRCV, c, v, 0);
       -}
       -
       -int
       -nbrecv(Channel *c, void *v)
       -{
       -        setuserpc(getcallerpc(&c));
       -        return runop(CHANRCV, c, v, 1);
       -}
       -
       -int
       -send(Channel *c, void *v)
       -{
       -        setuserpc(getcallerpc(&c));
       -        return runop(CHANSND, c, v, 0);
       -}
       -
       -int
       -nbsend(Channel *c, void *v)
       -{
       -        setuserpc(getcallerpc(&c));
       -        return runop(CHANSND, c, v, 1);
       -}
       -
       -static void
       -channelsize(Channel *c, int sz)
       -{
       -        if(c->e != sz){
       -                fprint(2, "expected channel with elements of size %d, got size %d\n",
       -                        sz, c->e);
       -                abort();
       -        }
       -}
       -
       -int
       -sendul(Channel *c, ulong v)
       -{
       -        setuserpc(getcallerpc(&c));
       -        channelsize(c, sizeof(ulong));
       -        return send(c, &v);
       -}
       -
       -ulong
       -recvul(Channel *c)
       -{
       -        ulong v;
       -
       -        setuserpc(getcallerpc(&c));
       -        channelsize(c, sizeof(ulong));
       -        if(runop(CHANRCV, c, &v, 0) < 0)
       -                return ~0;
       -        return v;
       -}
       -
       -int
       -sendp(Channel *c, void *v)
       -{
       -        setuserpc(getcallerpc(&c));
       -        channelsize(c, sizeof(void*));
       -        return runop(CHANSND, c, &v, 0);
       -}
       -
       -void*
       -recvp(Channel *c)
       -{
       -        void *v;
       -
       -        setuserpc(getcallerpc(&c));
       -        channelsize(c, sizeof(void*));
       -        if(runop(CHANRCV, c, &v, 0) < 0)
       -                return nil;
       -        return v;
       -}
       -
       -int
       -nbsendul(Channel *c, ulong v)
       -{
       -        setuserpc(getcallerpc(&c));
       -        channelsize(c, sizeof(ulong));
       -        return runop(CHANSND, c, &v, 1);
       -}
       -
       -ulong
       -nbrecvul(Channel *c)
       -{
       -        ulong v;
       -
       -        setuserpc(getcallerpc(&c));
       -        channelsize(c, sizeof(ulong));
       -        if(runop(CHANRCV, c, &v, 1) == 0)
       -                return 0;
       -        return v;
       -}
       -
       -int
       -nbsendp(Channel *c, void *v)
       -{
       -        setuserpc(getcallerpc(&c));
       -        channelsize(c, sizeof(void*));
       -        return runop(CHANSND, c, &v, 1);
       -}
       -
       -void*
       -nbrecvp(Channel *c)
       -{
       -        void *v;
       -
       -        setuserpc(getcallerpc(&c));
       -        channelsize(c, sizeof(void*));
       -        if(runop(CHANRCV, c, &v, 1) == 0)
       -                return nil;
       -        return v;
       -}
       -
       -static int
       -emptyentry(Channel *c)
       -{
       -        int i, extra;
       -
       -        assert((c->nentry==0 && c->qentry==nil) || (c->nentry && c->qentry));
       -
       -        for(i=0; i<c->nentry; i++)
       -                if(c->qentry[i]==nil)
       -                        return i;
       -
       -        extra = 16;
       -        c->nentry += extra;
       -if(c->nentry > _threadhighnentry) _threadhighnentry = c->nentry;
       -        c->qentry = realloc((void*)c->qentry, c->nentry*sizeof(c->qentry[0]));
       -        if(c->qentry == nil)
       -                sysfatal("realloc channel entries: %r");
       -        _threadmemset(&c->qentry[i], 0, extra*sizeof(c->qentry[0]));
       -        return i;
       -}
       -
       -static void
       -enqueue(Alt *a, Thread *t)
       -{
       -        int i;
       -
       -        _threaddebug(DBGCHAN, "Queueing alt %p on channel %p", a, a->c);
       -        a->thread = t;
       -        i = emptyentry(a->c);
       -        a->c->qentry[i] = a;
       -}
       -
       -static void
       -dequeue(Alt *a)
       -{
       -        int i;
       -        Channel *c;
       -
       -        c = a->c;
       -        for(i=0; i<c->nentry; i++)
       -                if(c->qentry[i]==a){
       -                        _threaddebug(DBGCHAN, "Dequeuing alt %p from channel %p", a, a->c);
       -                        c->qentry[i] = nil;
       -                        if(c->freed)
       -                                _chanfree(c);
       -                        return;
       -                }
       -}
       -
       -static void*
       -altexecbuffered(Alt *a, int willreplace)
       -{
       -        uchar *v;
       -        Channel *c;
       -
       -        c = a->c;
       -        /* use buffered channel queue */
       -        if(a->op==CHANRCV && c->n > 0){
       -                _threaddebug(DBGCHAN, "buffer recv alt %p chan %p", a, c);
       -                v = c->v + c->e*(c->f%c->s);
       -                if(!willreplace)
       -                        c->n--;
       -                c->f++;
       -                return v;
       -        }
       -        if(a->op==CHANSND && c->n < c->s){
       -                _threaddebug(DBGCHAN, "buffer send alt %p chan %p", a, c);
       -                v = c->v + c->e*((c->f+c->n)%c->s);
       -                if(!willreplace)
       -                        c->n++;
       -                return v;
       -        }
       -        abort();
       -        return nil;
       -}
       -
       -static void
       -altcopy(void *dst, void *src, int sz)
       -{
       -        if(dst){
       -                if(src)
       -                        memmove(dst, src, sz);
       -                else
       -                        _threadmemset(dst, 0, sz);
       -        }
       -}
       -
       -static int
       -altexec(Alt *a)
       -{
       -        volatile Alt *b;
       -        int i, n, otherop;
       -        Channel *c;
       -        void *me, *waiter, *buf;
       -
       -        c = a->c;
       -
       -        /* rendezvous with others */
       -        otherop = (CHANSND+CHANRCV) - a->op;
       -        n = 0;
       -        b = nil;
       -        me = a->v;
       -        for(i=0; i<c->nentry; i++)
       -                if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->thread->altc==nil)
       -                        if(nrand(++n) == 0)
       -                                b = c->qentry[i];
       -        if(b != nil){
       -                _threaddebug(DBGCHAN, "rendez %s alt %p chan %p alt %p", a->op==CHANRCV?"recv":"send", a, c, b);
       -                waiter = b->v;
       -                if(c->s && c->n){
       -                        /*
       -                         * if buffer is full and there are waiters
       -                         * and we're meeting a waiter,
       -                         * we must be receiving.
       -                         *
       -                         * we use the value in the channel buffer,
       -                         * copy the waiter's value into the channel buffer
       -                         * on behalf of the waiter, and then wake the waiter.
       -                         */
       -                        if(a->op!=CHANRCV)
       -                                abort();
       -                        buf = altexecbuffered(a, 1);
       -                        altcopy(me, buf, c->e);
       -                        altcopy(buf, waiter, c->e);
       -                }else{
       -                        if(a->op==CHANRCV)
       -                                altcopy(me, waiter, c->e);
       -                        else
       -                                altcopy(waiter, me, c->e);
       -                }
       -                b->thread->altc = c;
       -                _threadwakeup(&b->thread->altrend);
       -                _threaddebug(DBGCHAN, "chanlock is %lud", *(ulong*)(void*)&chanlock);
       -                _threaddebug(DBGCHAN, "unlocking the chanlock");
       -                unlock(&chanlock);
       -                return 1;
       -        }
       -
       -        buf = altexecbuffered(a, 0);
       -        if(a->op==CHANRCV)
       -                altcopy(me, buf, c->e);
       -        else
       -                altcopy(buf, me, c->e);
       -
       -        unlock(&chanlock);
       -        return 1;
       -}
 (DIR) diff --git a/src/libthread/chanprint.c b/src/libthread/chanprint.c
       t@@ -1,20 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -
       -int
       -chanprint(Channel *c, char *fmt, ...)
       -{
       -        va_list arg;
       -        char *p;
       -        int n;
       -
       -        va_start(arg, fmt);
       -        p = vsmprint(fmt, arg);
       -        va_end(arg);
       -        if(p == nil)
       -                sysfatal("vsmprint failed: %r");
       -        n = sendp(c, p);
       -        yield();        /* let recipient handle message immediately */
       -        return n;
       -}
 (DIR) diff --git a/src/libthread/create.c b/src/libthread/create.c
       t@@ -1,211 +0,0 @@
       -#include "threadimpl.h"
       -
       -Pqueue _threadpq;        /* list of all procs */
       -int _threadnprocs;        /* count of procs */
       -
       -static int newthreadid(void);
       -static int newprocid(void);
       -
       -/*
       - * Create and initialize a new Thread structure attached to a given proc.
       - */
       -int
       -_newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, 
       -        char *name, int grp)
       -{
       -        int id;
       -        Thread *t;
       -
       -        t = _threadmalloc(sizeof(Thread), 1);
       -        t->proc = p;
       -        t->nextproc = p;
       -        t->homeproc = p;
       -
       -        t->grp = grp;
       -        t->id = id = newthreadid();
       -        if(name)
       -                t->name = strdup(name);
       -        _threaddebug(DBGSCHED, "create thread %d.%d name %s", p->id, id, name);
       -
       -        /*
       -         * Allocate and clear stack.
       -         */
       -        if(stacksize < 1024)
       -                sysfatal("bad stacksize %d", stacksize);
       -        t->stk = _threadmalloc(stacksize, 0);
       -        t->stksize = stacksize;
       -        _threaddebugmemset(t->stk, 0xFE, stacksize);
       -
       -        /*
       -         * Set up t->context to call f(arg).
       -         */
       -        _threadinitstack(t, f, arg);
       -
       -        /*
       -         * Add thread to proc.
       -         */
       -        lock(&p->lock);
       -        _procaddthread(p, t);
       -
       -        /*
       -         * Mark thread as ready to run.
       -         */
       -        t->state = Ready;
       -        _threadready(t);
       -        unlock(&p->lock);
       -
       -        return id;
       -}
       -
       -/* 
       - * Free a Thread structure.
       - */
       -void
       -_threadfree(Thread *t)
       -{
       -        free(t->stk);
       -        free(t->name);
       -        free(t);
       -}
       -
       -/*
       - * Create and initialize a new Proc structure with a single Thread
       - * running inside it.  Add the Proc to the global process list.
       - */
       -Proc*
       -_newproc(void)
       -{
       -        Proc *p;
       -
       -        /*
       -         * Allocate.
       -         */
       -        p = _threadmalloc(sizeof *p, 1);
       -        p->id = newprocid();
       -        
       -        /*
       -         * Add to list.  Record if we're now multiprocess.
       -         */
       -        lock(&_threadpq.lock);
       -        if(_threadpq.head == nil)
       -                _threadpq.head = p;
       -        else
       -                *_threadpq.tail = p;
       -        _threadpq.tail = &p->next;
       -        if(_threadnprocs == 1)
       -                _threadmultiproc();
       -        _threadnprocs++;
       -        unlock(&_threadpq.lock);
       -
       -        return p;
       -}
       -
       -/*
       - * Allocate a new thread running f(arg) on a stack of size stacksize.
       - * Return the thread id.  The thread group inherits from the current thread.
       - */
       -int
       -threadcreate(void (*f)(void*), void *arg, uint stacksize)
       -{
       -        return _newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
       -}
       -
       -/* 
       - * Allocate a new idle thread.  Only allowed in a single-proc program.
       - */
       -int
       -threadcreateidle(void (*f)(void *arg), void *arg, uint stacksize)
       -{
       -        int id;
       -
       -        assert(_threadpq.head->next == nil);        /* only 1 */
       -
       -        id = threadcreate(f, arg, stacksize);
       -        _threaddebug(DBGSCHED, "idle is %d", id);
       -        _threadsetidle(id);
       -        return id;
       -}
       -
       -/*
       - * Threadcreate, but do it inside a fresh proc.
       - */
       -int
       -proccreate(void (*f)(void*), void *arg, uint stacksize)
       -{
       -        int id;
       -        Proc *p, *np;
       -
       -        p = _threadgetproc();
       -        np = _newproc();
       -        p->newproc = np;
       -        p->schedfn = _kthreadstartproc;
       -        id = _newthread(np, f, arg, stacksize, nil, p->thread->grp);
       -        _sched();        /* call into scheduler to create proc XXX */
       -        return id;
       -}
       -
       -/*
       - * Allocate a new thread id.
       - */
       -static int
       -newthreadid(void)
       -{
       -        static Lock l;
       -        static int id;
       -        int i;
       -
       -        lock(&l);
       -        i = ++id;
       -        unlock(&l);
       -        return i;
       -}
       -
       -/*
       - * Allocate a new proc id.
       - */
       -static int
       -newprocid(void)
       -{
       -        static Lock l;
       -        static int id;
       -        int i;
       -
       -        lock(&l);
       -        i = ++id;
       -        unlock(&l);
       -        return i;
       -}
       -
       -/*
       - * Add thread to proc's list.
       - */
       -void
       -_procaddthread(Proc *p, Thread *t)
       -{
       -        p->nthreads++;
       -        if(p->threads.head == nil)
       -                p->threads.head = t;
       -        else{
       -                t->prevt = p->threads.tail;
       -                t->prevt->nextt = t;
       -        }
       -        p->threads.tail = t;
       -        t->next = (Thread*)~0;
       -}
       -
       -/*
       - * Remove thread from proc's list.
       - */
       -void
       -_procdelthread(Proc *p, Thread *t)
       -{
       -        if(t->prevt)
       -                t->prevt->nextt = t->nextt;
       -        else
       -                p->threads.head = t->nextt;
       -        if(t->nextt)
       -                t->nextt->prevt = t->prevt;
       -        else
       -                p->threads.tail = t->prevt;
       -        p->nthreads--;
       -}
 (DIR) diff --git a/src/libthread/debug.c b/src/libthread/debug.c
       t@@ -1,48 +0,0 @@
       -#include "threadimpl.h"
       -
       -int _threaddebuglevel;
       -
       -void
       -__threaddebug(ulong flag, char *fmt, ...)
       -{
       -        char buf[128];
       -        va_list arg;
       -        Fmt f;
       -        Proc *p;
       -
       -        if((_threaddebuglevel&flag) == 0)
       -                return;
       -
       -        fmtfdinit(&f, 2, buf, sizeof buf);
       -
       -        p = _threadgetproc();
       -        if(p==nil)
       -                fmtprint(&f, "noproc ");
       -        else if(p->thread)
       -                fmtprint(&f, "%d.%d ", p->id, p->thread->id);
       -        else
       -                fmtprint(&f, "%d._ ", p->id);
       -
       -        va_start(arg, fmt);
       -        fmtvprint(&f, fmt, arg);
       -        va_end(arg);
       -        fmtprint(&f, "\n");
       -        fmtfdflush(&f);
       -}
       -
       -void
       -_threadassert(char *s)
       -{
       -        char buf[256];
       -        int n;
       -        Proc *p;
       -
       -        p = _threadgetproc();
       -        if(p && p->thread)
       -                n = sprint(buf, "%d.%d ", p->pid, p->thread->id);
       -        else
       -                n = 0;
       -        snprint(buf+n, sizeof(buf)-n, "%s: assertion failed\n", s);
       -        write(2, buf, strlen(buf));
       -        abort();
       -}
 (DIR) diff --git a/src/libthread/exec-unix.c b/src/libthread/exec-unix.c
       t@@ -1,147 +0,0 @@
       -#include <u.h>
       -#include <fcntl.h>
       -#include <unistd.h>
       -#include "threadimpl.h"
       -
       -static void efork(int[3], int[2], char*, char**);
       -int
       -_threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
       -{
       -        int pfd[2];
       -        int n, pid;
       -        char exitstr[ERRMAX];
       -
       -        _threaddebug(DBGEXEC, "threadexec %s", prog);
       -
       -        /*
       -         * We want threadexec to behave like exec; if exec succeeds,
       -         * never return, and if it fails, return with errstr set.
       -         * Unfortunately, the exec happens in another proc since
       -         * we have to wait for the exec'ed process to finish.
       -         * To provide the semantics, we open a pipe with the 
       -         * write end close-on-exec and hand it to the proc that
       -         * is doing the exec.  If the exec succeeds, the pipe will
       -         * close so that our read below fails.  If the exec fails,
       -         * then the proc doing the exec sends the errstr down the
       -         * pipe to us.
       -         */
       -        if(pipe(pfd) < 0)
       -                goto Bad;
       -        if(fcntl(pfd[0], F_SETFD, 1) < 0)
       -                goto Bad;
       -        if(fcntl(pfd[1], F_SETFD, 1) < 0)
       -                goto Bad;
       -
       -        switch(pid = fork()){
       -        case -1:
       -                close(pfd[0]);
       -                close(pfd[1]);
       -                goto Bad;
       -        case 0:
       -                efork(fd, pfd, prog, args);
       -                _threaddebug(DBGSCHED, "exit after efork");
       -                _exit(0);
       -        default:
       -                if(freeargs)
       -                        free(args);
       -                break;
       -        }
       -
       -        close(pfd[1]);
       -        if((n = read(pfd[0], exitstr, ERRMAX-1)) > 0){        /* exec failed */
       -                exitstr[n] = '\0';
       -                errstr(exitstr, ERRMAX);
       -                close(pfd[0]);
       -                goto Bad;
       -        }
       -        close(pfd[0]);
       -        close(fd[0]);
       -        if(fd[1] != fd[0])
       -                close(fd[1]);
       -        if(fd[2] != fd[1] && fd[2] != fd[0])
       -                close(fd[2]);
       -        if(pidc)
       -                sendul(pidc, pid);
       -
       -        _threaddebug(DBGEXEC, "threadexec schedexecwait");
       -        return pid;
       -
       -Bad:
       -        _threaddebug(DBGEXEC, "threadexec bad %r");
       -        if(pidc)
       -                sendul(pidc, ~0);
       -        return -1;
       -}
       -
       -void
       -threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
       -{
       -        if(_kthreadexec(pidc, fd, prog, args, 0) >= 0)
       -                threadexits(nil);
       -}
       -
       -int
       -threadspawn(int fd[3], char *prog, char *args[])
       -{
       -        return _kthreadexec(nil, fd, prog, args, 0);
       -}
       -
       -/*
       - * The &f+1 trick doesn't work on SunOS, so we might 
       - * as well bite the bullet and do this correctly.
       - */
       -void
       -threadexecl(Channel *pidc, int fd[3], char *f, ...)
       -{
       -        char **args, *s;
       -        int n;
       -        va_list arg;
       -
       -        va_start(arg, f);
       -        for(n=0; va_arg(arg, char*) != 0; n++)
       -                ;
       -        n++;
       -        va_end(arg);
       -
       -        args = malloc(n*sizeof(args[0]));
       -        if(args == nil){
       -                if(pidc)
       -                        sendul(pidc, ~0);
       -                return;
       -        }
       -
       -        va_start(arg, f);
       -        for(n=0; (s=va_arg(arg, char*)) != 0; n++)
       -                args[n] = s;
       -        args[n] = 0;
       -        va_end(arg);
       -
       -        if(_kthreadexec(pidc, fd, f, args, 1) >= 0)
       -                threadexits(nil);
       -}
       -
       -static void
       -efork(int stdfd[3], int fd[2], char *prog, char **args)
       -{
       -        char buf[ERRMAX];
       -        int i;
       -
       -        _threaddebug(DBGEXEC, "_schedexec %s -- calling execv", prog);
       -        dup(stdfd[0], 0);
       -        dup(stdfd[1], 1);
       -        dup(stdfd[2], 2);
       -        for(i=3; i<40; i++)
       -                if(i != fd[1])
       -                        close(i);
       -        rfork(RFNOTEG);
       -        execvp(prog, args);
       -        _threaddebug(DBGEXEC, "_schedexec failed: %r");
       -        rerrstr(buf, sizeof buf);
       -        if(buf[0]=='\0')
       -                strcpy(buf, "exec failed");
       -        write(fd[1], buf, strlen(buf));
       -        close(fd[1]);
       -        _threaddebug(DBGSCHED, "_exits in exec-unix");
       -        _exits(buf);
       -}
       -
 (DIR) diff --git a/src/libthread/exec.c b/src/libthread/exec.c
       t@@ -0,0 +1,153 @@
       +#include "u.h"
       +#include <errno.h>
       +#include "libc.h"
       +#include "thread.h"
       +#include "threadimpl.h"
       +
       +static Lock thewaitlock;
       +static Channel *thewaitchan;
       +static Channel *dowaitchan;
       +
       +/* BUG - start waitproc on first exec, not when threadwaitchan is called */
       +static void
       +waitproc(void *v)
       +{
       +        Channel *c;
       +        Waitmsg *w;
       +
       +        _threadsetsysproc();
       +        for(;;){
       +                while((w = wait()) == nil){
       +                        if(errno == ECHILD)
       +                                recvul(dowaitchan);
       +                }
       +                if((c = thewaitchan) != nil)
       +                        sendp(c, w);
       +                else
       +                        free(w);
       +        }
       +}
       +
       +Channel*
       +threadwaitchan(void)
       +{
       +        if(thewaitchan)
       +                return thewaitchan;
       +        lock(&thewaitlock);
       +        if(thewaitchan){
       +                unlock(&thewaitlock);
       +                return thewaitchan;
       +        }
       +        thewaitchan = chancreate(sizeof(Waitmsg*), 4);
       +        chansetname(thewaitchan, "threadwaitchan");
       +        dowaitchan = chancreate(sizeof(ulong), 1);
       +        chansetname(dowaitchan, "dowaitchan");
       +        proccreate(waitproc, nil, STACK);
       +        unlock(&thewaitlock);
       +        return thewaitchan;
       +}
       +
       +int
       +threadspawn(int fd[3], char *cmd, char *argv[])
       +{
       +        int i, n, p[2], pid;
       +        char exitstr[100];
       +
       +        if(pipe(p) < 0)
       +                return -1;
       +        if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){
       +                close(p[0]);
       +                close(p[1]);
       +                return -1;
       +        }
       +        switch(pid = fork()){
       +        case -1:
       +                close(p[0]);
       +                close(p[1]);
       +                return -1;
       +        case 0:
       +                dup2(fd[0], 0);
       +                dup2(fd[1], 1);
       +                dup2(fd[2], 2);
       +                for(i=3; i<100; i++)
       +                        if(i != p[1])
       +                                close(i);
       +                execvp(cmd, argv);
       +                fprint(p[1], "%d", errno);
       +                close(p[1]);
       +                _exit(0);
       +        }
       +
       +        close(p[1]);
       +        n = read(p[0], exitstr, sizeof exitstr-1);
       +        close(p[0]);
       +        if(n > 0){        /* exec failed */
       +                exitstr[n] = 0;
       +                errno = atoi(exitstr);
       +                return -1;
       +        }
       +
       +        close(fd[0]);
       +        if(fd[1] != fd[0])
       +                close(fd[1]);
       +        if(fd[2] != fd[1] && fd[2] != fd[0])
       +                close(fd[2]);
       +        channbsendul(dowaitchan, 1);
       +        return pid;
       +}
       +
       +int
       +_threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
       +{
       +        int pid;
       +
       +        pid = threadspawn(fd, cmd, argv);
       +        if(cpid){
       +                if(pid < 0)
       +                        chansendul(cpid, ~0);
       +                else
       +                        chansendul(cpid, pid);
       +        }
       +        return pid;
       +}
       +
       +void
       +threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
       +{
       +        if(_threadexec(cpid, fd, cmd, argv) >= 0)
       +                threadexits("threadexec");
       +}
       +
       +void
       +threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
       +{
       +        char **argv, *s;
       +        int n, pid;
       +        va_list arg;
       +
       +        va_start(arg, cmd);
       +        for(n=0; va_arg(arg, char*) != nil; n++)
       +                ;
       +        n++;
       +        va_end(arg);
       +
       +        argv = malloc(n*sizeof(argv[0]));
       +        if(argv == nil){
       +                if(cpid)
       +                        chansendul(cpid, ~0);
       +                return;
       +        }
       +
       +        va_start(arg, cmd);
       +        for(n=0; (s=va_arg(arg, char*)) != nil; n++)
       +                argv[n] = s;
       +        argv[n] = 0;
       +        va_end(arg);
       +
       +        pid = _threadexec(cpid, fd, cmd, argv);
       +        free(argv);
       +
       +        if(pid >= 0)
       +                threadexits("threadexecl");
       +}
       +
 (DIR) diff --git a/src/libthread/execproc.ch b/src/libthread/execproc.ch
       t@@ -1,183 +0,0 @@
       -/*
       - * Set up a dedicated proc to handle calls to exec.
       - * The proc also waits for child messages.  
       - * This way, each proc scheduler need not worry
       - * about calling wait in its main loop.
       - * 
       - * To be included from other files (e.g., Linux-clone.c).
       - */
       -
       -typedef struct Xarg Xarg;
       -struct Xarg
       -{
       -        Channel *pidc;
       -        int fd[3];
       -        char *prog;
       -        char **args;
       -        int freeargs;
       -        Channel *ret;
       -        int errn;
       -        char errstr[ERRMAX];
       -};
       -
       -static Proc *_threadexecproc;
       -static Channel *_threadexecchan;
       -static Lock threadexeclock;
       -
       -/*
       - * Called to poll for any kids of this pthread.
       - * We have a separate proc responsible for exec,
       - * so this is a no-op.
       - */
       -void
       -_threadwaitkids(Proc *p)
       -{
       -}
       -
       -#define WAITSIG SIGCHLD
       -
       -/*
       - * Separate process to wait for child messages.
       - * Also runs signal handlers and runs all execs.
       - */
       -static void
       -nop(int sig)
       -{
       -        USED(sig);
       -}
       -
       -static void
       -_threadwaitproc(void *v)
       -{
       -        Channel *c;
       -        Waitmsg *w;
       -        sigset_t mask;
       -        int ret, nkids;
       -        Xarg *xa;
       -
       -        nkids = 0;
       -
       -        sigemptyset(&mask);
       -        siginterrupt(WAITSIG, 1);
       -        signal(WAITSIG, nop);
       -        sigaddset(&mask, WAITSIG);
       -        sigprocmask(SIG_BLOCK, &mask, nil);
       -        USED(v);
       -        for(;;){
       -                while((nkids > 0 ? nbrecv : recv)(_threadexecchan, &xa) == 1){
       -                        ret = _threadexec(xa->pidc, xa->fd, xa->prog, xa->args, xa->freeargs);
       -                        if(ret > 0)
       -                                nkids++;
       -                        else{
       -                                rerrstr(xa->errstr, sizeof xa->errstr);
       -                                xa->errn = errno;
       -                        }
       -                        sendul(xa->ret, ret);
       -                }
       -                if(nkids > 0){
       -                        sigprocmask(SIG_UNBLOCK, &mask, nil);
       -                        w = wait();
       -                        sigprocmask(SIG_BLOCK, &mask, nil);
       -                        if(w == nil && errno == ECHILD){
       -                                fprint(2, "wait returned ECHILD but nkids=%d; reset\n", nkids);
       -                                nkids = 0;
       -                        }
       -                        if(w){
       -                                nkids--;
       -                                if((c = _threadwaitchan) != nil)
       -                                        sendp(c, w);
       -                                else
       -                                        free(w);
       -                        }
       -                }
       -        }
       -}
       -
       -static void _kickexecproc(void);
       -
       -int
       -_callthreadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
       -{
       -        int ret;
       -        Xarg xa;
       -
       -        if(_threadexecchan == nil){
       -                lock(&threadexeclock);
       -                if(_threadexecchan == nil)
       -                        _threadfirstexec();
       -                unlock(&threadexeclock);
       -        }
       -
       -        xa.pidc = pidc;
       -        xa.fd[0] = fd[0];
       -        xa.fd[1] = fd[1];
       -        xa.fd[2] = fd[2];
       -        xa.prog = prog;
       -        xa.args = args;
       -        xa.freeargs = freeargs;
       -        xa.ret = chancreate(sizeof(ulong), 1);
       -        sendp(_threadexecchan, &xa);
       -        _kickexecproc();
       -        ret = recvul(xa.ret);
       -        if(ret < 0){
       -                werrstr("%s", xa.errstr);
       -                errno = xa.errn;
       -        }
       -        chanfree(xa.ret);
       -        return ret;
       -}
       -
       -/* 
       - * Called before the first exec.
       - */
       -void
       -_threadfirstexec(void)
       -{
       -        int id;
       -        Proc *p;
       -
       -        _threadexecchan = chancreate(sizeof(Xarg*), 1);
       -        id = proccreate(_threadwaitproc, nil, 32*1024);
       -
       -        /*
       -         * Sleazy: decrement threadnprocs so that 
       -         * the existence of the _threadwaitproc proc
       -         * doesn't keep us from exiting.
       -         */
       -        lock(&_threadpq.lock);
       -        --_threadnprocs;
       -        for(p=_threadpq.head; p; p=p->next)
       -                if(p->threads.head && p->threads.head->id == id)
       -                        break;
       -        if(p == nil)
       -                sysfatal("cannot find exec proc");
       -        unlock(&_threadpq.lock);
       -        _threadexecproc = p;
       -}
       -
       -/*
       - * Called after the thread t has been rescheduled.
       - * Kick the exec proc in case it is in the middle of a wait.
       - */
       -static void
       -_kickexecproc(void)
       -{
       -        kill(_threadexecproc->pid, WAITSIG);
       -}
       -
       -/*
       - * Called before exec.
       - */
       -void
       -_threadbeforeexec(void)
       -{
       -}
       -
       -/*
       - * Called after exec.
       - */
       -void
       -_threadafterexec(void)
       -{
       -}
       -
 (DIR) diff --git a/src/libthread/exit-getpid.ch b/src/libthread/exit-getpid.ch
       t@@ -1,25 +0,0 @@
       -/*
       - * Implement threadexitsall by sending a signal to every proc.
       - *
       - * To be included from another C file (e.g., Linux-clone.c).
       - */
       -
       -void
       -_threadexitallproc(char *exitstr)
       -{
       -        Proc *p;
       -        int mypid;
       -
       -        mypid = getpid();
       -        lock(&_threadpq.lock);
       -        for(p=_threadpq.head; p; p=p->next)
       -                if(p->pid > 1 && p->pid != mypid)
       -                        kill(p->pid, SIGUSR2);
       -        exits(exitstr);
       -}
       -
       -void
       -_threadexitproc(char *exitstr)
       -{
       -        _exits(exitstr);
       -}
 (DIR) diff --git a/src/libthread/exit.c b/src/libthread/exit.c
       t@@ -1,44 +0,0 @@
       -#include <u.h>
       -#include <signal.h>
       -#include "threadimpl.h"
       -
       -char *_threadexitsallstatus;
       -Channel *_threadwaitchan;
       -
       -void
       -threadexits(char *exitstr)
       -{
       -        Proc *p;
       -        Thread *t;
       -
       -        p = _threadgetproc();
       -        t = p->thread;
       -        if(t == p->idle)
       -                p->idle = nil;
       -        t->moribund = 1;
       -        _threaddebug(DBGSCHED, "threadexits %s", exitstr);
       -        if(exitstr==nil)
       -                exitstr="";
       -        utfecpy(p->exitstr, p->exitstr+ERRMAX, exitstr);
       -        _sched();
       -}
       -
       -void
       -threadexitsall(char *exitstr)
       -{
       -        _threaddebug(DBGSCHED, "threadexitsall %s", exitstr);
       -        if(exitstr == nil)
       -                exitstr = "";
       -        _threadexitsallstatus = exitstr;
       -        _threaddebug(DBGSCHED, "_threadexitsallstatus set to %p", _threadexitsallstatus);
       -        /* leave */
       -        _kthreadexitallproc(exitstr);
       -}
       -
       -Channel*
       -threadwaitchan(void)
       -{
       -        if(_threadwaitchan==nil)
       -                _threadwaitchan = chancreate(sizeof(Waitmsg*), 16);
       -        return _threadwaitchan;
       -}
 (DIR) diff --git a/src/libthread/fdwait.c b/src/libthread/fdwait.c
       t@@ -1,241 +0,0 @@
       -#define NOPLAN9DEFINES
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -#include "threadimpl.h"
       -#include <errno.h>
       -#include <unistd.h>
       -#include <fcntl.h>
       -
       -void
       -fdwait()
       -{
       -        fd_set rfd, wfd, efd;
       -
       -        FD_ZERO(&rfd);
       -        FD_ZERO(&wfd);
       -        FD_ZERO(&efd);
       -        if(mode=='w')
       -                FD_SET(&wfd, fd);
       -        else
       -                FD_SET(&rfd, fd);
       -        FD_SET(&efd, fd);
       -        select(fd+1, &rfd, &wfd, &efd, nil);
       -}
       -
       -void
       -threadfdwaitsetup(void)
       -{
       -}
       -
       -void
       -_threadfdwait(int fd, int rw, ulong pc)
       -{
       -        int i;
       -
       -        struct {
       -                Channel c;
       -                ulong x;
       -                Alt *qentry[2];
       -        } s;
       -
       -        threadfdwaitsetup();
       -        chaninit(&s.c, sizeof(ulong), 1);
       -        s.c.qentry = (volatile Alt**)s.qentry;
       -        s.c.nentry = 2;
       -        memset(s.qentry, 0, sizeof s.qentry);
       -        for(i=0; i<npoll; i++)
       -                if(pfd[i].fd == -1)
       -                        break;
       -        if(i==npoll){
       -                if(npoll >= nelem(polls)){
       -                        fprint(2, "Too many polled fds.\n");
       -                        abort();
       -                }
       -                npoll++;
       -        }
       -
       -        pfd[i].fd = fd;
       -        pfd[i].events = rw=='r' ? POLLIN : POLLOUT;
       -        polls[i].c = &s.c;
       -        if(0) fprint(2, "%s [%3d] fdwait %d %c list *0x%lux\n",
       -                argv0, threadid(), fd, rw, pc);
       -        if(pollpid)
       -                postnote(PNPROC, pollpid, "interrupt");
       -        recvul(&s.c);
       -}
       -
       -void
       -threadfdwait(int fd, int rw)
       -{
       -        _threadfdwait(fd, rw, getcallerpc(&fd));
       -}
       -
       -void
       -threadsleep(int ms)
       -{
       -        struct {
       -                Channel c;
       -                ulong x;
       -                Alt *qentry[2];
       -        } s;
       -
       -        threadfdwaitsetup();
       -        chaninit(&s.c, sizeof(ulong), 1);
       -        s.c.qentry = (volatile Alt**)s.qentry;
       -        s.c.nentry = 2;
       -        memset(s.qentry, 0, sizeof s.qentry);
       -        
       -        sleepchan[nsleep] = &s.c;
       -        sleeptime[nsleep++] = p9nsec()/1000000+ms;
       -        recvul(&s.c);
       -}
       -
       -void
       -threadfdnoblock(int fd)
       -{
       -        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0)|O_NONBLOCK);
       -}
       -
       -long
       -threadread(int fd, void *a, long n)
       -{
       -        int nn;
       -
       -        threadfdnoblock(fd);
       -again:
       -        /*
       -         * Always call wait (i.e. don't optimistically try the read)
       -         * so that the scheduler gets a chance to run other threads.
       -         */
       -        _threadfdwait(fd, 'r', getcallerpc(&fd));
       -        errno = 0;
       -        nn = read(fd, a, n);
       -        if(nn <= 0){
       -                if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
       -                        goto again;
       -        }
       -        return nn;
       -}
       -
       -int
       -threadrecvfd(int fd)
       -{
       -        int nn;
       -
       -        threadfdnoblock(fd);
       -again:
       -        /*
       -         * Always call wait (i.e. don't optimistically try the recvfd)
       -         * so that the scheduler gets a chance to run other threads.
       -         */
       -        _threadfdwait(fd, 'r', getcallerpc(&fd));
       -        nn = recvfd(fd);
       -        if(nn < 0){
       -                if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
       -                        goto again;
       -        }
       -        return nn;
       -}
       -
       -int
       -threadsendfd(int fd, int sfd)
       -{
       -        int nn;
       -
       -        threadfdnoblock(fd);
       -again:
       -        /*
       -         * Always call wait (i.e. don't optimistically try the sendfd)
       -         * so that the scheduler gets a chance to run other threads.
       -         */
       -        _threadfdwait(fd, 'w', getcallerpc(&fd));
       -        nn = sendfd(fd, sfd);
       -        if(nn < 0){
       -                if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
       -                        goto again;
       -        }
       -        return nn;
       -}
       -
       -long
       -threadreadn(int fd, void *a, long n)
       -{
       -        int tot, nn;
       -
       -        for(tot = 0; tot<n; tot+=nn){
       -                nn = threadread(fd, (char*)a+tot, n-tot);
       -                if(nn <= 0){
       -                        if(tot == 0)
       -                                return nn;
       -                        return tot;
       -                }
       -        }
       -        return tot;
       -}
       -
       -long
       -_threadwrite(int fd, const void *a, long n)
       -{
       -        int nn;
       -
       -        threadfdnoblock(fd);
       -again:
       -        /*
       -         * Always call wait (i.e. don't optimistically try the write)
       -         * so that the scheduler gets a chance to run other threads.
       -         */
       -        _threadfdwait(fd, 'w', getcallerpc(&fd));
       -        nn = write(fd, a, n);
       -        if(nn < 0){
       -                if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
       -                        goto again;
       -        }
       -        return nn;
       -}
       -
       -long
       -threadwrite(int fd, const void *a, long n)
       -{
       -        int tot, nn;
       -
       -        for(tot = 0; tot<n; tot+=nn){
       -                nn = _threadwrite(fd, (char*)a+tot, n-tot);
       -                if(nn <= 0){
       -                        if(tot == 0)
       -                                return nn;
       -                        return tot;
       -                }
       -        }
       -        return tot;
       -}
       -
       -int
       -threadannounce(char *addr, char *dir)
       -{
       -        return p9announce(addr, dir);
       -}
       -
       -int
       -threadlisten(char *dir, char *newdir)
       -{
       -        int fd, ret;
       -        extern int _p9netfd(char*);
       -
       -        fd = _p9netfd(dir);
       -        if(fd < 0){
       -                werrstr("bad 'directory' in listen: %s", dir);
       -                return -1;
       -        }
       -        threadfdnoblock(fd);
       -        while((ret = p9listen(dir, newdir)) < 0 && errno==EAGAIN)
       -                _threadfdwait(fd, 'r', getcallerpc(&dir));
       -        return ret;
       -}
       -
       -int
       -threadaccept(int cfd, char *dir)
       -{
       -        return p9accept(cfd, dir);
       -}
       -
 (DIR) diff --git a/src/libthread/getpid.c b/src/libthread/getpid.c
       t@@ -1,7 +0,0 @@
       -#include "threadimpl.h"
       -extern int getfforkid(void);
       -int
       -_threadgetpid(void)
       -{
       -        return getfforkid();
       -}
 (DIR) diff --git a/src/libthread/id.c b/src/libthread/id.c
       t@@ -1,136 +0,0 @@
       -#include "threadimpl.h"
       -
       -int
       -threadid(void)
       -{
       -        return _threadgetproc()->thread->id;
       -}
       -
       -int
       -threadpid(int id)
       -{
       -        int pid;
       -        Proc *p;
       -        Thread *t;
       -
       -        if (id < 0)
       -                return -1;
       -        if (id == 0)
       -                return _threadgetproc()->pid;
       -        lock(&_threadpq.lock);
       -        for (p = _threadpq.head; p->next; p = p->next){
       -                lock(&p->lock);
       -                for (t = p->threads.head; t; t = t->nextt)
       -                        if (t->id == id){
       -                                pid = p->pid;
       -                                unlock(&p->lock);
       -                                unlock(&_threadpq.lock);
       -                                return pid;
       -                        }
       -                unlock(&p->lock);
       -        }
       -        unlock(&_threadpq.lock);
       -        return -1;
       -}
       -
       -int
       -threadsetgrp(int ng)
       -{
       -        int og;
       -        Thread *t;
       -
       -        t = _threadgetproc()->thread;
       -        og = t->grp;
       -        t->grp = ng;
       -        return og;
       -}
       -
       -int
       -threadgetgrp(void)
       -{
       -        return _threadgetproc()->thread->grp;
       -}
       -
       -void
       -threadsetname(char *fmt, ...)
       -{
       -        Proc *p;
       -        Thread *t;
       -        va_list arg;
       -
       -        p = _threadgetproc();
       -        t = p->thread;
       -        if(t->name)
       -                free(t->name);
       -        va_start(arg, fmt);
       -        t->name = vsmprint(fmt, arg);
       -        va_end(arg);
       -
       -        _threaddebug(DBGSCHED, "set name %s", t->name);
       -/* Plan 9 only 
       -        if(p->nthreads == 1){
       -                snprint(buf, sizeof buf, "#p/%d/args", getpid());
       -                if((fd = open(buf, OWRITE)) >= 0){
       -                        snprint(buf, sizeof buf, "%s [%s]", argv0, name);
       -                        n = strlen(buf)+1;
       -                        s = strchr(buf, ' ');
       -                        if(s)
       -                                *s = '\0';
       -                        write(fd, buf, n);
       -                        close(fd);
       -                }
       -        }
       -*/
       -}
       -
       -char*
       -threadgetname(void)
       -{
       -        return _threadgetproc()->thread->name;
       -}
       -
       -void**
       -threaddata(void)
       -{
       -        return &_threadgetproc()->thread->udata[0];
       -}
       -
       -void**
       -procdata(void)
       -{
       -        return &_threadgetproc()->udata;
       -}
       -
       -static Lock privlock;
       -static int privmask = 1;
       -
       -int
       -tprivalloc(void)
       -{
       -        int i;
       -
       -        lock(&privlock);
       -        for(i=0; i<NPRIV; i++)
       -                if(!(privmask&(1<<i))){
       -                        privmask |= 1<<i;
       -                        unlock(&privlock);
       -                        return i;
       -                }
       -        unlock(&privlock);
       -        return -1;
       -}
       -
       -void
       -tprivfree(int i)
       -{
       -        if(i < 0 || i >= NPRIV)
       -                abort();
       -        lock(&privlock);
       -        privmask &= ~(1<<i);
       -}
       -
       -void**
       -tprivaddr(int i)
       -{
       -        return &_threadgetproc()->thread->udata[i];
       -}
 (DIR) diff --git a/src/libthread/iocall.c b/src/libthread/iocall.c
       t@@ -1,55 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -#include "ioproc.h"
       -
       -long
       -iocall(Ioproc *io, long (*op)(va_list*), ...)
       -{
       -        char e[ERRMAX];
       -        int ret, inted;
       -        Ioproc *msg;
       -
       -        if(send(io->c, &io) == -1){
       -                werrstr("interrupted");
       -                return -1;
       -        }
       -        assert(!io->inuse);
       -        io->inuse = 1;
       -        io->op = op;
       -        va_start(io->arg, op);
       -        msg = io;
       -        inted = 0;
       -        while(send(io->creply, &msg) == -1){
       -                msg = nil;
       -                inted = 1;
       -        }
       -        if(inted){
       -                werrstr("interrupted");
       -                return -1;
       -        }
       -
       -        /*
       -         * If we get interrupted, we have stick around so that
       -         * the IO proc has someone to talk to.  Send it an interrupt
       -         * and try again.
       -         */
       -        inted = 0;
       -        while(recv(io->creply, nil) == -1){
       -                inted = 1;
       -                iointerrupt(io);
       -        }
       -        USED(inted);
       -        va_end(io->arg);
       -        ret = io->ret;
       -        if(ret < 0)
       -                strecpy(e, e+sizeof e, io->err);
       -        io->inuse = 0;
       -
       -        /* release resources */
       -        while(send(io->creply, &io) == -1)
       -                ;
       -        if(ret < 0)
       -                errstr(e, sizeof e);
       -        return ret;
       -}
 (DIR) diff --git a/src/libthread/ioclose.c b/src/libthread/ioclose.c
       t@@ -1,16 +0,0 @@
       -#include "threadimpl.h"
       -
       -static long
       -_ioclose(va_list *arg)
       -{
       -        int fd;
       -
       -        fd = va_arg(*arg, int);
       -        return close(fd);
       -}
       -
       -int
       -ioclose(Ioproc *io, int fd)
       -{
       -        return iocall(io, _ioclose, fd);
       -}
 (DIR) diff --git a/src/libthread/iodial.c b/src/libthread/iodial.c
       t@@ -1,24 +0,0 @@
       -#include "threadimpl.h"
       -
       -static long
       -_iodial(va_list *arg)
       -{
       -        char *addr, *local, *dir;
       -        int *cdfp, fd;
       -
       -        addr = va_arg(*arg, char*);
       -        local = va_arg(*arg, char*);
       -        dir = va_arg(*arg, char*);
       -        cdfp = va_arg(*arg, int*);
       -
       -fprint(2, "before dial\n");
       -        fd = dial(addr, local, dir, cdfp);
       -fprint(2, "after dial\n");
       -        return fd;
       -}
       -
       -int
       -iodial(Ioproc *io, char *addr, char *local, char *dir, int *cdfp)
       -{
       -        return iocall(io, _iodial, addr, local, dir, cdfp);
       -}
 (DIR) diff --git a/src/libthread/ioopen.c b/src/libthread/ioopen.c
       t@@ -1,21 +0,0 @@
       -#include <u.h>
       -#include <unistd.h>
       -#include <fcntl.h>
       -#include "threadimpl.h"
       -
       -static long
       -_ioopen(va_list *arg)
       -{
       -        char *path;
       -        int mode;
       -
       -        path = va_arg(*arg, char*);
       -        mode = va_arg(*arg, int);
       -        return open(path, mode);
       -}
       -
       -int
       -ioopen(Ioproc *io, char *path, int mode)
       -{
       -        return iocall(io, _ioopen, path, mode);
       -}
 (DIR) diff --git a/src/libthread/ioproc.c b/src/libthread/ioproc.c
       t@@ -1,77 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -#include "ioproc.h"
       -
       -enum
       -{
       -        STACK = 8192,
       -};
       -
       -void
       -iointerrupt(Ioproc *io)
       -{
       -        if(!io->inuse)
       -                return;
       -        threadint(io->tid);
       -}
       -
       -static void
       -xioproc(void *a)
       -{
       -        Ioproc *io, *x;
       -        io = a;
       -        /*
       -         * first recvp acquires the ioproc.
       -         * second tells us that the data is ready.
       -         */
       -        for(;;){
       -                while(recv(io->c, &x) == -1)
       -                        ;
       -                if(x == 0)        /* our cue to leave */
       -                        break;
       -                assert(x == io);
       -
       -                /* caller is now committed -- even if interrupted he'll return */
       -                while(recv(io->creply, &x) == -1)
       -                        ;
       -                if(x == 0)        /* caller backed out */
       -                        continue;
       -                assert(x == io);
       -
       -                io->ret = io->op(&io->arg);
       -                if(io->ret < 0)
       -                        rerrstr(io->err, sizeof io->err);
       -                while(send(io->creply, &io) == -1)
       -                        ;
       -                while(recv(io->creply, &x) == -1)
       -                        ;
       -        }
       -}
       -
       -Ioproc*
       -ioproc(void)
       -{
       -        Ioproc *io;
       -
       -        io = mallocz(sizeof(*io), 1);
       -        if(io == nil)
       -                sysfatal("ioproc malloc: %r");
       -        io->c = chancreate(sizeof(void*), 0);
       -        io->creply = chancreate(sizeof(void*), 0);
       -        io->tid = proccreate(xioproc, io, STACK);
       -        return io;
       -}
       -
       -void
       -closeioproc(Ioproc *io)
       -{
       -        if(io == nil)
       -                return;
       -        iointerrupt(io);
       -        while(send(io->c, 0) == -1)
       -                ;
       -        chanfree(io->c);
       -        chanfree(io->creply);
       -        free(io);
       -}
 (DIR) diff --git a/src/libthread/ioproc.h b/src/libthread/ioproc.h
       t@@ -1,14 +0,0 @@
       -#define ioproc_arg(io, type)        (va_arg((io)->arg, type))
       -
       -struct Ioproc
       -{
       -        int tid;
       -        Channel *c, *creply;
       -        int inuse;
       -        long (*op)(va_list*);
       -        va_list arg;
       -        long ret;
       -        char err[ERRMAX];
       -        Ioproc *next;
       -};
       -
 (DIR) diff --git a/src/libthread/ioread.c b/src/libthread/ioread.c
       t@@ -1,20 +0,0 @@
       -#include "threadimpl.h"
       -
       -static long
       -_ioread(va_list *arg)
       -{
       -        int fd;
       -        void *a;
       -        long n;
       -
       -        fd = va_arg(*arg, int);
       -        a = va_arg(*arg, void*);
       -        n = va_arg(*arg, long);
       -        return read(fd, a, n);
       -}
       -
       -long
       -ioread(Ioproc *io, int fd, void *a, long n)
       -{
       -        return iocall(io, _ioread, fd, a, n);
       -}
 (DIR) diff --git a/src/libthread/ioreadn.c b/src/libthread/ioreadn.c
       t@@ -1,21 +0,0 @@
       -#include "threadimpl.h"
       -
       -static long
       -_ioreadn(va_list *arg)
       -{
       -        int fd;
       -        void *a;
       -        long n;
       -
       -        fd = va_arg(*arg, int);
       -        a = va_arg(*arg, void*);
       -        n = va_arg(*arg, long);
       -        n = readn(fd, a, n);
       -        return n;
       -}
       -
       -long
       -ioreadn(Ioproc *io, int fd, void *a, long n)
       -{
       -        return iocall(io, _ioreadn, fd, a, n);
       -}
 (DIR) diff --git a/src/libthread/iorw.c b/src/libthread/iorw.c
       t@@ -0,0 +1,178 @@
       +#include <u.h>
       +#include <unistd.h>
       +#include <fcntl.h>
       +#include <libc.h>
       +#include <fcall.h>
       +#include <thread.h>
       +#include "ioproc.h"
       +
       +static long
       +_ioclose(va_list *arg)
       +{
       +        int fd;
       +
       +        fd = va_arg(*arg, int);
       +        return close(fd);
       +}
       +int
       +ioclose(Ioproc *io, int fd)
       +{
       +        return iocall(io, _ioclose, fd);
       +}
       +
       +static long
       +_iodial(va_list *arg)
       +{
       +        char *addr, *local, *dir;
       +        int *cdfp, fd;
       +
       +        addr = va_arg(*arg, char*);
       +        local = va_arg(*arg, char*);
       +        dir = va_arg(*arg, char*);
       +        cdfp = va_arg(*arg, int*);
       +
       +        fd = dial(addr, local, dir, cdfp);
       +        return fd;
       +}
       +int
       +iodial(Ioproc *io, char *addr, char *local, char *dir, int *cdfp)
       +{
       +        return iocall(io, _iodial, addr, local, dir, cdfp);
       +}
       +
       +static long
       +_ioopen(va_list *arg)
       +{
       +        char *path;
       +        int mode;
       +
       +        path = va_arg(*arg, char*);
       +        mode = va_arg(*arg, int);
       +        return open(path, mode);
       +}
       +int
       +ioopen(Ioproc *io, char *path, int mode)
       +{
       +        return iocall(io, _ioopen, path, mode);
       +}
       +
       +static long
       +_ioread(va_list *arg)
       +{
       +        int fd;
       +        void *a;
       +        long n;
       +
       +        fd = va_arg(*arg, int);
       +        a = va_arg(*arg, void*);
       +        n = va_arg(*arg, long);
       +        return read(fd, a, n);
       +}
       +long
       +ioread(Ioproc *io, int fd, void *a, long n)
       +{
       +        return iocall(io, _ioread, fd, a, n);
       +}
       +
       +static long
       +_ioreadn(va_list *arg)
       +{
       +        int fd;
       +        void *a;
       +        long n;
       +
       +        fd = va_arg(*arg, int);
       +        a = va_arg(*arg, void*);
       +        n = va_arg(*arg, long);
       +        n = readn(fd, a, n);
       +        return n;
       +}
       +long
       +ioreadn(Ioproc *io, int fd, void *a, long n)
       +{
       +        return iocall(io, _ioreadn, fd, a, n);
       +}
       +
       +static long
       +_iosleep(va_list *arg)
       +{
       +        long n;
       +
       +        n = va_arg(*arg, long);
       +        return sleep(n);
       +}
       +int
       +iosleep(Ioproc *io, long n)
       +{
       +        return iocall(io, _iosleep, n);
       +}
       +
       +static long
       +_iowrite(va_list *arg)
       +{
       +        int fd;
       +        void *a;
       +        long n, nn;
       +
       +        fd = va_arg(*arg, int);
       +        a = va_arg(*arg, void*);
       +        n = va_arg(*arg, long);
       +        nn = write(fd, a, n);
       +        return nn;
       +}
       +long
       +iowrite(Ioproc *io, int fd, void *a, long n)
       +{
       +        return iocall(io, _iowrite, fd, a, n);
       +}
       +
       +static long
       +_iosendfd(va_list *arg)
       +{
       +        int n, fd, fd2;
       +
       +        fd = va_arg(*arg, int);
       +        fd2 = va_arg(*arg, int);
       +        n = sendfd(fd, fd2);
       +        return n;
       +}
       +int
       +iosendfd(Ioproc *io, int fd, int fd2)
       +{
       +        return iocall(io, _iosendfd, fd, fd2);
       +}
       +
       +static long
       +_iorecvfd(va_list *arg)
       +{
       +        int n, fd;
       +
       +        fd = va_arg(*arg, int);
       +        n = recvfd(fd);
       +        return n;
       +}
       +int
       +iorecvfd(Ioproc *io, int fd)
       +{
       +        return iocall(io, _iorecvfd, fd);
       +}
       +
       +static long
       +_ioread9pmsg(va_list *arg)
       +{
       +        int fd;
       +        void *a;
       +        int n;
       +        int r;
       +
       +        fd = va_arg(*arg, int);
       +        a = va_arg(*arg, void*);
       +        n = va_arg(*arg, int);
       +        r = read9pmsg(fd, a, n);
       +        return n;
       +}
       +int
       +ioread9pmsg(Ioproc *io, int fd, void *a, int n)
       +{
       +        return iocall(io, _ioread9pmsg, fd, a, n);
       +}
 (DIR) diff --git a/src/libthread/iosleep.c b/src/libthread/iosleep.c
       t@@ -1,16 +0,0 @@
       -#include "threadimpl.h"
       -
       -static long
       -_iosleep(va_list *arg)
       -{
       -        long n;
       -
       -        n = va_arg(*arg, long);
       -        return sleep(n);
       -}
       -
       -int
       -iosleep(Ioproc *io, long n)
       -{
       -        return iocall(io, _iosleep, n);
       -}
 (DIR) diff --git a/src/libthread/iowrite.c b/src/libthread/iowrite.c
       t@@ -1,22 +0,0 @@
       -#include "threadimpl.h"
       -
       -static long
       -_iowrite(va_list *arg)
       -{
       -        int fd;
       -        void *a;
       -        long n, nn;
       -
       -        fd = va_arg(*arg, int);
       -        a = va_arg(*arg, void*);
       -        n = va_arg(*arg, long);
       -        nn = write(fd, a, n);
       -fprint(2, "_iowrite %d %d %r\n", n, nn);
       -        return nn;
       -}
       -
       -long
       -iowrite(Ioproc *io, int fd, void *a, long n)
       -{
       -        return iocall(io, _iowrite, fd, a, n);
       -}
 (DIR) diff --git a/src/libthread/kill.c b/src/libthread/kill.c
       t@@ -1,90 +0,0 @@
       -#include <u.h>
       -#include <signal.h>
       -#include "threadimpl.h"
       -
       -static void tinterrupt(Proc*, Thread*);
       -
       -static void
       -threadxxxgrp(int grp, int dokill)
       -{
       -        Proc *p;
       -        Thread *t;
       -
       -        lock(&_threadpq.lock);
       -        for(p=_threadpq.head; p; p=p->next){
       -                lock(&p->lock);
       -                for(t=p->threads.head; t; t=t->nextt)
       -                        if(t->grp == grp){
       -                                if(dokill)
       -                                        t->moribund = 1;
       -                                tinterrupt(p, t);
       -                        }
       -                unlock(&p->lock);
       -        }
       -        unlock(&_threadpq.lock);
       -        _threadbreakrendez();
       -}
       -
       -static void
       -threadxxx(int id, int dokill)
       -{
       -        Proc *p;
       -        Thread *t;
       -
       -        lock(&_threadpq.lock);
       -        for(p=_threadpq.head; p; p=p->next){
       -                lock(&p->lock);
       -                for(t=p->threads.head; t; t=t->nextt)
       -                        if(t->id == id){
       -                                if(dokill)
       -                                        t->moribund = 1;
       -                                tinterrupt(p, t);
       -                                unlock(&p->lock);
       -                                unlock(&_threadpq.lock);
       -                                _threadbreakrendez();
       -                                return;
       -                        }
       -                unlock(&p->lock);
       -        }
       -        unlock(&_threadpq.lock);
       -        _threaddebug(DBGNOTE, "Can't find thread to kill");
       -        return;
       -}
       -
       -void
       -threadkillgrp(int grp)
       -{
       -        threadxxxgrp(grp, 1);
       -}
       -
       -void
       -threadkill(int id)
       -{
       -        threadxxx(id, 1);
       -}
       -
       -void
       -threadintgrp(int grp)
       -{
       -        threadxxxgrp(grp, 0);
       -}
       -
       -void
       -threadint(int id)
       -{
       -        threadxxx(id, 0);
       -}
       -
       -static void
       -tinterrupt(Proc *p, Thread *t)
       -{
       -        switch(t->state){
       -        case Running:
       -                kill(p->pid, SIGINT);
       -        //        postnote(PNPROC, p->pid, "threadint");
       -                break;
       -        case Rendezvous:
       -                _threadflagrendez(t);
       -                break;
       -        }
       -}
 (DIR) diff --git a/src/libthread/label.h b/src/libthread/label.h
       t@@ -1,68 +0,0 @@
       -/*
       - * setjmp and longjmp, but our own because some (stupid) c libraries
       - * assume longjmp is only used to move up the stack, and error out
       - * if you do otherwise.
       - */
       -
       -typedef struct Label Label;
       -#define LABELDPC 0
       -
       -#if defined(__linux__)
       -#include <ucontext.h>
       -struct Label
       -{
       -        ucontext_t uc;
       -};
       -#elif defined (__i386__) && (defined(__FreeBSD__) || defined(__linux__) || defined(__OpenBSD__))
       -struct Label
       -{
       -        ulong pc;
       -        ulong bx;
       -        ulong sp;
       -        ulong bp;
       -        ulong si;
       -        ulong di;
       -};
       -#elif defined(__APPLE__)
       -struct Label
       -{
       -        ulong        pc;                /* lr */
       -        ulong        cr;                /* mfcr */
       -        ulong        ctr;                /* mfcr */
       -        ulong        xer;                /* mfcr */
       -        ulong        sp;                /* callee saved: r1 */
       -        ulong        toc;                /* callee saved: r2 */
       -        ulong        gpr[19];        /* callee saved: r13-r31 */
       -// XXX: currently do not save vector registers or floating-point state
       -//        ulong        pad;
       -//        uvlong        fpr[18];        /* callee saved: f14-f31 */
       -//        ulong        vr[4*12];        /* callee saved: v20-v31, 256-bits each */
       -};
       -#elif defined(__sun__)
       -struct Label
       -{
       -        ulong        input[8];        /* %i registers */
       -        ulong        local[8];        /* %l registers */
       -        ulong        sp;                /* %o6 */
       -        ulong        link;                /* %o7 */
       -};
       -#elif defined(__powerpc__)
       -struct Label
       -{
       -        ulong        pc;                /* lr */
       -        ulong        cr;                /* mfcr */
       -        ulong        ctr;                /* mfcr */
       -        ulong        xer;                /* mfcr */
       -        ulong        sp;                /* callee saved: r1 */
       -        ulong        toc;                /* callee saved: r2 */
       -        ulong        gpr[19];        /* callee saved: r13-r31 */
       -// XXX: currently do not save vector registers or floating-point state
       -//        ulong        pad;
       -//        uvlong        fpr[18];        /* callee saved: f14-f31 */
       -//        ulong        vr[4*12];        /* callee saved: v20-v31, 256-bits each */
       -};
       -#else
       -#error "Unknown or unsupported architecture"
       -#endif
       -
       -
 (DIR) diff --git a/src/libthread/lib.c b/src/libthread/lib.c
       t@@ -1,35 +0,0 @@
       -#include "threadimpl.h"
       -
       -static long totalmalloc;
       -
       -void*
       -_threadmalloc(long size, int z)
       -{
       -        void *m;
       -
       -        m = malloc(size);
       -        if (m == nil)
       -                sysfatal("Malloc of size %ld failed: %r\n", size);
       -        setmalloctag(m, getcallerpc(&size));
       -        totalmalloc += size;
       -        if (size > 1000000) {
       -                fprint(2, "Malloc of size %ld, total %ld\n", size, totalmalloc);
       -                abort();
       -        }
       -        if (z)
       -                _threadmemset(m, 0, size);
       -        return m;
       -}
       -
       -void
       -_threadsysfatal(char *fmt, va_list arg)
       -{
       -        char buf[1024];        /* size doesn't matter; we're about to exit */
       -
       -        vseprint(buf, buf+sizeof(buf), fmt, arg);
       -        if(argv0)
       -                fprint(2, "%s: %s\n", argv0, buf);
       -        else
       -                fprint(2, "%s\n", buf);
       -        threadexitsall(buf);
       -}
 (DIR) diff --git a/src/libthread/main.c b/src/libthread/main.c
       t@@ -1,98 +0,0 @@
       -/*
       - * Thread library.  
       - */
       -
       -#include "threadimpl.h"
       -
       -typedef struct Mainarg Mainarg;
       -struct Mainarg
       -{
       -        int argc;
       -        char **argv;
       -};
       -
       -int mainstacksize;
       -
       -extern void (*_sysfatal)(char*, va_list);
       -extern Jmp *(*_notejmpbuf)(void);
       -
       -static void
       -mainlauncher(void *arg)
       -{
       -        Mainarg *a;
       -
       -        a = arg;
       -        _kmaininit();
       -        threadmain(a->argc, a->argv);
       -        threadexits("threadmain");
       -}
       -
       -int
       -main(int argc, char **argv)
       -{
       -        Mainarg a;
       -        Proc *p;
       -
       -        /*
       -         * In pthreads, threadmain is actually run in a subprocess,
       -         * so that the main process can exit (if threaddaemonize is called).
       -         * The main process relays notes to the subprocess.
       -         * _Threadbackgroundsetup will return only in the subprocess.
       -         */
       -        _threadbackgroundinit();
       -
       -        /*
       -         * Instruct QLock et al. to use our scheduling functions
       -         * so that they can operate at the thread level.
       -         */
       -        _qlockinit(_threadsleep, _threadwakeup);
       -
       -        /*
       -         * Install our own _threadsysfatal which takes down
       -         * the whole confederation of procs.
       -         */
       -        _sysfatal = _threadsysfatal;
       -
       -        /*
       -         * Install our own jump handler.
       -         */
       -        _notejmpbuf = _threadgetjmp;
       -
       -        /*
       -         * Install our own signal handler.
       -         */
       -        notify(_threadnote);
       -
       -        /*
       -         * Construct the initial proc running mainlauncher(&a).
       -         */
       -        if(mainstacksize == 0)
       -                mainstacksize = 32*1024;
       -        a.argc = argc;
       -        a.argv = argv;
       -        p = _newproc();
       -        _newthread(p, mainlauncher, &a, mainstacksize, "threadmain", 0);
       -        _threadscheduler(p);
       -        abort();        /* not reached */
       -        return 0;
       -}
       -
       -/*
       - * No-op function here so that sched.o drags in main.o.
       - */
       -void
       -_threadlinkmain(void)
       -{
       -}
       -
       -Jmp*
       -_threadgetjmp(void)
       -{
       -        static Jmp j;
       -        Proc *p;
       -
       -        p = _threadgetproc();
       -        if(p == nil)
       -                return &j;
       -        return &p->sigjmp;
       -}
 (DIR) diff --git a/src/libthread/memset.c b/src/libthread/memset.c
       t@@ -1,8 +0,0 @@
       -#include "threadimpl.h"
       -#include <string.h>
       -
       -void
       -_threadmemset(void *v, int c, int n)
       -{
       -        memset(v, c, n);
       -}
 (DIR) diff --git a/src/libthread/memsetd.c b/src/libthread/memsetd.c
       t@@ -1,8 +0,0 @@
       -#include "threadimpl.h"
       -#include <string.h>
       -
       -void
       -_threaddebugmemset(void *v, int c, int n)
       -{
       -        memset(v, c, n);
       -}
 (DIR) diff --git a/src/libthread/mkfile b/src/libthread/mkfile
       t@@ -1,73 +0,0 @@
       -<$PLAN9/src/mkhdr
       -
       -LIB=libthread.a
       -SYSOFILES=`sh ./sysofiles.sh`
       -OFILES=\
       -        $SYSOFILES\
       -        channel.$O\
       -        chanprint.$O\
       -        create.$O\
       -        debug.$O\
       -        exec-unix.$O\
       -        exit.$O\
       -        fdwait.$O\
       -        getpid.$O\
       -        id.$O\
       -        iocall.$O\
       -        ioclose.$O\
       -        iodial.$O\
       -        ioopen.$O\
       -        ioproc.$O\
       -        ioread.$O\
       -        ioreadn.$O\
       -        iosleep.$O\
       -        iowrite.$O\
       -        lib.$O\
       -        main.$O\
       -        memset.$O\
       -        memsetd.$O\
       -        read9pmsg.$O\
       -        ref.$O\
       -        sched.$O\
       -        setproc.$O\
       -        sleep.$O\
       -
       -HFILES=\
       -        $PLAN9/include/thread.h\
       -        label.h\
       -        threadimpl.h\
       -
       -<$PLAN9/src/mksyslib
       -
       -tfork: tfork.$O $PLAN9/lib/$LIB
       -        $LD -o tfork tfork.$O $LDFLAGS -lthread -l9
       -
       -tprimes: tprimes.$O $PLAN9/lib/$LIB
       -        $LD -o tprimes tprimes.$O $LDFLAGS -lthread -l9
       -
       -texec: texec.$O $PLAN9/lib/$LIB
       -        $LD -o texec texec.$O $LDFLAGS -lthread -l9
       -
       -tspawn: tspawn.$O $PLAN9/lib/$LIB
       -        $LD -o tspawn tspawn.$O $LDFLAGS -lthread -l9
       -
       -trend: trend.$O $PLAN9/lib/$LIB
       -        $LD -o trend trend.$O $LDFLAGS -lthread -l9
       -
       -tsignal: tsignal.$O $PLAN9/lib/$LIB
       -        $LD -o tsignal tsignal.$O $LDFLAGS -lthread -l9
       -
       -CLEANFILES=$CLEANFILES tprimes texec
       -
       -asm-Linux-ppc.$O: asm-Linux-386.s
       -asm-Linux-386.$O: asm-FreeBSD-386.s
       -asm-NetBSD-386.$O: asm-FreeBSD-386.s
       -asm-OpenBSD-386.$O: asm-FreeBSD-386.s
       -
       -# sorry
       -VG=`test -d /home/rsc/pub/valgrind-debian && echo -DUSEVALGRIND`
       -# VG=
       -
       -CFLAGS=$CFLAGS $VG
       -
       -Linux-clone.$O: execproc.ch exit-getpid.ch proctab.ch procstack.ch
 (DIR) diff --git a/src/libthread/note.c b/src/libthread/note.c
       t@@ -1,145 +0,0 @@
       -#include "threadimpl.h"
       -
       -
       -int        _threadnopasser;
       -
       -#define        NFN                33
       -#define        ERRLEN        48
       -typedef struct Note Note;
       -struct Note
       -{
       -        Lock                inuse;
       -        Proc                *proc;                /* recipient */
       -        char                s[ERRMAX];        /* arg2 */
       -};
       -
       -static Note        notes[128];
       -static Note        *enotes = notes+nelem(notes);
       -static int                (*onnote[NFN])(void*, char*);
       -static int                onnotepid[NFN];
       -static Lock        onnotelock;
       -
       -int
       -threadnotify(int (*f)(void*, char*), int in)
       -{
       -        int i, topid;
       -        int (*from)(void*, char*), (*to)(void*, char*);
       -
       -        if(in){
       -                from = 0;
       -                to = f;
       -                topid = _threadgetproc()->pid;
       -        }else{
       -                from = f;
       -                to = 0;
       -                topid = 0;
       -        }
       -        lock(&onnotelock);
       -        for(i=0; i<NFN; i++)
       -                if(onnote[i]==from){
       -                        onnote[i] = to;
       -                        onnotepid[i] = topid;
       -                        break;
       -                }
       -        unlock(&onnotelock);
       -        return i<NFN;
       -}
       -
       -static void
       -delayednotes(Proc *p, void *v)
       -{
       -        int i;
       -        Note *n;
       -        int (*fn)(void*, char*);
       -
       -        if(!p->pending)
       -                return;
       -
       -        p->pending = 0;
       -        for(n=notes; n<enotes; n++){
       -                if(n->proc == p){
       -                        for(i=0; i<NFN; i++){
       -                                if(onnotepid[i]!=p->pid || (fn = onnote[i])==0)
       -                                        continue;
       -                                if((*fn)(v, n->s))
       -                                        break;
       -                        }
       -                        if(i==NFN){
       -                                _threaddebug(DBGNOTE, "Unhandled note %s, proc %p\n", n->s, p);
       -                                if(strcmp(n->s, "sys: child") == 0)
       -                                        noted(NCONT);
       -                                fprint(2, "unhandled note %s, pid %d\n", n->s, p->pid);
       -                                if(v != nil)
       -                                        noted(NDFLT);
       -                                else if(strncmp(n->s, "sys:", 4)==0)
       -                                        abort();
       -                                threadexitsall(n->s);
       -                        }
       -                        n->proc = nil;
       -                        unlock(&n->inuse);
       -                }
       -        }
       -}
       -
       -void
       -_threadnote(void *v, char *s)
       -{
       -        Proc *p;
       -        Note *n;
       -
       -        _threaddebug(DBGNOTE, "Got note %s", s);
       -        if(strncmp(s, "sys:", 4) == 0)
       -                noted(NDFLT);
       -
       -//        if(_threadexitsallstatus){
       -//                _threaddebug(DBGNOTE, "Threadexitsallstatus = '%s'\n", _threadexitsallstatus);
       -//                _exits(_threadexitsallstatus);
       -//        }
       -
       -        if(strcmp(s, "threadint")==0 || strcmp(s, "interrupt")==0)
       -                noted(NCONT);
       -
       -        p = _threadgetproc();
       -        if(p == nil)
       -                noted(NDFLT);
       -
       -        for(n=notes; n<enotes; n++)
       -                if(canlock(&n->inuse))
       -                        break;
       -        if(n==enotes)
       -                sysfatal("libthread: too many delayed notes");
       -        utfecpy(n->s, n->s+ERRMAX, s);
       -        n->proc = p;
       -        p->pending = 1;
       -        if(!p->splhi)
       -                delayednotes(p, v);
       -        noted(NCONT);
       -}
       -
       -int
       -_procsplhi(void)
       -{
       -        int s;
       -        Proc *p;
       -
       -        p = _threadgetproc();
       -        s = p->splhi;
       -        p->splhi = 1;
       -        return s;
       -}
       -
       -void
       -_procsplx(int s)
       -{
       -        Proc *p;
       -
       -        p = _threadgetproc();
       -        p->splhi = s;
       -        if(s)
       -                return;
       -/*
       -        if(p->pending)
       -                delayednotes(p, nil);
       -*/
       -}
       -
 (DIR) diff --git a/src/libthread/pid.c b/src/libthread/pid.c
       t@@ -1,25 +0,0 @@
       -        mypid = getpid();
       -
       -        /*
       -         * signal others.
       -         * copying all the pids first avoids other thread's
       -         * teardown procedures getting in the way.
       -         */
       -        lock(&_threadpq.lock);
       -        npid = 0;
       -        for(p=_threadpq.head; p; p=p->next)
       -                npid++;
       -        pid = _threadmalloc(npid*sizeof(pid[0]), 0);
       -        npid = 0;
       -        for(p = _threadpq.head; p; p=p->next)
       -                pid[npid++] = p->pid;
       -        unlock(&_threadpq.lock);
       -        for(i=0; i<npid; i++){
       -                _threaddebug(DBGSCHED, "threadexitsall kill %d", pid[i]);
       -                if(pid[i]==0 || pid[i]==-1)
       -                        fprint(2, "bad pid in threadexitsall: %d\n", pid[i]);
       -                else if(pid[i] != mypid){
       -                        kill(pid[i], SIGTERM);
       -                }
       -        }
       -
 (DIR) diff --git a/src/libthread/power.c b/src/libthread/power.c
       t@@ -1,40 +0,0 @@
       -#include "threadimpl.h"
       -
       -static void
       -launcherpower(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
       -        void (*f)(void *arg), void *arg)
       -{
       -        (*f)(arg);
       -        threadexits(nil);
       -}
       -
       -void
       -_threadinitstack(Thread *t, void (*f)(void*), void *arg)
       -{
       -        ulong *tos, *stk;
       -
       -        tos = (ulong*)&t->stk[t->stksize&~7];
       -        stk = tos;
       -        --stk;
       -        --stk;
       -        --stk;
       -        --stk;
       -        *--stk = (ulong)arg;
       -        *--stk = (ulong)f;
       -        t->sched.pc = (ulong)launcherpower+LABELDPC;
       -        t->sched.sp = ((ulong)stk)-8;
       -        *((ulong *)t->sched.sp) = 0;
       -}
       -
       -void
       -_threadinswitch(int enter)
       -{
       -        USED(enter);
       -}
       -
       -void
       -_threadstacklimit(void *addr, void *addr2)
       -{
       -        USED(addr);
       -}
       -
 (DIR) diff --git a/src/libthread/procstack.ch b/src/libthread/procstack.ch
       t@@ -1,75 +0,0 @@
       -static int fforkstacksize = 16384;
       -
       -typedef struct Stack Stack;
       -struct Stack
       -{
       -        Stack *next;
       -        Stack *fnext;
       -        int pid;
       -};
       -
       -static Lock stacklock;
       -static Stack *freestacks;
       -static Stack *allstacks;
       -static int stackmallocs;
       -static void gc(void);
       -
       -static void*
       -mallocstack(void)
       -{
       -        Stack *p;
       -
       -        lock(&stacklock);
       -top:
       -        p = freestacks;
       -        if(p)
       -                freestacks = p->fnext;
       -        else{
       -                if(stackmallocs++%1 == 0)
       -                        gc();
       -                if(freestacks)
       -                        goto top;
       -                p = malloc(fforkstacksize);
       -                p->next = allstacks;
       -                allstacks = p;
       -        }
       -        if(p)
       -                p->pid = 1;
       -        unlock(&stacklock);
       -        return p;
       -}
       -
       -static void
       -gc(void)
       -{
       -        Stack *p;
       -
       -        for(p=allstacks; p; p=p->next){
       -                if(p->pid > 1 && procexited(p->pid)){
       -                        if(0) fprint(2, "reclaim stack from %d\n", p->pid);
       -                        p->pid = 0;
       -                }
       -                if(p->pid == 0){
       -                        p->fnext = freestacks;
       -                        freestacks = p;
       -                }
       -        }
       -}
       -
       -static void
       -freestack(void *v)
       -{
       -        Stack *p;
       -
       -        p = v;
       -        if(p == nil)
       -                return;
       -        lock(&stacklock);
       -        p->fnext = freestacks;
       -        p->pid = 0;
       -        freestacks = p;
       -        unlock(&stacklock);
       -        return;
       -}
       -
       -
 (DIR) diff --git a/src/libthread/proctab.c b/src/libthread/proctab.c
       t@@ -1,75 +0,0 @@
       -#include "threadimpl.h"
       -
       -/* this will need work */
       -enum
       -{
       -        PTABHASH = 257,
       -};
       -
       -static int multi;
       -static Proc *theproc;
       -
       -void
       -_threadmultiproc(void)
       -{
       -        if(multi == 0){
       -                multi = 1;
       -                _threadsetproc(theproc);
       -        }
       -}
       -
       -static Lock ptablock;
       -Proc *ptab[PTABHASH];
       -
       -void
       -_threadsetproc(Proc *p)
       -{
       -        int h;
       -
       -        if(!multi){
       -                theproc = p;
       -                return;
       -        }
       -        lock(&ptablock);
       -        h = ((unsigned)p->pid)%PTABHASH;
       -        p->link = ptab[h];
       -        unlock(&ptablock);
       -        ptab[h] = p;
       -}
       -
       -static Proc*
       -__threadgetproc(int rm)
       -{
       -        Proc **l, *p;
       -        int h, pid;
       -
       -        if(!multi)
       -                return theproc;
       -
       -        pid = getpid();
       -
       -        lock(&ptablock);
       -        h = ((unsigned)pid)%PTABHASH;
       -        for(l=&ptab[h]; p=*l; l=&p->link){
       -                if(p->pid == pid){
       -                        if(rm)
       -                                *l = p->link;
       -                        unlock(&ptablock);
       -                        return p;
       -                }
       -        }
       -        unlock(&ptablock);
       -        return nil;
       -}
       -
       -Proc*
       -_threadgetproc(void)
       -{
       -        return __threadgetproc(0);
       -}
       -
       -Proc*
       -_threaddelproc(void)
       -{
       -        return __threadgetproc(1);
       -}
 (DIR) diff --git a/src/libthread/proctab.ch b/src/libthread/proctab.ch
       t@@ -1,97 +0,0 @@
       -/*
       - * Proc structure hash table indexed by proctabid() (usually getpid()).
       - * No lock is necessary for lookups (important when called from signal
       - * handlers).
       - * 
       - * To be included from other files (e.g., Linux-clone.c).
       - */
       -
       -#define T ((void*)-1)
       -
       -enum
       -{
       -        PTABHASH = 1031,
       -};
       -
       -static Lock ptablock;
       -static Proc *proctab[PTABHASH];
       -static Proc *theproc;
       -static int multi;
       -
       -void
       -_threadmultiproc(void)
       -{
       -        if(multi == 0){
       -                multi = 1;
       -                _threadsetproc(theproc);
       -        }
       -}
       -
       -void
       -_threadsetproc(Proc *p)
       -{
       -        int i, h;
       -        Proc **t;
       -
       -        if(!multi){
       -                theproc = p;
       -                return;
       -        }
       -        lock(&ptablock);
       -        p->procid = procid();
       -        h = p->procid%PTABHASH;
       -        for(i=0; i<PTABHASH; i++){
       -                t = &proctab[(h+i)%PTABHASH];
       -                if(*t==nil || *t==T){
       -                        *t = p;
       -                        break;
       -                }
       -        }
       -        unlock(&ptablock);
       -        if(i == PTABHASH)
       -                sysfatal("too many procs - proctab is full");
       -}
       -
       -static Proc**
       -_threadfindproc(int id)
       -{
       -        int i, h;
       -        Proc **t;
       -
       -        if(!multi)
       -                return &theproc;
       -
       -        h = id%PTABHASH;
       -        for(i=0; i<PTABHASH; i++){
       -                t = &proctab[(h+i)%PTABHASH];
       -                if(*t != nil && *t != T && (*t)->procid == id){
       -                        unlock(&ptablock);
       -                        return t;
       -                }
       -        }
       -        return nil;
       -}
       -
       -Proc*
       -_threadgetproc(void)
       -{
       -        Proc **t;
       -
       -        t = _threadfindproc(procid());
       -        if(t == nil)
       -                return nil;
       -        return *t;
       -}
       -
       -Proc*
       -_threaddelproc(void)
       -{
       -        Proc **t, *p;
       -
       -        t = _threadfindproc(procid());
       -        if(t == nil)
       -                return nil;
       -        p = *t;
       -        *t = T;
       -        return p;
       -}
 (DIR) diff --git a/src/libthread/pthread.c b/src/libthread/pthread.c
       t@@ -1,271 +0,0 @@
       -#include <u.h>
       -#include <errno.h>
       -#include "threadimpl.h"
       -
       -/*
       - * Basic kernel thread management.
       - */
       -static pthread_key_t key;
       -
       -void
       -_kthreadinit(void)
       -{
       -        pthread_key_create(&key, 0);
       -}
       -
       -void
       -_kthreadsetproc(Proc *p)
       -{
       -        sigset_t all;
       -
       -        p->pthreadid = pthread_self();
       -        sigfillset(&all);
       -        pthread_sigmask(SIG_SETMASK, &all, nil);
       -        pthread_setspecific(key, p);
       -}
       -
       -Proc*
       -_kthreadgetproc(void)
       -{
       -        return pthread_getspecific(key);
       -}
       -
       -void
       -_kthreadstartproc(Proc *p)
       -{
       -        Proc *np;
       -        pthread_t tid;
       -        sigset_t all;
       -
       -        np = p->newproc;
       -        sigfillset(&all);
       -        pthread_sigmask(SIG_SETMASK, &all, nil);
       -        if(pthread_create(&tid, nil, (void*(*)(void*))_threadscheduler, 
       -                        np) < 0)
       -                sysfatal("pthread_create: %r");
       -        np->pthreadid = tid;
       -}
       -
       -void
       -_kthreadexitproc(char *exitstr)
       -{
       -        _threaddebug(DBGSCHED, "_pthreadexit");
       -        pthread_exit(nil);
       -}
       -
       -void
       -_kthreadexitallproc(char *exitstr)
       -{
       -        _threaddebug(DBGSCHED, "_threadexitallproc");
       -        exits(exitstr);
       -}
       -
       -/*
       - * Exec.  Pthreads does the hard work of making it possible
       - * for any thread to do the waiting, so this is pretty easy.
       - * We create a separate proc whose job is to wait for children
       - * and deliver wait messages.
       - */
       -static Channel *_threadexecwaitchan;
       -
       -static void
       -_threadwaitproc(void *v)
       -{
       -        Channel *c;
       -        Waitmsg *w;
       -
       -        _threadinternalproc();
       -
       -        USED(v);
       -        
       -        for(;;){
       -                w = wait();
       -                if(w == nil){
       -                        if(errno == ECHILD)        /* wait for more */
       -                                recvul(_threadexecwaitchan);
       -                        continue;
       -                }
       -                if((c = _threadwaitchan) != nil)
       -                        sendp(c, w);
       -                else
       -                        free(w);
       -        }
       -        fprint(2, "_threadwaitproc exits\n");        /* not reached */
       -}
       -
       -
       -/* 
       - * Call _threadexec in the right conditions.
       - */
       -int
       -_kthreadexec(Channel *c, int fd[3], char *prog, char *args[], int freeargs)
       -{
       -        static Lock lk;
       -        int rv;
       -
       -        if(!_threadexecwaitchan){
       -                lock(&lk);
       -                if(!_threadexecwaitchan){
       -                        _threadexecwaitchan = chancreate(sizeof(ulong), 1);
       -                        proccreate(_threadwaitproc, nil, 32*1024);
       -                }
       -                unlock(&lk);
       -        }
       -        rv = _threadexec(c, fd, prog, args, freeargs);
       -        nbsendul(_threadexecwaitchan, 1);
       -        return rv;
       -}
       -
       -/*
       - * Some threaded applications want to run in the background.
       - * Calling fork() and exiting in the parent will result in a child
       - * with a single pthread (if we are using pthreads), and will screw
       - * up our internal process info if we are using clone/rfork.
       - * Instead, apps should call threadbackground(), which takes
       - * care of this.
       - * 
       - * _threadbackgroundinit is called from main.
       - */
       -
       -static int mainpid, passerpid;
       -
       -static void
       -passer(void *x, char *msg)
       -{
       -        Waitmsg *w;
       -
       -        USED(x);
       -        if(strcmp(msg, "sys: usr2") == 0)
       -                _exit(0);        /* daemonize */
       -        else if(strcmp(msg, "sys: child") == 0){
       -                /* child exited => so should we */
       -                w = wait();
       -                if(w == nil)
       -                        _exit(1);
       -                _exit(atoi(w->msg));
       -        }else
       -                postnote(PNGROUP, mainpid, msg);
       -}
       -
       -void
       -_threadbackgroundinit(void)
       -{
       -        int pid;
       -        sigset_t mask;
       -
       -        sigfillset(&mask);
       -        pthread_sigmask(SIG_BLOCK, &mask, 0);
       -
       -return;
       -
       -        passerpid = getpid();
       -        switch(pid = fork()){
       -        case -1:
       -                sysfatal("fork: %r");
       -
       -        case 0:
       -                rfork(RFNOTEG);
       -                return;
       -
       -        default:
       -                break;
       -        }
       -
       -        mainpid = pid;
       -        notify(passer);
       -        notifyon("sys: child");
       -        notifyon("sys: usr2");        /* should already be on */
       -        for(;;)
       -                pause();
       -        _exit(0);
       -}
       -
       -void
       -threadbackground(void)
       -{
       -        if(passerpid <= 1)
       -                return;
       -        postnote(PNPROC, passerpid, "sys: usr2");
       -}
       -
       -/*
       - * Notes.
       - */
       -Channel *_threadnotechan;
       -static ulong sigs;
       -static Lock _threadnotelk;
       -static void _threadnoteproc(void*);
       -extern int _p9strsig(char*);
       -extern char *_p9sigstr(int);
       -
       -Channel*
       -threadnotechan(void)
       -{
       -        if(_threadnotechan == nil){
       -                lock(&_threadnotelk);
       -                if(_threadnotechan == nil){
       -                        _threadnotechan = chancreate(sizeof(char*), 1);
       -                        proccreate(_threadnoteproc, nil, 32*1024);
       -                }
       -                unlock(&_threadnotelk);
       -        }
       -        return _threadnotechan;
       -}
       -
       -void
       -_threadnote(void *x, char *msg)
       -{
       -        USED(x);
       -
       -        if(_threadexitsallstatus)
       -                _kthreadexitproc(_threadexitsallstatus);
       -
       -        if(strcmp(msg, "sys: usr2") == 0)
       -                noted(NCONT);
       -
       -        if(_threadnotechan == nil)
       -                noted(NDFLT);
       -
       -        sigs |= 1<<_p9strsig(msg);
       -        noted(NCONT);
       -}
       -
       -void
       -_threadnoteproc(void *x)
       -{
       -        int i;
       -        sigset_t none;
       -        Channel *c;
       -
       -        _threadinternalproc();
       -        sigemptyset(&none);
       -        pthread_sigmask(SIG_SETMASK, &none, 0);
       -
       -        c = _threadnotechan;
       -        for(;;){
       -                if(sigs == 0)
       -                        pause();
       -                for(i=0; i<32; i++){
       -                        if((sigs&(1<<i)) == 0)
       -                                continue;
       -                        sigs &= ~(1<<i);
       -                        if(i == 0)
       -                                continue;
       -                        sendp(c, _p9sigstr(i));
       -                }
       -        }
       -}
       -
       -void
       -_threadschednote(void)
       -{
       -}
       -
       -void
       -_kmaininit(void)
       -{
       -        sigset_t all;
       -
       -        sigfillset(&all);
       -        pthread_sigmask(SIG_SETMASK, &all, 0);
       -}
 (DIR) diff --git a/src/libthread/qlock.c b/src/libthread/qlock.c
       t@@ -0,0 +1,3 @@
       +#include "u.h"
       +#include "libc.h"
       +
 (DIR) diff --git a/src/libthread/read9pmsg.c b/src/libthread/read9pmsg.c
       t@@ -1,32 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <fcall.h>
       -#include <thread.h>
       -
       -int
       -threadread9pmsg(int fd, void *abuf, uint n)
       -{
       -        int m, len;
       -        uchar *buf;
       -
       -        buf = abuf;
       -
       -        /* read count */
       -        m = threadreadn(fd, buf, BIT32SZ);
       -        if(m != BIT32SZ){
       -                if(m < 0)
       -                        return -1;
       -                return 0;
       -        }
       -
       -        len = GBIT32(buf);
       -        if(len <= BIT32SZ || len > n){
       -                werrstr("bad length in 9P2000 message header");
       -                return -1;
       -        }
       -        len -= BIT32SZ;
       -        m = threadreadn(fd, buf+BIT32SZ, len);
       -        if(m < len)
       -                return 0;
       -        return BIT32SZ+m;
       -}
 (DIR) diff --git a/src/libthread/ref.c b/src/libthread/ref.c
       t@@ -1,26 +0,0 @@
       -/*
       - * Atomic reference counts - used by applications.
       - *
       - * We use locks to avoid the assembly of the Plan 9 versions.
       - */
       -
       -#include "threadimpl.h"
       -
       -void
       -incref(Ref *r)
       -{
       -        lock(&r->lk);
       -        r->ref++;
       -        unlock(&r->lk);
       -}
       -
       -long
       -decref(Ref *r)
       -{
       -        long n;
       -
       -        lock(&r->lk);
       -        n = --r->ref;
       -        unlock(&r->lk);
       -        return n;
       -}
 (DIR) diff --git a/src/libthread/sched.c b/src/libthread/sched.c
       t@@ -1,343 +0,0 @@
       -/*
       - * Thread scheduler.
       - */
       -#include "threadimpl.h"
       -
       -static Thread *runthread(Proc*);
       -static void schedexit(Proc*);
       -
       -/*
       - * Main scheduling loop.
       - */
       -void
       -_threadscheduler(void *arg)
       -{
       -        Proc *p;
       -        Thread *t;
       -
       -        p = arg;
       -
       -        _threadlinkmain();
       -        _threadsetproc(p);
       -
       -        for(;;){
       -                /* 
       -                 * Clean up zombie children.
       -                 */
       -
       -                /*
       -                 * Find next thread to run.
       -                 */
       -                _threaddebug(DBGSCHED, "runthread");
       -                t = runthread(p);
       -                if(t == nil)
       -                        schedexit(p);
       -        
       -                /*
       -                 * If it's ready, run it (might instead be marked to die).
       -                 */
       -                lock(&p->lock);
       -                if(t->state == Ready){
       -                        _threaddebug(DBGSCHED, "running %d.%d", p->id, t->id);
       -                        t->state = Running;
       -                        t->nextstate = Ready;
       -                        p->thread = t;
       -                        unlock(&p->lock);
       -                        _swaplabel(&p->context, &t->context);
       -                        lock(&p->lock);
       -                        p->thread = nil;
       -                }
       -
       -                /*
       -                 * If thread needs to die, kill it.
       -                 * t->proc == p may not be true if we're
       -                 * trying to jump into the exec proc (see exec-unix.c).
       -                 */
       -                if(t->moribund){
       -                        _threaddebug(DBGSCHED, "moribund %d.%d", p->id, t->id);
       -                        if(t->moribund != 1)
       -                                print("moribund broke %p %d\n", &t->moribund, t->moribund);
       -                        assert(t->moribund == 1);
       -                        t->state = Dead;
       -                        _procdelthread(p, t);
       -                        unlock(&p->lock);
       -                        _threadfree(t);
       -                        t = nil;
       -                        continue;
       -                }
       -
       -                /*
       -                 * If the thread has asked to move to another proc,
       -                 * let it go (only to be used in *very* special situations).
       -                if(t->nextproc != p)
       -                        _procdelthread(p, t);
       -                 */
       -
       -                unlock(&p->lock);
       -
       -                /*
       -                 * If the thread has asked to move to another proc,
       -                 * add it to the new proc.
       -                 */
       -                if(t->nextproc != p){
       -                //        lock(&t->nextproc->lock);
       -                //        _procaddthread(t->nextproc, t);
       -                //        unlock(&t->nextproc->lock);
       -                        t->proc = t->nextproc;
       -                }
       -
       -                /*
       -                 * If there is a request to run a function on the 
       -                 * scheduling stack, do so.
       -                 */
       -                if(p->schedfn){
       -                        _threaddebug(DBGSCHED, "schedfn");
       -                        p->schedfn(p);
       -                        p->schedfn = nil;
       -                        _threaddebug(DBGSCHED, "schedfn ended");
       -                }
       -
       -                /*
       -                 * Move the thread along.
       -                 */
       -                t->state = t->nextstate;
       -                _threaddebug(DBGSCHED, "moveon %d.%d", t->proc->id, t->id);
       -                if(t->state == Ready)
       -                        _threadready(t);
       -        }
       -}
       -
       -/*
       - * Called by thread to give up control of processor to scheduler.
       - */
       -int
       -_sched(void)
       -{
       -        Proc *p;
       -        Thread *t;
       -
       -        p = _threadgetproc();
       -        t = p->thread;
       -        assert(t != nil);
       -        _swaplabel(&t->context, &p->context);
       -        return p->nsched++;
       -}
       -
       -/*
       - * Called by thread to yield the processor to other threads.
       - * Returns number of other threads run between call and return.
       - */
       -int
       -yield(void)
       -{
       -        Proc *p;
       -        int nsched;
       -
       -        p = _threadgetproc();
       -        nsched = p->nsched;
       -        return _sched() - nsched;
       -}
       -
       -/*
       - * Choose the next thread to run.
       - */
       -static Thread*
       -runthread(Proc *p)
       -{
       -        Thread *t;
       -        Tqueue *q;
       -
       -        /*
       -         * No threads left?
       -         */
       -        if(p->nthreads==0 || (p->nthreads==1 && p->idle))
       -                return nil;
       -
       -        _threadschednote();
       -        lock(&p->readylock);
       -        q = &p->ready;
       -        if(q->head == nil){
       -                /*
       -                 * Is this a single-process program with an idle thread?
       -                 */
       -                if(p->idle){
       -                        /*
       -                         * The idle thread had better be ready!
       -                         */
       -                        if(p->idle->state != Ready)
       -                                sysfatal("all threads are asleep");
       -
       -                        /*
       -                         * Run the idle thread.
       -                         */
       -                        unlock(&p->readylock);
       -                        _threaddebug(DBGSCHED, "running idle thread", p->nthreads);
       -                        return p->idle;
       -                }
       -
       -                /*
       -                 * Wait until one of our threads is readied (by another proc!).
       -                 */
       -                q->asleep = 1;
       -                p->rend.l = &p->readylock;
       -                while(q->asleep){
       -                        _procsleep(&p->rend);
       -                        _threadschednote();
       -                }
       -
       -                /*
       -                 * Maybe we were awakened to exit?
       -                 */
       -                if(_threadexitsallstatus){
       -                        _threaddebug(DBGSCHED, "time to exit");
       -                        _exits(_threadexitsallstatus);
       -                }
       -                assert(q->head != nil);
       -        }
       -
       -        t = q->head;
       -        q->head = t->next;
       -        unlock(&p->readylock);
       -
       -        return t;
       -}
       -
       -/*
       - * Add a newly-ready thread to its proc's run queue.
       - */
       -void
       -_threadready(Thread *t)
       -{
       -        Tqueue *q;
       -
       -        /*
       -         * The idle thread does not go on the run queue.
       -         */
       -        if(t == t->proc->idle){
       -                _threaddebug(DBGSCHED, "idle thread is ready");
       -                return;
       -        }
       -
       -        assert(t->state == Ready);
       -        _threaddebug(DBGSCHED, "readying %d.%d", t->proc->id, t->id);
       -
       -        /*
       -         * Add thread to run queue.
       -         */
       -        q = &t->proc->ready;
       -        lock(&t->proc->readylock);
       -
       -        t->next = nil;
       -        if(q->head == nil)
       -                q->head = t;
       -        else
       -                q->tail->next = t;
       -        q->tail = t;
       -
       -        /*
       -         * Wake proc scheduler if it is sleeping.
       -         */
       -        if(q->asleep){
       -                assert(q->asleep == 1);
       -                q->asleep = 0;
       -                _procwakeup(&t->proc->rend);
       -        }
       -        unlock(&t->proc->readylock);
       -}
       -
       -/*
       - * Mark the given thread as the idle thread.
       - * Since the idle thread was just created, it is sitting
       - * somewhere on the ready queue.
       - */
       -void
       -_threadsetidle(int id)
       -{
       -        Tqueue *q;
       -        Thread *t, **l, *last;
       -        Proc *p;
       -
       -        p = _threadgetproc();
       -
       -        lock(&p->readylock);
       -
       -        /*
       -         * Find thread on ready queue.
       -         */
       -        q = &p->ready;
       -        for(l=&q->head, last=nil; (t=*l) != nil; l=&t->next, last=t)
       -                if(t->id == id)
       -                        break;
       -        assert(t != nil);
       -
       -        /* 
       -         * Remove it from ready queue.
       -         */
       -        *l = t->next;
       -        if(t == q->head)
       -                q->head = t->next;
       -        if(t->next == nil)
       -                q->tail = last;
       -
       -        /*
       -         * Set as idle thread.
       -         */
       -        p->idle = t;
       -        _threaddebug(DBGSCHED, "p->idle is %d\n", t->id);
       -        unlock(&p->readylock);
       -}
       -
       -/*
       - * Mark proc as internal so that if all but internal procs exit, we exit.
       - */
       -void
       -_threadinternalproc(void)
       -{
       -        Proc *p;
       -
       -        p = _threadgetproc();
       -        if(p->internal)
       -                return;
       -        lock(&_threadpq.lock);
       -        if(p->internal == 0){
       -                p->internal = 1;
       -                --_threadnprocs;
       -        }
       -        unlock(&_threadpq.lock);
       -}
       -
       -static void
       -schedexit(Proc *p)
       -{
       -        char ex[ERRMAX];
       -        int n;
       -        Proc **l;
       -
       -        _threaddebug(DBGSCHED, "exiting proc %d", p->id);
       -        lock(&_threadpq.lock);
       -        for(l=&_threadpq.head; *l; l=&(*l)->next){
       -                if(*l == p){
       -                        *l = p->next;
       -                        if(*l == nil)
       -                                _threadpq.tail = l;
       -                        break;
       -                }
       -        }
       -        if(p->internal)
       -                n = _threadnprocs;
       -        else
       -                n = --_threadnprocs;
       -        unlock(&_threadpq.lock);
       -
       -        strncpy(ex, p->exitstr, sizeof ex);
       -        ex[sizeof ex-1] = '\0';
       -        free(p);
       -        if(n == 0){
       -                _threaddebug(DBGSCHED, "procexit; no more procs");
       -                _kthreadexitallproc(ex);
       -        }else{
       -                _threaddebug(DBGSCHED, "procexit");
       -                _kthreadexitproc(ex);
       -        }
       -}
       -
 (DIR) diff --git a/src/libthread/setproc.c b/src/libthread/setproc.c
       t@@ -1,36 +0,0 @@
       -/*
       - * Avoid using threading calls for single-proc programs.
       - */
       -
       -#include "threadimpl.h"
       -
       -static int multi;
       -static Proc *theproc;
       -
       -void
       -_threadsetproc(Proc *p)
       -{
       -        if(!multi)
       -                theproc = p;
       -        else
       -                _kthreadsetproc(p);
       -}
       -
       -Proc*
       -_threadgetproc(void)
       -{
       -        if(!multi)
       -                return theproc;
       -        return _kthreadgetproc();
       -}
       -
       -void
       -_threadmultiproc(void)
       -{
       -        if(multi)
       -                return;
       -
       -        multi = 1;
       -        _kthreadinit();
       -        _threadsetproc(theproc);
       -}
 (DIR) diff --git a/src/libthread/sleep.c b/src/libthread/sleep.c
       t@@ -1,39 +0,0 @@
       -#include "threadimpl.h"
       -
       -int _threadhighnrendez;
       -int _threadnrendez;
       -
       -void
       -_threadsleep(_Procrend *r)
       -{
       -        Thread *t;
       -
       -        t = _threadgetproc()->thread;
       -        r->arg = t;
       -        t->nextstate = Rendezvous;
       -        t->asleep = 1;
       -        unlock(r->l);
       -        _sched();
       -        t->asleep = 0;
       -        lock(r->l);
       -}
       -
       -void
       -_threadwakeup(_Procrend *r)
       -{
       -        Thread *t;
       -
       -        t = r->arg;
       -        while(t->state == Running)
       -                sleep(0);
       -        lock(&t->proc->lock);
       -        if(t->state == Dead){
       -                unlock(&t->proc->lock);
       -                return;
       -        }
       -        assert(t->state == Rendezvous && t->asleep);
       -        t->state = Ready;
       -        _threadready(t);
       -        unlock(&t->proc->lock);
       -}
       -
 (DIR) diff --git a/src/libthread/sun4u.c b/src/libthread/sun4u.c
       t@@ -1,53 +0,0 @@
       -#include "threadimpl.h"
       -
       -static void
       -launchersparc(uint o0, uint o1, uint o2, uint o3,
       -        uint o4, uint o5, uint o6, uint o7,
       -        void (*f)(void *arg), void *arg)
       -{
       -        if(0) print("ls %x %x %x %x %x %x %x %x %x %x at %x\n",
       -                o0, o1, o2, o3, o4, o5, o6, o7, f, arg, &o0);
       -        (*f)(arg);
       -        threadexits(nil);
       -}
       -
       -void
       -_threadinitstack(Thread *t, void (*f)(void*), void *arg)
       -{
       -        ulong *tos, *stk;
       -
       -        /*
       -         * This is a bit more complicated than it should be,
       -         * because we need to set things up so that gotolabel
       -         * (which executes a return) gets us into launchersparc.
       -         * So all the registers are going to be renamed before
       -         * we get there.  The input registers here become the
       -         * output registers there, which is useless.  
       -         * The input registers there are inaccessible, so we
       -         * have to give launchersparc enough arguments that
       -         * everything ends up in the stack.
       -         */
       -        tos = (ulong*)&t->stk[t->stksize&~7];
       -        stk = tos;
       -        --stk;
       -        *--stk = (ulong)arg;
       -        *--stk = (ulong)f;
       -        stk -= 25;        /* would love to understand this */
       -        t->sched.link = (ulong)launchersparc - 8;
       -        t->sched.input[6] = 0;
       -        t->sched.sp = (ulong)stk;
       -        if(0) print("tis %x %x at %x\n", f, arg, t->sched.sp);
       -}
       -
       -void
       -_threadinswitch(int enter)
       -{
       -        USED(enter);
       -}
       -
       -void
       -_threadstacklimit(void *addr, void *addr2)
       -{
       -        USED(addr);
       -}
       -
 (DIR) diff --git a/src/libthread/sysofiles.sh b/src/libthread/sysofiles.sh
       t@@ -1,11 +0,0 @@
       -#!/bin/sh
       -
       -case "`uname`-`uname -r`" in
       -Linux-2.[01234]*)
       -        echo Linux-clone.o ucontext.o
       -        exit 0
       -        ;;
       -esac
       -
       -echo pthread.o ucontext.o
       -exit 0
 (DIR) diff --git a/src/libthread/test/pthreadloop.c b/src/libthread/test/pthreadloop.c
       t@@ -0,0 +1,38 @@
       +#include <pthread.h>
       +#include <utf.h>
       +#include <fmt.h>
       +
       +pthread_key_t key;
       +
       +void
       +pexit(void *v)
       +{
       +        int s;
       +
       +        pthread_setspecific(key, (void*)1);
       +        switch(fork()){
       +        case -1:
       +                fprint(2, "fork: %r\n");
       +        case 0:
       +                _exit(0);
       +        default:
       +                wait(&s);
       +        }
       +        pthread_exit(0);
       +}
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        int i;
       +        pthread_t pid;
       +
       +        pthread_key_create(&key, 0);
       +        for(i=0;; i++){
       +                print("%d\n", i);
       +                if(pthread_create(&pid, 0, pexit, 0) < 0){
       +                        fprint(2, "pthread_create: %r\n");
       +                        abort();
       +                }
       +        }
       +}
 (DIR) diff --git a/src/libthread/test/tprimes.c b/src/libthread/test/tprimes.c
       t@@ -0,0 +1,80 @@
       +#include "u.h"
       +#include "libc.h"
       +#include "thread.h"
       +
       +enum
       +{
       +        STACK = 8192
       +};
       +
       +int max = 10000;
       +int (*mk)(void (*fn)(void*), void *arg, uint stack);
       +
       +void
       +countthread(void *v)
       +{
       +        uint i;
       +        Channel *c;
       +
       +        c = v;
       +        for(i=2;; i++){
       +                sendul(c, i);
       +        }
       +}
       +
       +void
       +filterthread(void *v)
       +{
       +        uint i, p;
       +        Channel *c, *nextc;
       +
       +        c = v;
       +        p = recvul(c);
       +        print("%d\n", p);
       +        if(p > max)
       +                threadexitsall(0);
       +        nextc = chancreate(sizeof(ulong), 0);
       +        mk(filterthread, nextc, STACK);
       +        for(;;){
       +                i = recvul(c);
       +                if(i%p)
       +                        sendul(nextc, i);
       +        }
       +}
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: tprimes [-p] [max]\n");
       +        threadexitsall("usage");
       +}
       +
       +void
       +threadmain(int argc, char **argv)
       +{
       +        Channel *c;
       +        int nbuf;
       +
       +        nbuf = 0;
       +        mk = threadcreate;
       +        ARGBEGIN{
       +        default:
       +                usage();
       +        case 'b':
       +                nbuf = atoi(EARGF(usage()));
       +                break;
       +        case 'p':
       +                mk = proccreate;
       +                max = 1000;
       +                break;
       +        }ARGEND
       +
       +        if(argc == 1)
       +                max = atoi(argv[0]);
       +        else if(argc)
       +                usage();
       +
       +        c = chancreate(sizeof(ulong), nbuf);
       +        mk(countthread, c, STACK);
       +        mk(filterthread, c, STACK);
       +}
 (DIR) diff --git a/src/libthread/test/tspawn.c b/src/libthread/test/tspawn.c
       t@@ -0,0 +1,39 @@
       +#include "u.h"
       +#include "libc.h"
       +#include "thread.h"
       +
       +void
       +threadmain(int argc, char **argv)
       +{
       +        int fd[3];
       +        Channel *c;
       +        Waitmsg *w;
       +
       +        ARGBEGIN{
       +        case 'D':
       +                break;
       +        }ARGEND
       +
       +        c = threadwaitchan();
       +        fd[0] = dup(0, -1);
       +        fd[1] = dup(1, -1);
       +        fd[2] = dup(2, -1);
       +        if(threadspawn(fd, argv[0], argv) < 0)
       +                sysfatal("threadspawn: %r");
       +        fd[0] = dup(0, -1);
       +        fd[1] = dup(1, -1);
       +        fd[2] = dup(2, -1);
       +        if(threadspawn(fd, argv[0], argv) < 0)
       +                sysfatal("threadspawn: %r");
       +        w = recvp(c);
       +        if(w == nil)
       +                print("exec/recvp failed: %r\n");
       +        else
       +                print("%d %lud %lud %lud %s\n", w->pid, w->time[0], w->time[1], w->time[2], w->msg);
       +        w = recvp(c);
       +        if(w == nil)
       +                print("exec/recvp failed: %r\n");
       +        else
       +                print("%d %lud %lud %lud %s\n", w->pid, w->time[0], w->time[1], w->time[2], w->msg);
       +        threadexits(nil);
       +}
 (DIR) diff --git a/src/libthread/test/tspawnloop.c b/src/libthread/test/tspawnloop.c
       t@@ -0,0 +1,41 @@
       +#include "u.h"
       +#include "libc.h"
       +#include "thread.h"
       +
       +void
       +execproc(void *v)
       +{
       +        int i, fd[3];
       +        char buf[100], *args[3];
       +
       +        i = (int)v;
       +        sprint(buf, "%d", i);
       +        fd[0] = dup(0, -1);
       +        fd[1] = dup(1, -1);
       +        fd[2] = dup(2, -1);
       +        args[0] = "echo";
       +        args[1] = buf;
       +        args[2] = nil;
       +        threadexec(nil, fd, args[0], args);
       +}
       +        
       +void
       +threadmain(int argc, char **argv)
       +{
       +        int i;
       +        Channel *c;
       +        Waitmsg *w;
       +
       +        ARGBEGIN{
       +        case 'D':
       +                break;
       +        }ARGEND
       +
       +        c = threadwaitchan();
       +        for(i=0;; i++){
       +                proccreate(execproc, (void*)i, 16384);
       +                w = recvp(c);
       +                if(w == nil)
       +                        sysfatal("exec/recvp failed: %r");
       +        }
       +}
 (DIR) diff --git a/src/libthread/texec.c b/src/libthread/texec.c
       t@@ -1,45 +0,0 @@
       -#include <lib9.h>
       -#include <thread.h>
       -extern int _threaddebuglevel;
       -
       -void
       -doexec(void *v)
       -{
       -        int fd[3];
       -        char **argv = v;
       -
       -        fd[0] = dup(0, -1);
       -        fd[1] = dup(1, -1);
       -        fd[2] = dup(2, -1);
       -        threadexec(nil, fd, argv[0], argv);
       -        print("exec failed: %r\n");
       -        sendp(threadwaitchan(), nil);
       -        threadexits(nil);
       -}
       -
       -void
       -threadmain(int argc, char **argv)
       -{
       -        Channel *c;
       -        Waitmsg *w;
       -        int (*mk)(void(*)(void*), void*, uint);
       -
       -        mk = threadcreate;
       -        ARGBEGIN{
       -        case 'D':
       -                _threaddebuglevel = ~0;
       -                break;
       -        case 'p':
       -                mk = proccreate;
       -                break;
       -        }ARGEND
       -
       -        c = threadwaitchan();
       -        mk(doexec, argv, 8192);
       -        w = recvp(c);
       -        if(w == nil)
       -                print("exec/recvp failed: %r\n");
       -        else
       -                print("%d %lud %lud %lud %s\n", w->pid, w->time[0], w->time[1], w->time[2], w->msg);
       -        threadexits(nil);
       -}
 (DIR) diff --git a/src/libthread/tfork.c b/src/libthread/tfork.c
       t@@ -1,23 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -
       -Channel *c;
       -
       -void
       -f(void *v)
       -{
       -        recvp(c);
       -}
       -
       -void
       -threadmain(int argc, char **argv)
       -{
       -        int i;
       -
       -        c = chancreate(sizeof(ulong), 0);
       -        for(i=0;; i++){
       -                print("%d\n", i);
       -                proccreate(f, nil, 8192);
       -        }
       -}
 (DIR) diff --git a/src/libthread/thread.c b/src/libthread/thread.c
       t@@ -0,0 +1,535 @@
       +#include "u.h"
       +#include <linux/unistd.h>
       +#include "libc.h"
       +#include "thread.h"
       +#include "threadimpl.h"
       +
       +       _syscall0(pid_t,gettid)
       +
       +int        _threaddebuglevel;
       +
       +static        uint                threadnproc;
       +static        uint                threadnsysproc;
       +static        Lock                threadnproclock;
       +static        Ref                threadidref;
       +
       +static        void                addthread(_Threadlist*, _Thread*);
       +static        void                delthread(_Threadlist*, _Thread*);
       +static        void                addthreadinproc(Proc*, _Thread*);
       +static        void                delthreadinproc(Proc*, _Thread*);
       +static        void                contextswitch(Context *from, Context *to);
       +static        void                scheduler(void*);
       +
       +static _Thread*
       +getthreadnow(void)
       +{
       +        return proc()->thread;
       +}
       +_Thread        *(*threadnow)(void) = getthreadnow;
       +
       +static Proc*
       +procalloc(void)
       +{
       +        Proc *p;
       +
       +        p = malloc(sizeof *p);
       +        memset(p, 0, sizeof *p);
       +        lock(&threadnproclock);
       +        threadnproc++;
       +        unlock(&threadnproclock);
       +        return p;
       +}
       +
       +static void
       +threadstart(void *v)
       +{
       +        _Thread *t;
       +
       +        t = v;
       +        t->startfn(t->startarg);
       +        _threadexit();
       +}
       +
       +static _Thread*
       +threadalloc(void (*fn)(void*), void *arg, uint stack)
       +{
       +        _Thread *t;
       +        sigset_t zero;
       +
       +        /* allocate the task and stack together */
       +        t = malloc(sizeof *t+stack);
       +        memset(t, 0, sizeof *t);
       +        t->stk = (uchar*)(t+1);
       +        t->stksize = stack;
       +        t->id = incref(&threadidref);
       +        t->startfn = fn;
       +        t->startarg = arg;
       +
       +        /* do a reasonable initialization */
       +        memset(&t->context.uc, 0, sizeof t->context.uc);
       +        sigemptyset(&zero);
       +        sigprocmask(SIG_BLOCK, &zero, &t->context.uc.uc_sigmask);
       +
       +        /* on Linux makecontext neglects floating point */
       +        getcontext(&t->context.uc);
       +
       +        /* call makecontext to do the real work. */
       +        /* leave a few words open on both ends */
       +        t->context.uc.uc_stack.ss_sp = t->stk+8;
       +        t->context.uc.uc_stack.ss_size = t->stksize-16;
       +        makecontext(&t->context.uc, (void(*)())threadstart, 1, t);
       +
       +        return t;
       +}
       +
       +_Thread*
       +_threadcreate(Proc *p, void (*fn)(void*), void *arg, uint stack)
       +{
       +        _Thread *t;
       +
       +        t = threadalloc(fn, arg, stack);
       +        t->proc = p;
       +        addthreadinproc(p, t);
       +        p->nthread++;
       +        _threadready(t);
       +        return t;
       +}
       +
       +int
       +threadcreate(void (*fn)(void*), void *arg, uint stack)
       +{
       +        _Thread *t;
       +
       +        t = _threadcreate(proc(), fn, arg, stack);
       +        return t->id;
       +}
       +
       +int
       +proccreate(void (*fn)(void*), void *arg, uint stack)
       +{
       +        _Thread *t;
       +        Proc *p;
       +
       +        p = procalloc();
       +//print("pa %p\n", p);
       +        t = _threadcreate(p, fn, arg, stack);
       +//print("ps %p\n", p);
       +        _procstart(p, scheduler);
       +        return t->id;
       +}
       +
       +void
       +_threadswitch(void)
       +{
       +        Proc *p;
       +
       +        p = proc();
       +        contextswitch(&p->thread->context, &p->schedcontext);
       +}
       +
       +void
       +_threadready(_Thread *t)
       +{
       +        Proc *p;
       +
       +        p = t->proc;
       +        lock(&p->lock);
       +        addthread(&p->runqueue, t);
       +        _procwakeup(&p->runrend);
       +        unlock(&p->lock);
       +}
       +
       +void
       +threadyield(void)
       +{
       +        _threadready(proc()->thread);
       +        _threadswitch();
       +}
       +
       +void
       +_threadexit(void)
       +{
       +        proc()->thread->exiting = 1;
       +        _threadswitch();
       +}
       +
       +void
       +threadexits(char *msg)
       +{
       +/*
       +        Proc *p;
       +
       +        p = proc();
       +        utfecpy(p->msg, p->msg+sizeof p->msg, msg);
       +*/
       +        _threadexit();
       +}
       +
       +void
       +threadexitsall(char *msg)
       +{
       +        if(msg && msg[0])
       +                exit(1);
       +        exit(0);
       +}
       +
       +static void
       +contextswitch(Context *from, Context *to)
       +{
       +        if(swapcontext(&from->uc, &to->uc) < 0){
       +                fprint(2, "swapcontext failed: %r\n");
       +                assert(0);
       +        }
       +}
       +
       +static void
       +scheduler(void *v)
       +{
       +        _Thread *t;
       +        Proc *p;
       +
       +        p = v;
       +        setproc(p);
       +        print("s %p %d\n", p, gettid());
       +        p->tid = pthread_self();
       +        pthread_detach(p->tid);
       +        lock(&p->lock);
       +        for(;;){
       +                while((t = p->runqueue.head) == nil){
       +                        if(p->nthread == 0)
       +                                goto Out;
       +                        p->runrend.l = &p->lock;
       +                        _procsleep(&p->runrend);
       +                }
       +                delthread(&p->runqueue, t);
       +                unlock(&p->lock);
       +                p->thread = t;
       +                // print("run %s %d\n", t->name, t->id);
       +                contextswitch(&p->schedcontext, &t->context);
       +                p->thread = nil;
       +                lock(&p->lock);
       +                if(t->exiting){
       +                        delthreadinproc(p, t);
       +                        p->nthread--;
       +                        free(t);
       +                }
       +        }
       +
       +Out:
       +        lock(&threadnproclock);
       +        if(p->sysproc)
       +                --threadnsysproc;
       +        if(--threadnproc == threadnsysproc)
       +                exit(0);
       +        unlock(&threadnproclock);
       +        unlock(&p->lock);
       +        free(p);
       +        setproc(0);
       +        print("e %p (tid %d)\n", p, gettid());
       +        pthread_exit(nil);
       +}
       +
       +void
       +_threadsetsysproc(void)
       +{
       +        lock(&threadnproclock);
       +        if(++threadnsysproc == threadnproc)
       +                exit(0);
       +        unlock(&threadnproclock);
       +        proc()->sysproc = 1;
       +}
       +
       +/*
       + * debugging
       + */
       +void
       +threadsetname(char *fmt, ...)
       +{
       +        va_list arg;
       +        _Thread *t;
       +
       +        t = proc()->thread;
       +        va_start(arg, fmt);
       +        vsnprint(t->name, sizeof t->name, fmt, arg);
       +        va_end(arg);
       +}
       +
       +void
       +threadsetstate(char *fmt, ...)
       +{
       +        va_list arg;
       +        _Thread *t;
       +
       +        t = proc()->thread;
       +        va_start(arg, fmt);
       +        vsnprint(t->state, sizeof t->name, fmt, arg);
       +        va_end(arg);
       +}
       +
       +/*
       + * locking
       + */
       +static int
       +threadqlock(QLock *l, int block, ulong pc)
       +{
       +        lock(&l->l);
       +        if(l->owner == nil){
       +                l->owner = (*threadnow)();
       +//print("qlock %p @%#x by %p\n", l, pc, l->owner);
       +                unlock(&l->l);
       +                return 1;
       +        }
       +        if(!block){
       +                unlock(&l->l);
       +                return 0;
       +        }
       +//print("qsleep %p @%#x by %p\n", l, pc, (*threadnow)());
       +        addthread(&l->waiting, (*threadnow)());
       +        unlock(&l->l);
       +
       +        _threadswitch();
       +
       +        if(l->owner != (*threadnow)()){
       +                fprint(2, "qlock pc=0x%lux owner=%p self=%p oops\n", pc, l->owner, (*threadnow)());
       +                abort();
       +        }
       +//print("qlock wakeup %p @%#x by %p\n", l, pc, (*threadnow)());
       +        return 1;
       +}
       +
       +static void
       +threadqunlock(QLock *l, ulong pc)
       +{
       +        lock(&l->l);
       +//print("qlock unlock %p @%#x by %p (owner %p)\n", l, pc, (*threadnow)(), l->owner);
       +        if(l->owner == nil){
       +                fprint(2, "qunlock pc=0x%lux owner=%p self=%p oops\n",
       +                        pc, l->owner, (*threadnow)());
       +                abort();
       +        }
       +        if((l->owner = l->waiting.head) != nil){
       +                delthread(&l->waiting, l->owner);
       +                _threadready(l->owner);
       +        }
       +        unlock(&l->l);
       +}
       +
       +static int
       +threadrlock(RWLock *l, int block, ulong pc)
       +{
       +        USED(pc);
       +
       +        lock(&l->l);
       +        if(l->writer == nil && l->wwaiting.head == nil){
       +                l->readers++;
       +                unlock(&l->l);
       +                return 1;
       +        }
       +        if(!block){
       +                unlock(&l->l);
       +                return 0;
       +        }
       +        addthread(&l->rwaiting, (*threadnow)());
       +        unlock(&l->l);
       +        _threadswitch();
       +        return 1;        
       +}
       +
       +static int
       +threadwlock(RWLock *l, int block, ulong pc)
       +{
       +        USED(pc);
       +
       +        lock(&l->l);
       +        if(l->writer == nil && l->readers == 0){
       +                l->writer = (*threadnow)();
       +                unlock(&l->l);
       +                return 1;
       +        }
       +        if(!block){
       +                unlock(&l->l);
       +                return 0;
       +        }
       +        addthread(&l->wwaiting, (*threadnow)());
       +        unlock(&l->l);
       +        _threadswitch();
       +        return 1;
       +}
       +
       +static void
       +threadrunlock(RWLock *l, ulong pc)
       +{
       +        _Thread *t;
       +
       +        USED(pc);
       +        lock(&l->l);
       +        --l->readers;
       +        if(l->readers == 0 && (t = l->wwaiting.head) != nil){
       +                delthread(&l->wwaiting, t);
       +                l->writer = t;
       +                _threadready(t);
       +        }
       +        unlock(&l->l);
       +}
       +
       +static void
       +threadwunlock(RWLock *l, ulong pc)
       +{
       +        _Thread *t;
       +
       +        USED(pc);
       +        lock(&l->l);
       +        l->writer = nil;
       +        assert(l->readers == 0);
       +        while((t = l->rwaiting.head) != nil){
       +                delthread(&l->rwaiting, t);
       +                l->readers++;
       +                _threadready(t);
       +        }
       +        if(l->readers == 0 && (t = l->wwaiting.head) != nil){
       +                delthread(&l->wwaiting, t);
       +                l->writer = t;
       +                _threadready(t);
       +        }
       +        unlock(&l->l);
       +}
       +
       +/*
       + * sleep and wakeup
       + */
       +static void
       +threadrsleep(Rendez *r, ulong pc)
       +{
       +        addthread(&r->waiting, proc()->thread);
       +        qunlock(r->l);
       +        _threadswitch();
       +        qlock(r->l);
       +}
       +
       +static int
       +threadrwakeup(Rendez *r, int all, ulong pc)
       +{
       +        int i;
       +        _Thread *t;
       +
       +        for(i=0;; i++){
       +                if(i==1 && !all)
       +                        break;
       +                if((t = r->waiting.head) == nil)
       +                        break;
       +                delthread(&r->waiting, t);
       +                _threadready(t);        
       +        }
       +        return i;
       +}
       +
       +/*
       + * hooray for linked lists
       + */
       +static void
       +addthread(_Threadlist *l, _Thread *t)
       +{
       +        if(l->tail){
       +                l->tail->next = t;
       +                t->prev = l->tail;
       +        }else{
       +                l->head = t;
       +                t->prev = nil;
       +        }
       +        l->tail = t;
       +        t->next = nil;
       +}
       +
       +static void
       +delthread(_Threadlist *l, _Thread *t)
       +{
       +        if(t->prev)
       +                t->prev->next = t->next;
       +        else
       +                l->head = t->next;
       +        if(t->next)
       +                t->next->prev = t->prev;
       +        else
       +                l->tail = t->prev;
       +}
       +
       +static void
       +addthreadinproc(Proc *p, _Thread *t)
       +{
       +        _Threadlist *l;
       +
       +        l = &p->allthreads;
       +        if(l->tail){
       +                l->tail->allnext = t;
       +                t->allprev = l->tail;
       +        }else{
       +                l->head = t;
       +                t->allprev = nil;
       +        }
       +        l->tail = t;
       +        t->allnext = nil;
       +}
       +
       +static void
       +delthreadinproc(Proc *p, _Thread *t)
       +{
       +        _Threadlist *l;
       +
       +        l = &p->allthreads;
       +        if(t->allprev)
       +                t->allprev->allnext = t->allnext;
       +        else
       +                l->head = t->allnext;
       +        if(t->allnext)
       +                t->allnext->allprev = t->allprev;
       +        else
       +                l->tail = t->allprev;
       +}
       +
       +void**
       +procdata(void)
       +{
       +        return &proc()->udata;
       +}
       +
       +static int threadargc;
       +static char **threadargv;
       +int mainstacksize;
       +
       +static void
       +threadmainstart(void *v)
       +{
       +        USED(v);
       +        threadmain(threadargc, threadargv);
       +}
       +
       +int
       +main(int argc, char **argv)
       +{
       +        Proc *p;
       +
       +        threadargc = argc;
       +        threadargv = argv;
       +
       +        /*
       +         * Install locking routines into C library.
       +         */
       +        _lock = _threadlock;
       +        _unlock = _threadunlock;
       +        _qlock = threadqlock;
       +        _qunlock = threadqunlock;
       +        _rlock = threadrlock;
       +        _runlock = threadrunlock;
       +        _wlock = threadwlock;
       +        _wunlock = threadwunlock;
       +        _rsleep = threadrsleep;
       +        _rwakeup = threadrwakeup;
       +
       +        pthreadinit();
       +        p = procalloc();
       +        if(mainstacksize == 0)
       +                mainstacksize = 65536;
       +        _threadcreate(p, threadmainstart, nil, mainstacksize);
       +        scheduler(p);
       +        return 0;        /* not reached */
       +}
 (DIR) diff --git a/src/libthread/thread.sh b/src/libthread/thread.sh
       t@@ -1,15 +0,0 @@
       -#!/bin/sh
       -
       -if [ `uname` = Linux ]
       -then
       -        case `uname -r` in
       -        2.[6789]*)
       -                echo pthread
       -                ;;
       -        *)
       -                echo Linux-clone
       -                ;;
       -        esac
       -else
       -        echo pthread
       -fi
 (DIR) diff --git a/src/libthread/threadimpl.h b/src/libthread/threadimpl.h
       t@@ -1,241 +0,0 @@
       -/* 
       - * Some notes on locking:
       - *
       - *        All the locking woes come from implementing
       - *        threadinterrupt (and threadkill).
       - *
       - *        _threadgetproc()->thread is always a live pointer.
       - *        p->threads, p->ready, and _threadrgrp also contain
       - *         live thread pointers.  These may only be consulted
       - *        while holding p->lock; in procs other than p, the
       - *        pointers are only guaranteed to be live while the lock
       - *        is still being held.
       - *
       - *        Thread structures can only be freed by the proc
       - *        they belong to.  Threads marked with t->inrendez
       - *         need to be extracted from the _threadrgrp before
       - *        being freed.
       - */
       -
       -#include <u.h>
       -#include <assert.h>
       -#include <libc.h>
       -#include <thread.h>
       -#include "label.h"
       -
       -typedef struct Thread        Thread;
       -typedef struct Proc                Proc;
       -typedef struct Tqueue        Tqueue;
       -typedef struct Pqueue        Pqueue;
       -typedef struct Execargs        Execargs;
       -typedef struct Jmp Jmp;
       -
       -/* sync with ../lib9/notify.c */
       -struct Jmp
       -{
       -        p9jmp_buf b;
       -};
       -
       -
       -typedef enum
       -{
       -        Dead,
       -        Running,
       -        Ready,
       -        Rendezvous,
       -} State;
       -        
       -typedef enum
       -{
       -        Channone,
       -        Chanalt,
       -        Chansend,
       -        Chanrecv,
       -} Chanstate;
       -
       -enum
       -{
       -        NPRIV = 8,
       -};
       -
       -struct Tqueue                /* Thread queue */
       -{
       -        int                asleep;
       -        Thread        *head;
       -        Thread        *tail;
       -};
       -
       -struct Pqueue {                /* Proc queue */
       -        Lock                lock;
       -        Proc                *head;
       -        Proc                **tail;
       -};
       -
       -struct Thread
       -{
       -        Lock                lock;                        /* protects thread data structure */
       -
       -        int                asleep;                /* thread is in _threadsleep */
       -        Label        context;                /* for context switches */
       -        int                 grp;                        /* thread group */
       -        Proc                *homeproc;        /* ``home'' proc */
       -        int                id;                        /* thread id */
       -        int                moribund;        /* thread needs to die */
       -        char                *name;                /* name of thread */
       -        Thread        *next;                /* next on ready queue */
       -        Thread        *nextt;                /* next on list of threads in this proc */
       -        Proc                *nextproc;        /* next proc in which to run (rarely changes) */
       -        State                nextstate;                /* next run state */
       -        Proc                *proc;                /* proc of this thread */
       -        Thread        *prevt;                /* prev on list of threads in this proc */
       -        int                ret;                        /* return value for Exec, Fork */
       -        State                state;                /* run state */
       -        uchar        *stk;                        /* top of stack (lowest address of stack) */
       -        uint                stksize;                /* stack size */
       -        void*        udata[NPRIV];        /* User per-thread data pointer */
       -
       -        /*
       -         * for debugging only
       -         * (could go away without impacting correct behavior):
       -         */
       -
       -        Channel        *altc;
       -        _Procrend        altrend;
       -
       -        Chanstate        chan;                /* which channel operation is current */
       -        Alt                *alt;                        /* pointer to current alt structure (debugging) */
       -        ulong                userpc;
       -        Channel        *c;
       -
       -};
       -
       -struct Execargs
       -{
       -        char                *prog;
       -        char                **args;
       -        int                fd[2];
       -        int                *stdfd;
       -};
       -
       -struct Proc
       -{
       -        Lock                lock;
       -
       -        Label        context;                /* for context switches */
       -        Proc                *link;                /* in ptab */
       -        int                splhi;                /* delay notes */
       -        Thread        *thread;                /* running thread */
       -        Thread        *idle;                        /* idle thread */
       -        int                id;
       -        int                procid;
       -
       -        int                needexec;
       -        Execargs        exec;                /* exec argument */
       -        Proc                *newproc;        /* fork argument */
       -        char                exitstr[ERRMAX];        /* exit status */
       -
       -        int                internal;
       -        int                rforkflag;
       -        int                nthreads;
       -        Tqueue        threads;                /* All threads of this proc */
       -        Tqueue        ready;                /* Runnable threads */
       -        Lock                readylock;
       -
       -        int                blocked;                /* In a rendezvous */
       -        int                pending;                /* delayed note pending */
       -        int                nonotes;                /*  delay notes */
       -        uint                nextID;                /* ID of most recently created thread */
       -        Proc                *next;                /* linked list of Procs */
       -
       -        Jmp                sigjmp;                /* for notify implementation */
       -
       -        void                (*schedfn)(Proc*);        /* function to call in scheduler */
       -
       -        _Procrend        rend;        /* sleep here for more ready threads */
       -
       -        void                *arg;                        /* passed between shared and unshared stk */
       -        char                str[ERRMAX];        /* used by threadexits to avoid malloc */
       -        char                errbuf[ERRMAX];        /* errstr */
       -        Waitmsg                *waitmsg;
       -
       -        void*        udata;                /* User per-proc data pointer */
       -        int                nsched;
       -
       -        /*
       -         * for debugging only
       -         */
       -        int                pid;                        /* process id */
       -        int                pthreadid;                /* pthread id */
       -};
       -
       -void                _swaplabel(Label*, Label*);
       -Proc*        _newproc(void);
       -int                _newthread(Proc*, void(*)(void*), void*, uint, char*, int);
       -int                _sched(void);
       -int                _schedexec(Execargs*);
       -void                _schedexecwait(void);
       -void                _schedexit(Proc*);
       -int                _schedfork(Proc*);
       -void                _threadfree(Thread*);
       -void                _threadscheduler(void*);
       -void                _systhreadinit(void);
       -void                _threadassert(char*);
       -void                __threaddebug(ulong, char*, ...);
       -#define _threaddebug if(!_threaddebuglevel){}else __threaddebug
       -void                _threadexitsall(char*);
       -Proc*        _threadgetproc(void);
       -extern void        _threadmultiproc(void);
       -Proc*        _threaddelproc(void);
       -void                _kthreadinitproc(Proc*);
       -void                _threadsetproc(Proc*);
       -void                _threadinitstack(Thread*, void(*)(void*), void*);
       -void                _threadlinkmain(void);
       -void*        _threadmalloc(long, int);
       -void                _threadnote(void*, char*);
       -void                _threadready(Thread*);
       -void                _threadschednote(void);
       -void                _threadsetidle(int);
       -void                _threadsleep(_Procrend*);
       -void                _threadwakeup(_Procrend*);
       -void                _threadsignal(void);
       -void                _threadsysfatal(char*, va_list);
       -long                _xdec(long*);
       -void                _xinc(long*);
       -void                _threadremove(Proc*, Thread*);
       -void                threadstatus(void);
       -void                _threadefork(int[3], int[2], char*, char**);
       -Jmp*                _threadgetjmp(void);
       -void                _kthreadinit(void);
       -void                _kthreadsetproc(Proc*);
       -Proc*        _kthreadgetproc(void);
       -void                _kthreadstartproc(Proc*);
       -void                _kthreadexitproc(char*);
       -void                _kthreadexitallproc(char*);
       -void                _threadinternalproc(void);
       -void                _threadbackgroundinit(void);
       -void                _kmaininit(void);
       -
       -extern int                        _threadnprocs;
       -extern int                        _threaddebuglevel;
       -extern char*                _threadexitsallstatus;
       -extern Pqueue                _threadpq;
       -extern Channel*        _threadwaitchan;
       -
       -#define DBGAPPL        (1 << 0)
       -#define DBGSCHED        (1 << 16)
       -#define DBGCHAN        (1 << 17)
       -#define DBGREND        (1 << 18)
       -/* #define DBGKILL        (1 << 19) */
       -#define DBGNOTE        (1 << 20)
       -#define DBGEXEC        (1 << 21)
       -
       -extern void _threadmemset(void*, int, int);
       -extern void _threaddebugmemset(void*, int, int);
       -extern int _threadprocs;
       -extern void _threadstacklimit(void*, void*);
       -extern void _procdelthread(Proc*, Thread*);
       -extern void _procaddthread(Proc*, Thread*);
       -
       -extern void _threadmaininit(void);
       -extern int _threadexec(Channel*, int[3], char*, char*[], int);
       -extern int _kthreadexec(Channel*, int[3], char*, char*[], int);
 (DIR) diff --git a/src/libthread/tprimes.c b/src/libthread/tprimes.c
       t@@ -1,68 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -
       -enum
       -{
       -        STACK = 8192
       -};
       -
       -int quiet;
       -int goal;
       -int buffer;
       -int (*fn)(void(*)(void*), void*, uint) = threadcreate;
       -
       -void
       -primethread(void *arg)
       -{
       -        Channel *c, *nc;
       -        int p, i;
       -
       -        c = arg;
       -        p = recvul(c);
       -        if(p > goal)
       -                threadexitsall(nil);
       -        if(!quiet)
       -                print("%d\n", p);
       -        nc = chancreate(sizeof(ulong), buffer);
       -        (*fn)(primethread, nc, STACK);
       -        for(;;){
       -                i = recvul(c);
       -                if(i%p)
       -                        sendul(nc, i);
       -        }
       -}
       -
       -extern int _threaddebuglevel;
       -
       -void
       -threadmain(int argc, char **argv)
       -{
       -        int i;
       -        Channel *c;
       -
       -        ARGBEGIN{
       -        case 'D':
       -                _threaddebuglevel = atoi(ARGF());
       -                break;
       -        case 'q':
       -                quiet = 1;
       -                break;
       -        case 'b':
       -                buffer = atoi(ARGF());
       -                break;
       -        case 'p':
       -                fn = proccreate;
       -                break;
       -        }ARGEND
       -
       -        if(argc>0)
       -                goal = atoi(argv[0]);
       -        else
       -                goal = 100;
       -
       -        c = chancreate(sizeof(ulong), buffer);
       -        (*fn)(primethread, c, STACK);
       -        for(i=2;; i++)
       -                sendul(c, i);
       -}
 (DIR) diff --git a/src/libthread/trend.c b/src/libthread/trend.c
       t@@ -1,31 +0,0 @@
       -#include <lib9.h>
       -#include <thread.h>
       -
       -Channel *c[3];
       -
       -
       -void
       -pingpong(void *v)
       -{
       -        int n;
       -        Channel **c;
       -
       -        c = v;
       -        do{
       -                n = recvul(c[0]);
       -                sendul(c[1], n-1);
       -        }while(n > 0);
       -        exit(0);
       -}
       -
       -void
       -threadmain(int argc, char **argv)
       -{
       -        c[0] = chancreate(sizeof(ulong), 1);
       -        c[1] = chancreate(sizeof(ulong), 1);
       -        c[2] = c[0];
       -
       -        proccreate(pingpong, c, 16384);
       -        threadcreate(pingpong, c+1, 16384);
       -        sendul(c[0], atoi(argv[1]));
       -}
 (DIR) diff --git a/src/libthread/tsignal.c b/src/libthread/tsignal.c
       t@@ -1,43 +0,0 @@
       -#include <u.h>
       -#include <libc.h>
       -#include <thread.h>
       -
       -extern int _threaddebuglevel;
       -
       -void
       -usage(void)
       -{
       -        fprint(2, "usage: tsignal [-[ednf] note]*\n");
       -        threadexitsall("usage");
       -}
       -
       -void
       -threadmain(int argc, char **argv)
       -{
       -        Channel *c;
       -        char *msg;
       -
       -        ARGBEGIN{
       -        case 'D':
       -                _threaddebuglevel = ~0;
       -                break;
       -        default:
       -                usage();
       -        case 'e':
       -                notifyenable(EARGF(usage()));
       -                break;
       -        case 'd':
       -                notifydisable(EARGF(usage()));
       -                break;
       -        case 'n':
       -                notifyon(EARGF(usage()));
       -                break;
       -        case 'f':
       -                notifyoff(EARGF(usage()));
       -                break;
       -        }ARGEND
       -
       -        c = threadnotechan();
       -        while((msg = recvp(c)) != nil)
       -                print("note: %s\n", msg);
       -}
 (DIR) diff --git a/src/libthread/tspawn.c b/src/libthread/tspawn.c
       t@@ -1,41 +0,0 @@
       -#include <lib9.h>
       -#include <thread.h>
       -extern int _threaddebuglevel;
       -
       -void
       -doexec(void *v)
       -{
       -        int fd[3];
       -        char **argv = v;
       -
       -        print("exec failed: %r\n");
       -        sendp(threadwaitchan(), nil);
       -        threadexits(nil);
       -}
       -
       -void
       -threadmain(int argc, char **argv)
       -{
       -        int fd[3];
       -        Channel *c;
       -        Waitmsg *w;
       -
       -        ARGBEGIN{
       -        case 'D':
       -                _threaddebuglevel = ~0;
       -                break;
       -        }ARGEND
       -
       -        c = threadwaitchan();
       -        fd[0] = dup(0, -1);
       -        fd[1] = dup(1, -1);
       -        fd[2] = dup(2, -1);
       -        if(threadspawn(fd, argv[0], argv) < 0)
       -                sysfatal("threadspawn: %r");
       -        w = recvp(c);
       -        if(w == nil)
       -                print("exec/recvp failed: %r\n");
       -        else
       -                print("%d %lud %lud %lud %s\n", w->pid, w->time[0], w->time[1], w->time[2], w->msg);
       -        threadexits(nil);
       -}
 (DIR) diff --git a/src/libthread/ucontext.c b/src/libthread/ucontext.c
       t@@ -1,49 +0,0 @@
       -#include "threadimpl.h"
       -
       -static void
       -launcher(void (*f)(void*), void *arg)
       -{
       -        f(arg);
       -        threadexits(nil);
       -}
       -
       -void
       -_threadinitstack(Thread *t, void (*f)(void*), void *arg)
       -{
       -        sigset_t zero;
       -
       -        /* do a reasonable initialization */
       -        memset(&t->context.uc, 0, sizeof t->context.uc);
       -        sigemptyset(&zero);
       -        sigprocmask(SIG_BLOCK, &zero, &t->context.uc.uc_sigmask);
       -
       -        /* call getcontext, because on Linux makecontext neglects floating point */
       -        getcontext(&t->context.uc);
       -
       -        /* call makecontext to do the real work. */
       -        /* leave a few words open on both ends */
       -        t->context.uc.uc_stack.ss_sp = t->stk+8;
       -        t->context.uc.uc_stack.ss_size = t->stksize-16;
       -        makecontext(&t->context.uc, (void(*)())launcher, 2, f, arg);
       -}
       -
       -void
       -_threadinswitch(int enter)
       -{
       -        USED(enter);
       -}
       -
       -void
       -_threadstacklimit(void *bottom, void *top)
       -{
       -        USED(bottom);
       -        USED(top);
       -}
       -
       -void
       -_swaplabel(Label *old, Label *new)
       -{
       -        if(swapcontext(&old->uc, &new->uc) < 0)
       -                sysfatal("swapcontext: %r");
       -}
       -