From 1544f90960275dc9211bde30329c3258e0e1bf38 Mon Sep 17 00:00:00 2001 From: rsc Date: Sat, 25 Dec 2004 21:56:33 +0000 Subject: New thread library --- src/libthread/386.c | 62 ---- src/libthread/FreeBSD-386.s | 18 - src/libthread/Linux-clone.c | 185 ----------- src/libthread/NOTICE | 19 -- src/libthread/PowerMacintosh.c | 39 --- src/libthread/README | 19 -- src/libthread/asm-Darwin-PowerMacintosh.s | 80 ----- src/libthread/asm-FreeBSD-386.s | 55 --- src/libthread/asm-Linux-386.s | 1 - src/libthread/asm-Linux-power.s | 80 ----- src/libthread/asm-OpenBSD-386.s | 49 --- src/libthread/asm-SunOS-sun4u.s | 51 --- src/libthread/channel.c | 500 ---------------------------- src/libthread/chanprint.c | 20 -- src/libthread/create.c | 211 ------------ src/libthread/debug.c | 48 --- src/libthread/exec-unix.c | 147 -------- src/libthread/exec.c | 153 +++++++++ src/libthread/execproc.ch | 183 ---------- src/libthread/exit-getpid.ch | 25 -- src/libthread/exit.c | 44 --- src/libthread/fdwait.c | 241 -------------- src/libthread/getpid.c | 7 - src/libthread/id.c | 136 -------- src/libthread/iocall.c | 55 --- src/libthread/ioclose.c | 16 - src/libthread/iodial.c | 24 -- src/libthread/ioopen.c | 21 -- src/libthread/ioproc.c | 77 ----- src/libthread/ioproc.h | 14 - src/libthread/ioread.c | 20 -- src/libthread/ioreadn.c | 21 -- src/libthread/iorw.c | 178 ++++++++++ src/libthread/iosleep.c | 16 - src/libthread/iowrite.c | 22 -- src/libthread/kill.c | 90 ----- src/libthread/label.h | 68 ---- src/libthread/lib.c | 35 -- src/libthread/main.c | 98 ------ src/libthread/memset.c | 8 - src/libthread/memsetd.c | 8 - src/libthread/mkfile | 73 ---- src/libthread/note.c | 145 -------- src/libthread/pid.c | 25 -- src/libthread/power.c | 40 --- src/libthread/procstack.ch | 75 ----- src/libthread/proctab.c | 75 ----- src/libthread/proctab.ch | 97 ------ src/libthread/pthread.c | 271 --------------- src/libthread/qlock.c | 3 + src/libthread/read9pmsg.c | 32 -- src/libthread/ref.c | 26 -- src/libthread/sched.c | 343 ------------------- src/libthread/setproc.c | 36 -- src/libthread/sleep.c | 39 --- src/libthread/sun4u.c | 53 --- src/libthread/sysofiles.sh | 11 - src/libthread/test/pthreadloop.c | 38 +++ src/libthread/test/tprimes.c | 80 +++++ src/libthread/test/tspawn.c | 39 +++ src/libthread/test/tspawnloop.c | 41 +++ src/libthread/texec.c | 45 --- src/libthread/tfork.c | 23 -- src/libthread/thread.c | 535 ++++++++++++++++++++++++++++++ src/libthread/thread.sh | 15 - src/libthread/threadimpl.h | 241 -------------- src/libthread/tprimes.c | 68 ---- src/libthread/trend.c | 31 -- src/libthread/tsignal.c | 43 --- src/libthread/tspawn.c | 41 --- src/libthread/ucontext.c | 49 --- 71 files changed, 1067 insertions(+), 4710 deletions(-) delete mode 100644 src/libthread/386.c delete mode 100644 src/libthread/FreeBSD-386.s delete mode 100644 src/libthread/Linux-clone.c delete mode 100644 src/libthread/NOTICE delete mode 100644 src/libthread/PowerMacintosh.c delete mode 100644 src/libthread/README delete mode 100644 src/libthread/asm-Darwin-PowerMacintosh.s delete mode 100644 src/libthread/asm-FreeBSD-386.s delete mode 100644 src/libthread/asm-Linux-386.s delete mode 100644 src/libthread/asm-Linux-power.s delete mode 100644 src/libthread/asm-OpenBSD-386.s delete mode 100644 src/libthread/asm-SunOS-sun4u.s delete mode 100644 src/libthread/channel.c delete mode 100644 src/libthread/chanprint.c delete mode 100644 src/libthread/create.c delete mode 100644 src/libthread/debug.c delete mode 100644 src/libthread/exec-unix.c create mode 100644 src/libthread/exec.c delete mode 100644 src/libthread/execproc.ch delete mode 100644 src/libthread/exit-getpid.ch delete mode 100644 src/libthread/exit.c delete mode 100644 src/libthread/fdwait.c delete mode 100644 src/libthread/getpid.c delete mode 100644 src/libthread/id.c delete mode 100644 src/libthread/iocall.c delete mode 100644 src/libthread/ioclose.c delete mode 100644 src/libthread/iodial.c delete mode 100644 src/libthread/ioopen.c delete mode 100644 src/libthread/ioproc.c delete mode 100644 src/libthread/ioproc.h delete mode 100644 src/libthread/ioread.c delete mode 100644 src/libthread/ioreadn.c create mode 100644 src/libthread/iorw.c delete mode 100644 src/libthread/iosleep.c delete mode 100644 src/libthread/iowrite.c delete mode 100644 src/libthread/kill.c delete mode 100644 src/libthread/label.h delete mode 100644 src/libthread/lib.c delete mode 100644 src/libthread/main.c delete mode 100644 src/libthread/memset.c delete mode 100644 src/libthread/memsetd.c delete mode 100644 src/libthread/mkfile delete mode 100644 src/libthread/note.c delete mode 100644 src/libthread/pid.c delete mode 100644 src/libthread/power.c delete mode 100644 src/libthread/procstack.ch delete mode 100644 src/libthread/proctab.c delete mode 100644 src/libthread/proctab.ch delete mode 100644 src/libthread/pthread.c create mode 100644 src/libthread/qlock.c delete mode 100644 src/libthread/read9pmsg.c delete mode 100644 src/libthread/ref.c delete mode 100644 src/libthread/sched.c delete mode 100644 src/libthread/setproc.c delete mode 100644 src/libthread/sleep.c delete mode 100644 src/libthread/sun4u.c delete mode 100644 src/libthread/sysofiles.sh create mode 100644 src/libthread/test/pthreadloop.c create mode 100644 src/libthread/test/tprimes.c create mode 100644 src/libthread/test/tspawn.c create mode 100644 src/libthread/test/tspawnloop.c delete mode 100644 src/libthread/texec.c delete mode 100644 src/libthread/tfork.c create mode 100644 src/libthread/thread.c delete mode 100644 src/libthread/thread.sh delete mode 100644 src/libthread/threadimpl.h delete mode 100644 src/libthread/tprimes.c delete mode 100644 src/libthread/trend.c delete mode 100644 src/libthread/tsignal.c delete mode 100644 src/libthread/tspawn.c delete mode 100644 src/libthread/ucontext.c (limited to 'src/libthread') diff --git a/src/libthread/386.c b/src/libthread/386.c deleted file mode 100644 index 313c2be5..00000000 --- a/src/libthread/386.c +++ /dev/null @@ -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 -#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 diff --git a/src/libthread/FreeBSD-386.s b/src/libthread/FreeBSD-386.s deleted file mode 100644 index 624518e0..00000000 --- a/src/libthread/FreeBSD-386.s +++ /dev/null @@ -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 - diff --git a/src/libthread/Linux-clone.c b/src/libthread/Linux-clone.c deleted file mode 100644 index 1f5e3bde..00000000 --- a/src/libthread/Linux-clone.c +++ /dev/null @@ -1,185 +0,0 @@ -#include -#include -#include -#include -#include -#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) -{ -} - diff --git a/src/libthread/NOTICE b/src/libthread/NOTICE deleted file mode 100644 index 8bf69d6a..00000000 --- a/src/libthread/NOTICE +++ /dev/null @@ -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 . - diff --git a/src/libthread/PowerMacintosh.c b/src/libthread/PowerMacintosh.c deleted file mode 100644 index 94d4db9a..00000000 --- a/src/libthread/PowerMacintosh.c +++ /dev/null @@ -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); -} - diff --git a/src/libthread/README b/src/libthread/README deleted file mode 100644 index 8bf69d6a..00000000 --- a/src/libthread/README +++ /dev/null @@ -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 . - diff --git a/src/libthread/asm-Darwin-PowerMacintosh.s b/src/libthread/asm-Darwin-PowerMacintosh.s deleted file mode 100644 index c503e1d6..00000000 --- a/src/libthread/asm-Darwin-PowerMacintosh.s +++ /dev/null @@ -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 diff --git a/src/libthread/asm-FreeBSD-386.s b/src/libthread/asm-FreeBSD-386.s deleted file mode 100644 index c815ac58..00000000 --- a/src/libthread/asm-FreeBSD-386.s +++ /dev/null @@ -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 -# diff --git a/src/libthread/asm-Linux-386.s b/src/libthread/asm-Linux-386.s deleted file mode 100644 index 75d965bf..00000000 --- a/src/libthread/asm-Linux-386.s +++ /dev/null @@ -1 +0,0 @@ -.include "asm-FreeBSD-386.s" diff --git a/src/libthread/asm-Linux-power.s b/src/libthread/asm-Linux-power.s deleted file mode 100644 index 00bfec3e..00000000 --- a/src/libthread/asm-Linux-power.s +++ /dev/null @@ -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 diff --git a/src/libthread/asm-OpenBSD-386.s b/src/libthread/asm-OpenBSD-386.s deleted file mode 100644 index 35e2ab6f..00000000 --- a/src/libthread/asm-OpenBSD-386.s +++ /dev/null @@ -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 -# diff --git a/src/libthread/asm-SunOS-sun4u.s b/src/libthread/asm-SunOS-sun4u.s deleted file mode 100644 index 3e95f02b..00000000 --- a/src/libthread/asm-SunOS-sun4u.s +++ /dev/null @@ -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 diff --git a/src/libthread/channel.c b/src/libthread/channel.c deleted file mode 100644 index b488dc97..00000000 --- a/src/libthread/channel.c +++ /dev/null @@ -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; inentry; 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; inentry; 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; inentry; 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; inentry; 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; -} diff --git a/src/libthread/chanprint.c b/src/libthread/chanprint.c deleted file mode 100644 index 781c6f6f..00000000 --- a/src/libthread/chanprint.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include - -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; -} diff --git a/src/libthread/create.c b/src/libthread/create.c deleted file mode 100644 index 4e6bc6de..00000000 --- a/src/libthread/create.c +++ /dev/null @@ -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--; -} diff --git a/src/libthread/debug.c b/src/libthread/debug.c deleted file mode 100644 index 14b47c00..00000000 --- a/src/libthread/debug.c +++ /dev/null @@ -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(); -} diff --git a/src/libthread/exec-unix.c b/src/libthread/exec-unix.c deleted file mode 100644 index e5848eaa..00000000 --- a/src/libthread/exec-unix.c +++ /dev/null @@ -1,147 +0,0 @@ -#include -#include -#include -#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); -} - diff --git a/src/libthread/exec.c b/src/libthread/exec.c new file mode 100644 index 00000000..2cbb4437 --- /dev/null +++ b/src/libthread/exec.c @@ -0,0 +1,153 @@ +#include "u.h" +#include +#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"); +} + diff --git a/src/libthread/execproc.ch b/src/libthread/execproc.ch deleted file mode 100644 index 4382be40..00000000 --- a/src/libthread/execproc.ch +++ /dev/null @@ -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) -{ -} - diff --git a/src/libthread/exit-getpid.ch b/src/libthread/exit-getpid.ch deleted file mode 100644 index e2580ac7..00000000 --- a/src/libthread/exit-getpid.ch +++ /dev/null @@ -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); -} diff --git a/src/libthread/exit.c b/src/libthread/exit.c deleted file mode 100644 index 69f3f738..00000000 --- a/src/libthread/exit.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#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; -} diff --git a/src/libthread/fdwait.c b/src/libthread/fdwait.c deleted file mode 100644 index d3983419..00000000 --- a/src/libthread/fdwait.c +++ /dev/null @@ -1,241 +0,0 @@ -#define NOPLAN9DEFINES -#include -#include -#include -#include "threadimpl.h" -#include -#include -#include - -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= 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; totthread->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) - abort(); - lock(&privlock); - privmask &= ~(1<thread->udata[i]; -} diff --git a/src/libthread/iocall.c b/src/libthread/iocall.c deleted file mode 100644 index e359c4d5..00000000 --- a/src/libthread/iocall.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include -#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; -} diff --git a/src/libthread/ioclose.c b/src/libthread/ioclose.c deleted file mode 100644 index fbaabb7c..00000000 --- a/src/libthread/ioclose.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/iodial.c b/src/libthread/iodial.c deleted file mode 100644 index 2e45cfe6..00000000 --- a/src/libthread/iodial.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/ioopen.c b/src/libthread/ioopen.c deleted file mode 100644 index 219e581e..00000000 --- a/src/libthread/ioopen.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include -#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); -} diff --git a/src/libthread/ioproc.c b/src/libthread/ioproc.c deleted file mode 100644 index 4e4c32a8..00000000 --- a/src/libthread/ioproc.c +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#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); -} diff --git a/src/libthread/ioproc.h b/src/libthread/ioproc.h deleted file mode 100644 index f3a488d3..00000000 --- a/src/libthread/ioproc.h +++ /dev/null @@ -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; -}; - diff --git a/src/libthread/ioread.c b/src/libthread/ioread.c deleted file mode 100644 index 62b1be03..00000000 --- a/src/libthread/ioread.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/ioreadn.c b/src/libthread/ioreadn.c deleted file mode 100644 index b843f603..00000000 --- a/src/libthread/ioreadn.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/iorw.c b/src/libthread/iorw.c new file mode 100644 index 00000000..2ad80878 --- /dev/null +++ b/src/libthread/iorw.c @@ -0,0 +1,178 @@ +#include +#include +#include +#include +#include +#include +#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); +} diff --git a/src/libthread/iosleep.c b/src/libthread/iosleep.c deleted file mode 100644 index 55756454..00000000 --- a/src/libthread/iosleep.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/iowrite.c b/src/libthread/iowrite.c deleted file mode 100644 index 593224c2..00000000 --- a/src/libthread/iowrite.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/kill.c b/src/libthread/kill.c deleted file mode 100644 index 648bd66e..00000000 --- a/src/libthread/kill.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#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; - } -} diff --git a/src/libthread/label.h b/src/libthread/label.h deleted file mode 100644 index 5081f48f..00000000 --- a/src/libthread/label.h +++ /dev/null @@ -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 -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 - - diff --git a/src/libthread/lib.c b/src/libthread/lib.c deleted file mode 100644 index 86e7506e..00000000 --- a/src/libthread/lib.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/main.c b/src/libthread/main.c deleted file mode 100644 index bc4efd27..00000000 --- a/src/libthread/main.c +++ /dev/null @@ -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; -} diff --git a/src/libthread/memset.c b/src/libthread/memset.c deleted file mode 100644 index dd74fb6c..00000000 --- a/src/libthread/memset.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "threadimpl.h" -#include - -void -_threadmemset(void *v, int c, int n) -{ - memset(v, c, n); -} diff --git a/src/libthread/memsetd.c b/src/libthread/memsetd.c deleted file mode 100644 index ef3f9605..00000000 --- a/src/libthread/memsetd.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "threadimpl.h" -#include - -void -_threaddebugmemset(void *v, int c, int n) -{ - memset(v, c, n); -} diff --git a/src/libthread/mkfile b/src/libthread/mkfile deleted file mode 100644 index 6492bb93..00000000 --- a/src/libthread/mkfile +++ /dev/null @@ -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 diff --git a/src/libthread/note.c b/src/libthread/note.c deleted file mode 100644 index ed40c08f..00000000 --- a/src/libthread/note.c +++ /dev/null @@ -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; ipending) - return; - - p->pending = 0; - for(n=notes; nproc == p){ - for(i=0; ipid || (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; ninuse)) - 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); -*/ -} - diff --git a/src/libthread/pid.c b/src/libthread/pid.c deleted file mode 100644 index bbc7dbbf..00000000 --- a/src/libthread/pid.c +++ /dev/null @@ -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; istk[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); -} - diff --git a/src/libthread/procstack.ch b/src/libthread/procstack.ch deleted file mode 100644 index ccf81866..00000000 --- a/src/libthread/procstack.ch +++ /dev/null @@ -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; -} - - diff --git a/src/libthread/proctab.c b/src/libthread/proctab.c deleted file mode 100644 index b8dd2097..00000000 --- a/src/libthread/proctab.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/proctab.ch b/src/libthread/proctab.ch deleted file mode 100644 index d51543f9..00000000 --- a/src/libthread/proctab.ch +++ /dev/null @@ -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; iprocid == 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; -} diff --git a/src/libthread/pthread.c b/src/libthread/pthread.c deleted file mode 100644 index 83d8b023..00000000 --- a/src/libthread/pthread.c +++ /dev/null @@ -1,271 +0,0 @@ -#include -#include -#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< -#include -#include -#include - -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; -} diff --git a/src/libthread/ref.c b/src/libthread/ref.c deleted file mode 100644 index a3b2cbae..00000000 --- a/src/libthread/ref.c +++ /dev/null @@ -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; -} diff --git a/src/libthread/sched.c b/src/libthread/sched.c deleted file mode 100644 index ac982da8..00000000 --- a/src/libthread/sched.c +++ /dev/null @@ -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); - } -} - diff --git a/src/libthread/setproc.c b/src/libthread/setproc.c deleted file mode 100644 index 5f1e2a8d..00000000 --- a/src/libthread/setproc.c +++ /dev/null @@ -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); -} diff --git a/src/libthread/sleep.c b/src/libthread/sleep.c deleted file mode 100644 index 4b0d82a1..00000000 --- a/src/libthread/sleep.c +++ /dev/null @@ -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); -} - diff --git a/src/libthread/sun4u.c b/src/libthread/sun4u.c deleted file mode 100644 index 0d2d8d24..00000000 --- a/src/libthread/sun4u.c +++ /dev/null @@ -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); -} - diff --git a/src/libthread/sysofiles.sh b/src/libthread/sysofiles.sh deleted file mode 100644 index 11b21814..00000000 --- a/src/libthread/sysofiles.sh +++ /dev/null @@ -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 diff --git a/src/libthread/test/pthreadloop.c b/src/libthread/test/pthreadloop.c new file mode 100644 index 00000000..73b600e7 --- /dev/null +++ b/src/libthread/test/pthreadloop.c @@ -0,0 +1,38 @@ +#include +#include +#include + +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(); + } + } +} diff --git a/src/libthread/test/tprimes.c b/src/libthread/test/tprimes.c new file mode 100644 index 00000000..91af5a73 --- /dev/null +++ b/src/libthread/test/tprimes.c @@ -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); +} diff --git a/src/libthread/test/tspawn.c b/src/libthread/test/tspawn.c new file mode 100644 index 00000000..ed4df3c4 --- /dev/null +++ b/src/libthread/test/tspawn.c @@ -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); +} diff --git a/src/libthread/test/tspawnloop.c b/src/libthread/test/tspawnloop.c new file mode 100644 index 00000000..8835267f --- /dev/null +++ b/src/libthread/test/tspawnloop.c @@ -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"); + } +} diff --git a/src/libthread/texec.c b/src/libthread/texec.c deleted file mode 100644 index c9682e35..00000000 --- a/src/libthread/texec.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -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); -} diff --git a/src/libthread/tfork.c b/src/libthread/tfork.c deleted file mode 100644 index 0cbb4be9..00000000 --- a/src/libthread/tfork.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -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); - } -} diff --git a/src/libthread/thread.c b/src/libthread/thread.c new file mode 100644 index 00000000..69895181 --- /dev/null +++ b/src/libthread/thread.c @@ -0,0 +1,535 @@ +#include "u.h" +#include +#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 */ +} diff --git a/src/libthread/thread.sh b/src/libthread/thread.sh deleted file mode 100644 index 818b509f..00000000 --- a/src/libthread/thread.sh +++ /dev/null @@ -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 diff --git a/src/libthread/threadimpl.h b/src/libthread/threadimpl.h deleted file mode 100644 index 0ad4568e..00000000 --- a/src/libthread/threadimpl.h +++ /dev/null @@ -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 -#include -#include -#include -#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); diff --git a/src/libthread/tprimes.c b/src/libthread/tprimes.c deleted file mode 100644 index 89d30c03..00000000 --- a/src/libthread/tprimes.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include - -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); -} diff --git a/src/libthread/trend.c b/src/libthread/trend.c deleted file mode 100644 index 1ccf1a79..00000000 --- a/src/libthread/trend.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -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])); -} diff --git a/src/libthread/tsignal.c b/src/libthread/tsignal.c deleted file mode 100644 index 9c64c46b..00000000 --- a/src/libthread/tsignal.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -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); -} diff --git a/src/libthread/tspawn.c b/src/libthread/tspawn.c deleted file mode 100644 index 97962c5d..00000000 --- a/src/libthread/tspawn.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -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); -} diff --git a/src/libthread/ucontext.c b/src/libthread/ucontext.c deleted file mode 100644 index 98e92ccf..00000000 --- a/src/libthread/ucontext.c +++ /dev/null @@ -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"); -} - -- cgit v1.2.3