aboutsummaryrefslogtreecommitdiff
path: root/src/libthread
diff options
context:
space:
mode:
Diffstat (limited to 'src/libthread')
-rw-r--r--src/libthread/386-ucontext.c (renamed from src/libthread/OpenBSD-386.c)2
-rw-r--r--src/libthread/BSD.c403
-rw-r--r--src/libthread/COPYRIGHT6
-rw-r--r--src/libthread/Darwin-386-asm.s52
-rw-r--r--src/libthread/Darwin-386.c30
-rw-r--r--src/libthread/Darwin-power-asm.s83
-rw-r--r--src/libthread/Darwin-x86_64-swapcontext.c30
-rw-r--r--src/libthread/FreeBSD-386-asm.s52
-rw-r--r--src/libthread/FreeBSD.c34
-rw-r--r--src/libthread/Linux-386-asm.s7
-rw-r--r--src/libthread/Linux-arm-asm.s20
-rw-r--r--src/libthread/Linux-arm-context.s41
-rw-r--r--src/libthread/Linux-power-asm.s16
-rw-r--r--src/libthread/Linux-sparc64-asm.s16
-rw-r--r--src/libthread/Linux.c462
-rw-r--r--src/libthread/NetBSD.c438
-rw-r--r--src/libthread/OpenBSD-386-asm.s46
-rw-r--r--src/libthread/OpenBSD-power-asm.S15
-rw-r--r--src/libthread/OpenBSD-power.c24
-rw-r--r--src/libthread/OpenBSD.c145
-rw-r--r--src/libthread/README.Linux40
-rw-r--r--src/libthread/arm-ucontext.c (renamed from src/libthread/Linux-arm-swapcontext.c)2
-rw-r--r--src/libthread/mkfile11
-rw-r--r--src/libthread/power-ucontext.c (renamed from src/libthread/Darwin-power.c)6
-rw-r--r--src/libthread/sparc-ucontext.h23
-rw-r--r--src/libthread/sparc64-ucontext.c (renamed from src/libthread/Linux-sparc64-swapcontext.c)0
-rw-r--r--src/libthread/stkmalloc.c13
-rw-r--r--src/libthread/stkmmap.c25
-rw-r--r--src/libthread/sysofiles.sh45
-rw-r--r--src/libthread/thread.c23
-rw-r--r--src/libthread/threadimpl.h28
-rw-r--r--src/libthread/x86_64-ucontext.c (renamed from src/libthread/OpenBSD-x86_64.c)4
32 files changed, 578 insertions, 1564 deletions
diff --git a/src/libthread/OpenBSD-386.c b/src/libthread/386-ucontext.c
index 89bfedcd..3afa9513 100644
--- a/src/libthread/OpenBSD-386.c
+++ b/src/libthread/386-ucontext.c
@@ -5,7 +5,7 @@ makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
{
int *sp;
- sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4;
+ sp = USPALIGN(ucp, 4);
sp -= argc;
memmove(sp, &argc+1, argc*sizeof(int));
*--sp = 0; /* return address */
diff --git a/src/libthread/BSD.c b/src/libthread/BSD.c
deleted file mode 100644
index 737c0a63..00000000
--- a/src/libthread/BSD.c
+++ /dev/null
@@ -1,403 +0,0 @@
-#undef exits
-#undef _exits
-
-extern int __isthreaded;
-
-/*
- * spin locks
- */
-extern int _tas(int*);
-
-void
-_threadunlock(Lock *l, ulong pc)
-{
- USED(pc);
-
- l->held = 0;
-}
-
-int
-_threadlock(Lock *l, int block, ulong pc)
-{
- int i;
-
- USED(pc);
-
- /* once fast */
- if(!_tas(&l->held))
- return 1;
- if(!block)
- return 0;
-
- /* a thousand times pretty fast */
- for(i=0; i<1000; i++){
- if(!_tas(&l->held))
- return 1;
- sleep(0);
- }
- /* increasingly slow */
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(1);
- }
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(10);
- }
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(100);
- }
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(1000);
- }
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(10*1000);
- }
- /* now nice and slow */
- for(i=0; i<1000; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(100*1000);
- }
- /* take your time */
- while(_tas(&l->held))
- usleep(1000*1000);
- return 1;
-}
-
-/*
- * For libc.
- */
-
-typedef struct {
- volatile long access_lock;
- volatile long lock_owner;
- volatile char *fname;
- volatile int lineno;
-} spinlock_t;
-
-void
-_spinlock(spinlock_t *lk)
-{
- lock((Lock*)&lk->access_lock);
-}
-
-void
-_spinunlock(spinlock_t *lk)
-{
- unlock((Lock*)&lk->access_lock);
-}
-
-
-
-/*
- * sleep and wakeup
- */
-static void
-ign(int x)
-{
- USED(x);
-}
-
-static void /*__attribute__((constructor))*/
-ignusr1(int restart)
-{
- struct sigaction sa;
-
- memset(&sa, 0, sizeof sa);
- sa.sa_handler = ign;
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGUSR1);
- if(restart)
- sa.sa_flags = SA_RESTART;
- sigaction(SIGUSR1, &sa, nil);
-}
-
-void
-_procsleep(_Procrendez *r)
-{
- sigset_t mask;
-
- /*
- * Go to sleep.
- *
- * Block USR1, set the handler to interrupt system calls,
- * unlock the vouslock so our waker can wake us,
- * and then suspend.
- */
-again:
- r->asleep = 1;
- r->pid = getpid();
-
- sigprocmask(SIG_SETMASK, nil, &mask);
- sigaddset(&mask, SIGUSR1);
- sigprocmask(SIG_SETMASK, &mask, nil);
- ignusr1(0);
- unlock(r->l);
- sigdelset(&mask, SIGUSR1);
- sigsuspend(&mask);
-
- /*
- * We're awake. Make USR1 not interrupt system calls.
- */
- lock(r->l);
- ignusr1(1);
- if(r->asleep && r->pid == getpid()){
- /* Didn't really wake up - signal from something else */
- goto again;
- }
-}
-
-void
-_procwakeup(_Procrendez *r)
-{
- if(r->asleep){
- r->asleep = 0;
- assert(r->pid >= 1);
- kill(r->pid, SIGUSR1);
- }
-}
-
-void
-_procwakeupandunlock(_Procrendez *r)
-{
- _procwakeup(r);
- unlock(r->l);
-}
-
-
-/*
- * process creation and exit
- */
-typedef struct Stackfree Stackfree;
-struct Stackfree
-{
- Stackfree *next;
- int pid;
-};
-static Lock stacklock;
-static Stackfree *stackfree;
-
-static void
-delayfreestack(uchar *stk)
-{
- Stackfree *sf;
-
- sf = (Stackfree*)stk;
- sf->pid = getpid();
- lock(&stacklock);
- sf->next = stackfree;
- stackfree = sf;
- unlock(&stacklock);
-}
-
-static void
-dofreestacks(void)
-{
- Stackfree *sf, *last, *next;
-
- if(stackfree==nil || !canlock(&stacklock))
- return;
-
- for(last=nil,sf=stackfree; sf; last=sf,sf=next){
- next = sf->next;
- if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){
- free(sf);
- if(last)
- last->next = next;
- else
- stackfree = next;
- sf = last;
- }
- }
- unlock(&stacklock);
-}
-
-static int
-startprocfn(void *v)
-{
- void **a;
- uchar *stk;
- void (*fn)(void*);
- Proc *p;
-
- a = (void**)v;
- fn = a[0];
- p = a[1];
- stk = a[2];
- free(a);
- p->osprocid = getpid();
-
- (*fn)(p);
-
- delayfreestack(stk);
- _exit(0);
- return 0;
-}
-
-void
-_procstart(Proc *p, void (*fn)(Proc*))
-{
- void **a;
- uchar *stk;
- int pid;
-
- dofreestacks();
- a = malloc(3*sizeof a[0]);
- if(a == nil)
- sysfatal("_procstart malloc: %r");
- stk = malloc(65536);
- if(stk == nil)
- sysfatal("_procstart malloc stack: %r");
-
- a[0] = fn;
- a[1] = p;
- a[2] = stk;
-
- pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, stk+65536-64, startprocfn, a);
- if(pid < 0){
- fprint(2, "_procstart rfork_thread: %r\n");
- abort();
- }
-}
-
-static char *threadexitsmsg;
-void
-sigusr2handler(int s)
-{
-/* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
- if(threadexitsmsg)
- _exits(threadexitsmsg);
-}
-
-void
-threadexitsall(char *msg)
-{
- static int pid[1024];
- int i, npid, mypid;
- Proc *p;
-
- if(msg == nil)
- msg = "";
-
- /*
- * Only one guy, ever, gets to run this.
- * If two guys do it, inevitably they end up
- * tripping over each other in the underlying
- * C library exit() implementation, which is
- * trying to run the atexit handlers and apparently
- * not thread safe. This has been observed on
- * both Linux and OpenBSD. Sigh.
- */
- {
- static Lock onelock;
- if(!canlock(&onelock))
- _exits(threadexitsmsg);
- threadexitsmsg = msg;
- }
-
- if(msg == nil)
- msg = "";
- mypid = getpid();
- lock(&_threadprocslock);
- threadexitsmsg = msg;
- npid = 0;
- for(p=_threadprocs; p; p=p->next)
- if(p->osprocid != mypid && p->osprocid >= 1)
- pid[npid++] = p->osprocid;
- for(i=0; i<npid; i++)
- kill(pid[i], SIGUSR2);
- unlock(&_threadprocslock);
- exits(msg);
-}
-
-/*
- * per-process data, indexed by pid
- */
-typedef struct Perproc Perproc;
-struct Perproc
-{
- int pid;
- Proc *proc;
-};
-
-static Lock perlock;
-static Perproc perproc[1024];
-#define P ((Proc*)-1)
-
-static Perproc*
-myperproc(void)
-{
- int i, pid, h;
- Perproc *p;
-
- pid = getpid();
- h = pid%nelem(perproc);
- for(i=0; i<nelem(perproc); i++){
- p = &perproc[(i+h)%nelem(perproc)];
- if(p->pid == pid)
- return p;
- if(p->pid == 0){
- print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
- break;
- }
- }
- fprint(2, "myperproc %d: cannot find self\n", pid);
- abort();
- return nil;
-}
-
-static Perproc*
-newperproc(void)
-{
- int i, pid, h;
- Perproc *p;
-
- lock(&perlock);
- pid = getpid();
- h = pid%nelem(perproc);
- for(i=0; i<nelem(perproc); i++){
- p = &perproc[(i+h)%nelem(perproc)];
- if(p->pid == pid || p->pid == -1 || p->pid == 0){
- p->pid = pid;
- unlock(&perlock);
- return p;
- }
- }
- fprint(2, "newperproc %d: out of procs\n", pid);
- abort();
- return nil;
-}
-
-Proc*
-_threadproc(void)
-{
- return myperproc()->proc;
-}
-
-void
-_threadsetproc(Proc *p)
-{
- Perproc *pp;
-
- if(p)
- p->osprocid = getpid();
- pp = newperproc();
- pp->proc = p;
- if(p == nil)
- pp->pid = -1;
-}
-
-void
-_threadpexit(void)
-{
- _exit(0);
-}
diff --git a/src/libthread/COPYRIGHT b/src/libthread/COPYRIGHT
index f4ee354e..d0820965 100644
--- a/src/libthread/COPYRIGHT
+++ b/src/libthread/COPYRIGHT
@@ -45,9 +45,9 @@ Contains parts of an earlier library that has:
===
-The above notices do *NOT* apply to Linux-sparc64-context.S
-or to Linux-sparc64-swapcontext.c. Those are functions from
+The above notices do *NOT* apply to Linux-sparc64-context.S
+or to sparc64-ucontext.c. Those are functions from
the GNU C library and are provided for systems that use the GNU C
-library but somehow are missing those functions. They are
+library but somehow are missing those functions. They are
distributed under the Lesser GPL; see COPYING.SPARC64-CONTEXT.
diff --git a/src/libthread/Darwin-386-asm.s b/src/libthread/Darwin-386-asm.s
deleted file mode 100644
index 46c96e94..00000000
--- a/src/libthread/Darwin-386-asm.s
+++ /dev/null
@@ -1,52 +0,0 @@
-.globl _tas
-_tas:
- movl $0xCAFEBABE, %eax
- movl 4(%esp), %ecx
- xchgl %eax, 0(%ecx)
- ret
-
-.globl _getmcontext
-_getmcontext:
- movl 4(%esp), %eax
-
- movl %fs, 8(%eax)
- movl %es, 12(%eax)
- movl %ds, 16(%eax)
- movl %ss, 76(%eax)
- movl %edi, 20(%eax)
- movl %esi, 24(%eax)
- movl %ebp, 28(%eax)
- movl %ebx, 36(%eax)
- movl %edx, 40(%eax)
- movl %ecx, 44(%eax)
-
- movl $1, 48(%eax) /* %eax */
- movl (%esp), %ecx /* %eip */
- movl %ecx, 60(%eax)
- leal 4(%esp), %ecx /* %esp */
- movl %ecx, 72(%eax)
-
- movl 44(%eax), %ecx /* restore %ecx */
- movl $0, %eax
- ret
-
-.globl _setmcontext
-_setmcontext:
- movl 4(%esp), %eax
-
- movl 8(%eax), %fs
- movl 12(%eax), %es
- movl 16(%eax), %ds
- movl 76(%eax), %ss
- movl 20(%eax), %edi
- movl 24(%eax), %esi
- movl 28(%eax), %ebp
- movl 36(%eax), %ebx
- movl 40(%eax), %edx
- movl 44(%eax), %ecx
-
- movl 72(%eax), %esp
- pushl 60(%eax) /* new %eip */
- movl 48(%eax), %eax
- ret
-
diff --git a/src/libthread/Darwin-386.c b/src/libthread/Darwin-386.c
deleted file mode 100644
index b138e420..00000000
--- a/src/libthread/Darwin-386.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "threadimpl.h"
-
-void
-makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
-{
- int *sp;
-
- sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4;
- sp -= argc;
- /*
- * Stack pointer at call instruction (before return address
- * gets pushed) must be 16-byte aligned.
- */
- if((uintptr)sp%4)
- abort();
- while((uintptr)sp%16)
- sp--;
- memmove(sp, &argc+1, argc*sizeof(int));
- *--sp = 0; /* return address */
- ucp->uc_mcontext.mc_eip = (long)func;
- ucp->uc_mcontext.mc_esp = (int)sp;
-}
-
-int
-swapcontext(ucontext_t *oucp, ucontext_t *ucp)
-{
- if(getcontext(oucp) == 0)
- setcontext(ucp);
- return 0;
-}
diff --git a/src/libthread/Darwin-power-asm.s b/src/libthread/Darwin-power-asm.s
deleted file mode 100644
index a064b5ea..00000000
--- a/src/libthread/Darwin-power-asm.s
+++ /dev/null
@@ -1,83 +0,0 @@
-/* get FPR and VR use flags with sc 0x7FF3 */
-/* get vsave with mfspr reg, 256 */
-
-.text
-.align 2
-
-.globl __getmcontext
-
-__getmcontext: /* xxx: instruction scheduling */
- mflr r0
- mfcr r5
- mfctr r6
- mfxer r7
- stw r0, 0*4(r3)
- stw r5, 1*4(r3)
- stw r6, 2*4(r3)
- stw r7, 3*4(r3)
-
- stw r1, 4*4(r3)
- stw r2, 5*4(r3)
- li r5, 1 /* return value for setmcontext */
- stw r5, 6*4(r3)
-
- stw r13, (0+7)*4(r3) /* callee-save GPRs */
- stw r14, (1+7)*4(r3) /* xxx: block move */
- stw r15, (2+7)*4(r3)
- stw r16, (3+7)*4(r3)
- stw r17, (4+7)*4(r3)
- stw r18, (5+7)*4(r3)
- stw r19, (6+7)*4(r3)
- stw r20, (7+7)*4(r3)
- stw r21, (8+7)*4(r3)
- stw r22, (9+7)*4(r3)
- stw r23, (10+7)*4(r3)
- stw r24, (11+7)*4(r3)
- stw r25, (12+7)*4(r3)
- stw r26, (13+7)*4(r3)
- stw r27, (14+7)*4(r3)
- stw r28, (15+7)*4(r3)
- stw r29, (16+7)*4(r3)
- stw r30, (17+7)*4(r3)
- stw r31, (18+7)*4(r3)
-
- li r3, 0 /* return */
- blr
-
-.globl __setmcontext
-
-__setmcontext:
- lwz r13, (0+7)*4(r3) /* callee-save GPRs */
- lwz r14, (1+7)*4(r3) /* xxx: block move */
- lwz r15, (2+7)*4(r3)
- lwz r16, (3+7)*4(r3)
- lwz r17, (4+7)*4(r3)
- lwz r18, (5+7)*4(r3)
- lwz r19, (6+7)*4(r3)
- lwz r20, (7+7)*4(r3)
- lwz r21, (8+7)*4(r3)
- lwz r22, (9+7)*4(r3)
- lwz r23, (10+7)*4(r3)
- lwz r24, (11+7)*4(r3)
- lwz r25, (12+7)*4(r3)
- lwz r26, (13+7)*4(r3)
- lwz r27, (14+7)*4(r3)
- lwz r28, (15+7)*4(r3)
- lwz r29, (16+7)*4(r3)
- lwz r30, (17+7)*4(r3)
- lwz r31, (18+7)*4(r3)
-
- lwz r1, 4*4(r3)
- lwz r2, 5*4(r3)
-
- lwz r0, 0*4(r3)
- mtlr r0
- lwz r0, 1*4(r3)
- mtcr r0 /* mtcrf 0xFF, r0 */
- lwz r0, 2*4(r3)
- mtctr r0
- lwz r0, 3*4(r3)
- mtxer r0
-
- lwz r3, 6*4(r3)
- blr
diff --git a/src/libthread/Darwin-x86_64-swapcontext.c b/src/libthread/Darwin-x86_64-swapcontext.c
deleted file mode 100644
index 27931456..00000000
--- a/src/libthread/Darwin-x86_64-swapcontext.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "threadimpl.h"
-
-void
-makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
-{
- uintptr *sp;
- va_list arg;
-
-//fprint(2, "makecontext %d\n", argc);
- if(argc != 2)
- sysfatal("libthread: makecontext misused");
- va_start(arg, argc);
- uc->mc.di = va_arg(arg, uint);
- uc->mc.si = va_arg(arg, uint);
-//fprint(2, "%ux %ux\n", uc->mc.di, uc->mc.si);
- va_end(arg);
-
- sp = (uintptr*)((char*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size);
- *--sp = 0; // fn's return address
- *--sp = (uintptr)fn; // return address of setcontext
- uc->mc.sp = (uintptr)sp;
-}
-
-int
-swapcontext(ucontext_t *oucp, ucontext_t *ucp)
-{
- if(getcontext(oucp) == 0)
- setcontext(ucp);
- return 0;
-}
diff --git a/src/libthread/FreeBSD-386-asm.s b/src/libthread/FreeBSD-386-asm.s
deleted file mode 100644
index 42169853..00000000
--- a/src/libthread/FreeBSD-386-asm.s
+++ /dev/null
@@ -1,52 +0,0 @@
-.globl _tas
-_tas:
- movl $0xCAFEBABE, %eax
- movl 4(%esp), %ecx
- xchgl %eax, 0(%ecx)
- ret
-
-.globl getmcontext
-getmcontext:
- movl 4(%esp), %eax
-
- movl %fs, 8(%eax)
- movl %es, 12(%eax)
- movl %ds, 16(%eax)
- movl %ss, 76(%eax)
- movl %edi, 20(%eax)
- movl %esi, 24(%eax)
- movl %ebp, 28(%eax)
- movl %ebx, 36(%eax)
- movl %edx, 40(%eax)
- movl %ecx, 44(%eax)
-
- movl $1, 48(%eax) /* %eax */
- movl (%esp), %ecx /* %eip */
- movl %ecx, 60(%eax)
- leal 4(%esp), %ecx /* %esp */
- movl %ecx, 72(%eax)
-
- movl 44(%eax), %ecx /* restore %ecx */
- movl $0, %eax
- ret
-
-.globl setmcontext
-setmcontext:
- movl 4(%esp), %eax
-
- movl 8(%eax), %fs
- movl 12(%eax), %es
- movl 16(%eax), %ds
- movl 76(%eax), %ss
- movl 20(%eax), %edi
- movl 24(%eax), %esi
- movl 28(%eax), %ebp
- movl 36(%eax), %ebx
- movl 40(%eax), %edx
- movl 44(%eax), %ecx
-
- movl 72(%eax), %esp
- pushl 60(%eax) /* new %eip */
- movl 48(%eax), %eax
- ret
-
diff --git a/src/libthread/FreeBSD.c b/src/libthread/FreeBSD.c
deleted file mode 100644
index 5c282465..00000000
--- a/src/libthread/FreeBSD.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "threadimpl.h"
-
-#include "BSD.c"
-
-/*
- * FreeBSD 4 and earlier needs the context functions.
- */
-void
-makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
-{
- int *sp;
-
- sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4;
- sp -= argc;
- memmove(sp, &argc+1, argc*sizeof(int));
- *--sp = 0; /* return address */
- ucp->uc_mcontext.mc_eip = (long)func;
- ucp->uc_mcontext.mc_esp = (int)sp;
-}
-
-int
-swapcontext(ucontext_t *oucp, ucontext_t *ucp)
-{
- if(getcontext(oucp) == 0)
- setcontext(ucp);
- return 0;
-}
-
-void
-_pthreadinit(void)
-{
- __isthreaded = 1;
- signal(SIGUSR2, sigusr2handler);
-}
diff --git a/src/libthread/Linux-386-asm.s b/src/libthread/Linux-386-asm.s
deleted file mode 100644
index 197f12b5..00000000
--- a/src/libthread/Linux-386-asm.s
+++ /dev/null
@@ -1,7 +0,0 @@
-.globl _tas
-_tas:
- movl $0xCAFEBABE, %eax
- movl 4(%esp), %ecx
- xchgl %eax, 0(%ecx)
- ret
-
diff --git a/src/libthread/Linux-arm-asm.s b/src/libthread/Linux-arm-asm.s
index 5a285bf2..9bd54f8a 100644
--- a/src/libthread/Linux-arm-asm.s
+++ b/src/libthread/Linux-arm-asm.s
@@ -1,16 +1,5 @@
-
-.globl _tas
-_tas:
- mov r3, #0xCA000000
- add r3, r3, #0xFE0000
- add r3, r3, #0xBA00
- add r3, r3, #0xBE
- swp r3, r3, [r0]
- mov r0, r3
- mov pc, lr
-
-.globl getmcontext
-getmcontext:
+.globl mygetmcontext
+mygetmcontext:
str r1, [r0,#4]
str r2, [r0,#8]
str r3, [r0,#12]
@@ -32,8 +21,8 @@ getmcontext:
mov r0, #0
mov pc, lr
-.globl setmcontext
-setmcontext:
+.globl mysetmcontext
+mysetmcontext:
ldr r1, [r0,#4]
ldr r2, [r0,#8]
ldr r3, [r0,#12]
@@ -50,4 +39,3 @@ setmcontext:
ldr r14, [r0,#56]
ldr r0, [r0]
mov pc, lr
-
diff --git a/src/libthread/Linux-arm-context.s b/src/libthread/Linux-arm-context.s
deleted file mode 100644
index 9bd54f8a..00000000
--- a/src/libthread/Linux-arm-context.s
+++ /dev/null
@@ -1,41 +0,0 @@
-.globl mygetmcontext
-mygetmcontext:
- str r1, [r0,#4]
- str r2, [r0,#8]
- str r3, [r0,#12]
- str r4, [r0,#16]
- str r5, [r0,#20]
- str r6, [r0,#24]
- str r7, [r0,#28]
- str r8, [r0,#32]
- str r9, [r0,#36]
- str r10, [r0,#40]
- str r11, [r0,#44]
- str r12, [r0,#48]
- str r13, [r0,#52]
- str r14, [r0,#56]
- /* store 1 as r0-to-restore */
- mov r1, #1
- str r1, [r0]
- /* return 0 */
- mov r0, #0
- mov pc, lr
-
-.globl mysetmcontext
-mysetmcontext:
- ldr r1, [r0,#4]
- ldr r2, [r0,#8]
- ldr r3, [r0,#12]
- ldr r4, [r0,#16]
- ldr r5, [r0,#20]
- ldr r6, [r0,#24]
- ldr r7, [r0,#28]
- ldr r8, [r0,#32]
- ldr r9, [r0,#36]
- ldr r10, [r0,#40]
- ldr r11, [r0,#44]
- ldr r12, [r0,#48]
- ldr r13, [r0,#52]
- ldr r14, [r0,#56]
- ldr r0, [r0]
- mov pc, lr
diff --git a/src/libthread/Linux-power-asm.s b/src/libthread/Linux-power-asm.s
deleted file mode 100644
index d6e21c15..00000000
--- a/src/libthread/Linux-power-asm.s
+++ /dev/null
@@ -1,16 +0,0 @@
- .globl _tas
-_tas:
- li %r0, 0
- mr %r4, %r3
- lis %r5, 0xcafe
- ori %r5, %r5, 0xbabe
-1:
- lwarx %r3, %r0, %r4
- cmpwi %r3, 0
- bne 2f
- stwcx. %r5, %r0, %r4
- bne- 1b
-2:
- sync
- blr
-
diff --git a/src/libthread/Linux-sparc64-asm.s b/src/libthread/Linux-sparc64-asm.s
deleted file mode 100644
index 422a1b24..00000000
--- a/src/libthread/Linux-sparc64-asm.s
+++ /dev/null
@@ -1,16 +0,0 @@
-! Actually sparc32 assembly.
-! Debian's sparc64 port is a 32-bit user space.
-
- .section ".text", #alloc, #execinstr
- .align 8
- .skip 16
- .global _tas
-! .type _tas,2
-_tas:
- or %g0,1,%o1
- swap [%o0],%o1 ! o0 points to lock; key is first word
- retl
- mov %o1, %o0
-
- .size _tas,(.-_tas)
-
diff --git a/src/libthread/Linux.c b/src/libthread/Linux.c
deleted file mode 100644
index 31577e87..00000000
--- a/src/libthread/Linux.c
+++ /dev/null
@@ -1,462 +0,0 @@
-#include "threadimpl.h"
-
-#undef exits
-#undef _exits
-
-static int
-timefmt(Fmt *fmt)
-{
- static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
- vlong ns;
- Tm tm;
- ns = nsec();
- tm = *localtime(time(0));
- return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
- mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
- (int)(ns%1000000000)/1000000);
-}
-
-/*
- * spin locks
- */
-extern int _tas(int*);
-
-void
-_threadunlock(Lock *l, ulong pc)
-{
- USED(pc);
-
- l->held = 0;
-}
-
-int
-_threadlock(Lock *l, int block, ulong pc)
-{
- int i;
-static int first=1;
-if(first) {first=0; fmtinstall('\001', timefmt);}
-
- USED(pc);
-
- /* once fast */
- if(!_tas(&l->held))
- return 1;
- if(!block)
- return 0;
-
- /* a thousand times pretty fast */
- for(i=0; i<1000; i++){
- if(!_tas(&l->held))
- return 1;
- sched_yield();
- }
- /* now increasingly slow */
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(1);
- }
-fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc);
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(10);
- }
-fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc);
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(100);
- }
-fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc);
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(1000);
- }
-fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc);
- for(i=0; i<10; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(10*1000);
- }
-fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc);
- for(i=0; i<1000; i++){
- if(!_tas(&l->held))
- return 1;
- usleep(100*1000);
- }
-fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc);
- /* take your time */
- while(_tas(&l->held))
- usleep(1000*1000);
- return 1;
-}
-
-/*
- * sleep and wakeup
- */
-static void
-ign(int x)
-{
- USED(x);
-}
-
-static void /*__attribute__((constructor))*/
-ignusr1(int restart)
-{
- struct sigaction sa;
-
- memset(&sa, 0, sizeof sa);
- sa.sa_handler = ign;
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGUSR1);
- if(restart)
- sa.sa_flags = SA_RESTART;
- sigaction(SIGUSR1, &sa, nil);
-}
-
-void
-_procsleep(_Procrendez *r)
-{
- sigset_t mask;
-
- /*
- * Go to sleep.
- *
- * Block USR1, set the handler to interrupt system calls,
- * unlock the vouslock so our waker can wake us,
- * and then suspend.
- */
-again:
- r->asleep = 1;
- r->pid = getpid();
-
- sigprocmask(SIG_SETMASK, nil, &mask);
- sigaddset(&mask, SIGUSR1);
- sigprocmask(SIG_SETMASK, &mask, nil);
- ignusr1(0);
- unlock(r->l);
- sigdelset(&mask, SIGUSR1);
- sigsuspend(&mask);
-
- /*
- * We're awake. Make USR1 not interrupt system calls.
- */
- lock(r->l);
- ignusr1(1);
- if(r->asleep && r->pid == getpid()){
- /* Didn't really wake up - signal from something else */
- goto again;
- }
-}
-
-void
-_procwakeupandunlock(_Procrendez *r)
-{
- int pid;
-
- pid = 0;
- if(r->asleep){
- r->asleep = 0;
- assert(r->pid >= 1);
- pid = r->pid;
- }
- assert(r->l);
- unlock(r->l);
- if(pid)
- kill(pid, SIGUSR1);
-}
-
-/*
- * process creation and exit
- */
-typedef struct Stackfree Stackfree;
-struct Stackfree
-{
- Stackfree *next;
- int pid;
- int pid1;
-};
-static Lock stacklock;
-static Stackfree *stackfree;
-
-static void
-delayfreestack(uchar *stk, int pid, int pid1)
-{
- Stackfree *sf;
-
- sf = (Stackfree*)stk;
- sf->pid = pid;
- sf->pid1 = pid1;
- lock(&stacklock);
- sf->next = stackfree;
- stackfree = sf;
- unlock(&stacklock);
-}
-
-static void
-dofreestacks(void)
-{
- Stackfree *sf, *last, *next;
-
- if(stackfree==nil || !canlock(&stacklock))
- return;
-
- for(last=nil,sf=stackfree; sf; last=sf,sf=next){
- next = sf->next;
- if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH)
- if(sf->pid1 >= 1 && kill(sf->pid1, 0) < 0 && errno == ESRCH){
- free(sf);
- if(last)
- last->next = next;
- else
- stackfree = next;
- sf = last;
- }
- }
- unlock(&stacklock);
-}
-
-static int
-startprocfn(void *v)
-{
- void **a;
- uchar *stk;
- void (*fn)(void*);
- Proc *p;
- int pid0, pid1;
-
- a = (void**)v;
- fn = a[0];
- p = a[1];
- stk = a[2];
- pid0 = (int)a[4];
- pid1 = getpid();
- free(a);
- p->osprocid = pid1;
-
- (*fn)(p);
-
- delayfreestack(stk, pid0, pid1);
- _exit(0);
- return 0;
-}
-
-/*
- * indirect through here so that parent need not wait for child zombie
- *
- * slight race - if child exits and then another process starts before we
- * manage to exit, we'll be running on a freed stack.
- */
-static int
-trampnowait(void *v)
-{
- void **a;
- int *kidpid;
-
- a = (void*)v;
- kidpid = a[3];
- a[4] = (void*)getpid();
- *kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
- _exit(0);
- return 0;
-}
-
-void
-_procstart(Proc *p, void (*fn)(Proc*))
-{
- void **a;
- uchar *stk;
- int pid, kidpid, status;
-
- dofreestacks();
- a = malloc(5*sizeof a[0]);
- if(a == nil)
- sysfatal("_procstart malloc: %r");
- stk = malloc(65536);
- if(stk == nil)
- sysfatal("_procstart malloc stack: %r");
-
- a[0] = fn;
- a[1] = p;
- a[2] = stk;
- a[3] = &kidpid;
- kidpid = -1;
-
- pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
- if(pid > 0)
- if(wait4(pid, &status, __WALL, 0) < 0)
- fprint(2, "ffork wait4: %r\n");
- if(pid < 0 || kidpid < 0){
- fprint(2, "_procstart clone: %r\n");
- abort();
- }
-}
-
-static char *threadexitsmsg;
-void
-sigusr2handler(int s)
-{
-/* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
- if(threadexitsmsg)
- _exits(threadexitsmsg);
-}
-
-void
-threadexitsall(char *msg)
-{
- static int pid[1024];
- int i, npid, mypid;
- Proc *p;
-
- if(msg == nil)
- msg = "";
-
- /*
- * Only one guy, ever, gets to run this.
- * If two guys do it, inevitably they end up
- * tripping over each other in the underlying
- * C library exit() implementation, which is
- * trying to run the atexit handlers and apparently
- * not thread safe. This has been observed on
- * both Linux and OpenBSD. Sigh.
- */
- {
- static Lock onelock;
- if(!canlock(&onelock))
- _exits(threadexitsmsg);
- threadexitsmsg = msg;
- }
-
- mypid = getpid();
- lock(&_threadprocslock);
- npid = 0;
- for(p=_threadprocs; p; p=p->next)
- if(p->osprocid != mypid && p->osprocid >= 1)
- pid[npid++] = p->osprocid;
- for(i=0; i<npid; i++)
- kill(pid[i], SIGUSR2);
- unlock(&_threadprocslock);
- exits(msg);
-}
-
-/*
- * per-process data, indexed by pid
- *
- * could use modify_ldt and a segment register
- * to avoid the many calls to getpid(), but i don't
- * care -- this is compatibility code. linux 2.6 with
- * nptl is a good enough pthreads to avoid this whole file.
- */
-typedef struct Perproc Perproc;
-struct Perproc
-{
- int pid;
- Proc *proc;
-};
-
-static Lock perlock;
-static Perproc perproc[1024];
-#define P ((Proc*)-1)
-
-static Perproc*
-myperproc(void)
-{
- int i, pid, h;
- Perproc *p;
-
- pid = getpid();
- h = pid%nelem(perproc);
- for(i=0; i<nelem(perproc); i++){
- p = &perproc[(i+h)%nelem(perproc)];
- if(p->pid == pid)
- return p;
- if(p->pid == 0){
- print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
- break;
- }
- }
- fprint(2, "myperproc %d (%s): cannot find self\n", pid, argv0);
- abort();
- return nil;
-}
-
-static Perproc*
-newperproc(void)
-{
- int i, pid, h;
- Perproc *p;
-
- lock(&perlock);
- pid = getpid();
- h = pid%nelem(perproc);
- for(i=0; i<nelem(perproc); i++){
- p = &perproc[(i+h)%nelem(perproc)];
- if(p->pid == pid || p->pid == -1 || p->pid == 0){
- p->pid = pid;
- unlock(&perlock);
- return p;
- }
- }
- fprint(2, "newperproc %d: out of procs\n", pid);
- abort();
- return nil;
-}
-
-Proc*
-_threadproc(void)
-{
- return myperproc()->proc;
-}
-
-void
-_threadsetproc(Proc *p)
-{
- Perproc *pp;
-
- if(p)
- p->osprocid = getpid();
- pp = newperproc();
- pp->proc = p;
- if(p == nil)
- pp->pid = -1;
-}
-
-void
-_pthreadinit(void)
-{
- signal(SIGUSR2, sigusr2handler);
-}
-
-void
-_threadpexit(void)
-{
- _exit(0);
-}
-
-#ifdef __arm__
-void
-makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
-{
- int i, *sp;
- va_list arg;
-
- sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4;
- va_start(arg, argc);
- for(i=0; i<4 && i<argc; i++)
- uc->uc_mcontext.gregs[i] = va_arg(arg, uint);
- va_end(arg);
- uc->uc_mcontext.gregs[13] = (uint)sp;
- uc->uc_mcontext.gregs[14] = (uint)fn;
-}
-
-int
-swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
-{
- if(getcontext(oucp) == 0)
- setcontext(ucp);
- return 0;
-}
-#endif
diff --git a/src/libthread/NetBSD.c b/src/libthread/NetBSD.c
index 37dabe9c..2b14146b 100644
--- a/src/libthread/NetBSD.c
+++ b/src/libthread/NetBSD.c
@@ -1 +1,437 @@
-#include "Linux.c"
+#include "threadimpl.h"
+
+#undef exits
+#undef _exits
+
+static int
+timefmt(Fmt *fmt)
+{
+ static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ vlong ns;
+ Tm tm;
+ ns = nsec();
+ tm = *localtime(time(0));
+ return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
+ mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
+ (int)(ns%1000000000)/1000000);
+}
+
+/*
+ * spin locks
+ */
+extern int _tas(int*);
+
+void
+_threadunlock(Lock *l, ulong pc)
+{
+ USED(pc);
+
+ l->held = 0;
+}
+
+int
+_threadlock(Lock *l, int block, ulong pc)
+{
+ int i;
+static int first=1;
+if(first) {first=0; fmtinstall('\001', timefmt);}
+
+ USED(pc);
+
+ /* once fast */
+ if(!_tas(&l->held))
+ return 1;
+ if(!block)
+ return 0;
+
+ /* a thousand times pretty fast */
+ for(i=0; i<1000; i++){
+ if(!_tas(&l->held))
+ return 1;
+ sched_yield();
+ }
+ /* now increasingly slow */
+ for(i=0; i<10; i++){
+ if(!_tas(&l->held))
+ return 1;
+ usleep(1);
+ }
+fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc);
+ for(i=0; i<10; i++){
+ if(!_tas(&l->held))
+ return 1;
+ usleep(10);
+ }
+fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc);
+ for(i=0; i<10; i++){
+ if(!_tas(&l->held))
+ return 1;
+ usleep(100);
+ }
+fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc);
+ for(i=0; i<10; i++){
+ if(!_tas(&l->held))
+ return 1;
+ usleep(1000);
+ }
+fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc);
+ for(i=0; i<10; i++){
+ if(!_tas(&l->held))
+ return 1;
+ usleep(10*1000);
+ }
+fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc);
+ for(i=0; i<1000; i++){
+ if(!_tas(&l->held))
+ return 1;
+ usleep(100*1000);
+ }
+fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc);
+ /* take your time */
+ while(_tas(&l->held))
+ usleep(1000*1000);
+ return 1;
+}
+
+/*
+ * sleep and wakeup
+ */
+static void
+ign(int x)
+{
+ USED(x);
+}
+
+static void /*__attribute__((constructor))*/
+ignusr1(int restart)
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_handler = ign;
+ sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGUSR1);
+ if(restart)
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGUSR1, &sa, nil);
+}
+
+void
+_procsleep(_Procrendez *r)
+{
+ sigset_t mask;
+
+ /*
+ * Go to sleep.
+ *
+ * Block USR1, set the handler to interrupt system calls,
+ * unlock the vouslock so our waker can wake us,
+ * and then suspend.
+ */
+again:
+ r->asleep = 1;
+ r->pid = getpid();
+
+ sigprocmask(SIG_SETMASK, nil, &mask);
+ sigaddset(&mask, SIGUSR1);
+ sigprocmask(SIG_SETMASK, &mask, nil);
+ ignusr1(0);
+ unlock(r->l);
+ sigdelset(&mask, SIGUSR1);
+ sigsuspend(&mask);
+
+ /*
+ * We're awake. Make USR1 not interrupt system calls.
+ */
+ lock(r->l);
+ ignusr1(1);
+ if(r->asleep && r->pid == getpid()){
+ /* Didn't really wake up - signal from something else */
+ goto again;
+ }
+}
+
+void
+_procwakeupandunlock(_Procrendez *r)
+{
+ int pid;
+
+ pid = 0;
+ if(r->asleep){
+ r->asleep = 0;
+ assert(r->pid >= 1);
+ pid = r->pid;
+ }
+ assert(r->l);
+ unlock(r->l);
+ if(pid)
+ kill(pid, SIGUSR1);
+}
+
+/*
+ * process creation and exit
+ */
+typedef struct Stackfree Stackfree;
+struct Stackfree
+{
+ Stackfree *next;
+ int pid;
+ int pid1;
+};
+static Lock stacklock;
+static Stackfree *stackfree;
+
+static void
+delayfreestack(uchar *stk, int pid, int pid1)
+{
+ Stackfree *sf;
+
+ sf = (Stackfree*)stk;
+ sf->pid = pid;
+ sf->pid1 = pid1;
+ lock(&stacklock);
+ sf->next = stackfree;
+ stackfree = sf;
+ unlock(&stacklock);
+}
+
+static void
+dofreestacks(void)
+{
+ Stackfree *sf, *last, *next;
+
+ if(stackfree==nil || !canlock(&stacklock))
+ return;
+
+ for(last=nil,sf=stackfree; sf; last=sf,sf=next){
+ next = sf->next;
+ if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH)
+ if(sf->pid1 >= 1 && kill(sf->pid1, 0) < 0 && errno == ESRCH){
+ free(sf);
+ if(last)
+ last->next = next;
+ else
+ stackfree = next;
+ sf = last;
+ }
+ }
+ unlock(&stacklock);
+}
+
+static int
+startprocfn(void *v)
+{
+ void **a;
+ uchar *stk;
+ void (*fn)(void*);
+ Proc *p;
+ int pid0, pid1;
+
+ a = (void**)v;
+ fn = a[0];
+ p = a[1];
+ stk = a[2];
+ pid0 = (int)a[4];
+ pid1 = getpid();
+ free(a);
+ p->osprocid = pid1;
+
+ (*fn)(p);
+
+ delayfreestack(stk, pid0, pid1);
+ _exit(0);
+ return 0;
+}
+
+/*
+ * indirect through here so that parent need not wait for child zombie
+ *
+ * slight race - if child exits and then another process starts before we
+ * manage to exit, we'll be running on a freed stack.
+ */
+static int
+trampnowait(void *v)
+{
+ void **a;
+ int *kidpid;
+
+ a = (void*)v;
+ kidpid = a[3];
+ a[4] = (void*)getpid();
+ *kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
+ _exit(0);
+ return 0;
+}
+
+void
+_procstart(Proc *p, void (*fn)(Proc*))
+{
+ void **a;
+ uchar *stk;
+ int pid, kidpid, status;
+
+ dofreestacks();
+ a = malloc(5*sizeof a[0]);
+ if(a == nil)
+ sysfatal("_procstart malloc: %r");
+ stk = malloc(65536);
+ if(stk == nil)
+ sysfatal("_procstart malloc stack: %r");
+
+ a[0] = fn;
+ a[1] = p;
+ a[2] = stk;
+ a[3] = &kidpid;
+ kidpid = -1;
+
+ pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
+ if(pid > 0)
+ if(wait4(pid, &status, __WALL, 0) < 0)
+ fprint(2, "ffork wait4: %r\n");
+ if(pid < 0 || kidpid < 0){
+ fprint(2, "_procstart clone: %r\n");
+ abort();
+ }
+}
+
+static char *threadexitsmsg;
+void
+sigusr2handler(int s)
+{
+/* fprint(2, "%d usr2 %d\n", time(0), getpid()); */
+ if(threadexitsmsg)
+ _exits(threadexitsmsg);
+}
+
+void
+threadexitsall(char *msg)
+{
+ static int pid[1024];
+ int i, npid, mypid;
+ Proc *p;
+
+ if(msg == nil)
+ msg = "";
+
+ /*
+ * Only one guy, ever, gets to run this.
+ * If two guys do it, inevitably they end up
+ * tripping over each other in the underlying
+ * C library exit() implementation, which is
+ * trying to run the atexit handlers and apparently
+ * not thread safe. This has been observed on
+ * both Linux and OpenBSD. Sigh.
+ */
+ {
+ static Lock onelock;
+ if(!canlock(&onelock))
+ _exits(threadexitsmsg);
+ threadexitsmsg = msg;
+ }
+
+ mypid = getpid();
+ lock(&_threadprocslock);
+ npid = 0;
+ for(p=_threadprocs; p; p=p->next)
+ if(p->osprocid != mypid && p->osprocid >= 1)
+ pid[npid++] = p->osprocid;
+ for(i=0; i<npid; i++)
+ kill(pid[i], SIGUSR2);
+ unlock(&_threadprocslock);
+ exits(msg);
+}
+
+/*
+ * per-process data, indexed by pid
+ *
+ * could use modify_ldt and a segment register
+ * to avoid the many calls to getpid(), but i don't
+ * care -- this is compatibility code. linux 2.6 with
+ * nptl is a good enough pthreads to avoid this whole file.
+ */
+typedef struct Perproc Perproc;
+struct Perproc
+{
+ int pid;
+ Proc *proc;
+};
+
+static Lock perlock;
+static Perproc perproc[1024];
+#define P ((Proc*)-1)
+
+static Perproc*
+myperproc(void)
+{
+ int i, pid, h;
+ Perproc *p;
+
+ pid = getpid();
+ h = pid%nelem(perproc);
+ for(i=0; i<nelem(perproc); i++){
+ p = &perproc[(i+h)%nelem(perproc)];
+ if(p->pid == pid)
+ return p;
+ if(p->pid == 0){
+ print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
+ break;
+ }
+ }
+ fprint(2, "myperproc %d (%s): cannot find self\n", pid, argv0);
+ abort();
+ return nil;
+}
+
+static Perproc*
+newperproc(void)
+{
+ int i, pid, h;
+ Perproc *p;
+
+ lock(&perlock);
+ pid = getpid();
+ h = pid%nelem(perproc);
+ for(i=0; i<nelem(perproc); i++){
+ p = &perproc[(i+h)%nelem(perproc)];
+ if(p->pid == pid || p->pid == -1 || p->pid == 0){
+ p->pid = pid;
+ unlock(&perlock);
+ return p;
+ }
+ }
+ fprint(2, "newperproc %d: out of procs\n", pid);
+ abort();
+ return nil;
+}
+
+Proc*
+_threadproc(void)
+{
+ return myperproc()->proc;
+}
+
+void
+_threadsetproc(Proc *p)
+{
+ Perproc *pp;
+
+ if(p)
+ p->osprocid = getpid();
+ pp = newperproc();
+ pp->proc = p;
+ if(p == nil)
+ pp->pid = -1;
+}
+
+void
+_pthreadinit(void)
+{
+ signal(SIGUSR2, sigusr2handler);
+}
+
+void
+_threadpexit(void)
+{
+ _exit(0);
+}
diff --git a/src/libthread/OpenBSD-386-asm.s b/src/libthread/OpenBSD-386-asm.s
index dad1b536..ed18d2f0 100644
--- a/src/libthread/OpenBSD-386-asm.s
+++ b/src/libthread/OpenBSD-386-asm.s
@@ -1 +1,45 @@
-#include "FreeBSD-386-asm.s"
+.globl getmcontext
+getmcontext:
+ movl 4(%esp), %eax
+
+ movl %fs, 8(%eax)
+ movl %es, 12(%eax)
+ movl %ds, 16(%eax)
+ movl %ss, 76(%eax)
+ movl %edi, 20(%eax)
+ movl %esi, 24(%eax)
+ movl %ebp, 28(%eax)
+ movl %ebx, 36(%eax)
+ movl %edx, 40(%eax)
+ movl %ecx, 44(%eax)
+
+ movl $1, 48(%eax) /* %eax */
+ movl (%esp), %ecx /* %eip */
+ movl %ecx, 60(%eax)
+ leal 4(%esp), %ecx /* %esp */
+ movl %ecx, 72(%eax)
+
+ movl 44(%eax), %ecx /* restore %ecx */
+ movl $0, %eax
+ ret
+
+.globl setmcontext
+setmcontext:
+ movl 4(%esp), %eax
+
+ movl 8(%eax), %fs
+ movl 12(%eax), %es
+ movl 16(%eax), %ds
+ movl 76(%eax), %ss
+ movl 20(%eax), %edi
+ movl 24(%eax), %esi
+ movl 28(%eax), %ebp
+ movl 36(%eax), %ebx
+ movl 40(%eax), %edx
+ movl 44(%eax), %ecx
+
+ movl 72(%eax), %esp
+ pushl 60(%eax) /* new %eip */
+ movl 48(%eax), %eax
+ ret
+
diff --git a/src/libthread/OpenBSD-power-asm.S b/src/libthread/OpenBSD-power-asm.S
index 03b46e7b..36035eb5 100644
--- a/src/libthread/OpenBSD-power-asm.S
+++ b/src/libthread/OpenBSD-power-asm.S
@@ -1,18 +1,3 @@
-ENTRY(_tas)
- li %r0, 0
- mr %r4, %r3
- lis %r5, 0xcafe
- ori %r5, %r5, 0xbabe
-1:
- lwarx %r3, %r0, %r4
- cmpwi %r3, 0
- bne 2f
- stwcx. %r5, %r0, %r4
- bne- 1b
-2:
- sync
- blr
-
ENTRY(_getmcontext) /* xxx: instruction scheduling */
mflr %r0
mfcr %r5
diff --git a/src/libthread/OpenBSD-power.c b/src/libthread/OpenBSD-power.c
deleted file mode 100644
index eab711f2..00000000
--- a/src/libthread/OpenBSD-power.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "threadimpl.h"
-
-void
-makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
-{
- ulong *sp, *tos;
- va_list arg;
-
- tos = (ulong*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(ulong);
- sp = (ulong*)((ulong)(tos-16) & ~15);
- ucp->mc.pc = (long)func;
- ucp->mc.sp = (long)sp;
- va_start(arg, argc);
- ucp->mc.r3 = va_arg(arg, long);
- va_end(arg);
-}
-
-int
-swapcontext(ucontext_t *oucp, ucontext_t *ucp)
-{
- if(getcontext(oucp) == 0)
- setcontext(ucp);
- return 0;
-}
diff --git a/src/libthread/OpenBSD.c b/src/libthread/OpenBSD.c
deleted file mode 100644
index 80a50977..00000000
--- a/src/libthread/OpenBSD.c
+++ /dev/null
@@ -1,145 +0,0 @@
-#include "threadimpl.h"
-#include "BSD.c"
-
-#include <dlfcn.h>
-
-struct thread_tag {
- struct thread_tag *next;
- spinlock_t l;
- volatile int key;
- void *data;
-};
-
-static spinlock_t mlock;
-static spinlock_t dl_lock;
-static spinlock_t tag_lock;
-static struct thread_tag *thread_tag_store = nil;
-static uint nextkey = 0;
-
-void
-_thread_malloc_lock(void)
-{
- _spinlock(&mlock);
-}
-
-void
-_thread_malloc_unlock(void)
-{
- _spinunlock(&mlock);
-}
-
-void
-_thread_malloc_init(void)
-{
-}
-
-/*
- * for ld.so
- */
-void
-_thread_dl_lock(int t)
-{
- if(t)
- _spinunlock(&dl_lock);
- else
- _spinlock(&dl_lock);
-}
-
-/*
- * for libc
- */
-static void
-_thread_tag_init(void **tag)
-{
- struct thread_tag *t;
-
- _spinlock(&tag_lock);
- if(*tag == nil) {
- t = malloc(sizeof (*t));
- if(t != nil) {
- memset(&t->l, 0, sizeof(t->l));
- t->key = nextkey++;
- *tag = t;
- }
- }
- _spinunlock(&tag_lock);
-}
-
-void
-_thread_tag_lock(void **tag)
-{
- struct thread_tag *t;
-
- if(*tag == nil)
- _thread_tag_init(tag);
- t = *tag;
- _spinlock(&t->l);
-}
-
-void
-_thread_tag_unlock(void **tag)
-{
- struct thread_tag *t;
-
- if(*tag == nil)
- _thread_tag_init(tag);
- t = *tag;
- _spinunlock(&t->l);
-}
-
-static void *
-_thread_tag_insert(struct thread_tag *t, void *v)
-{
- t->data = v;
- t->next = thread_tag_store;
- thread_tag_store = t;
- return t;
-}
-
-static void *
-_thread_tag_lookup(struct thread_tag *tag, int size)
-{
- struct thread_tag *t;
- void *p;
-
- _spinlock(&tag->l);
- for(t = thread_tag_store; t != nil; t = t->next)
- if(t->key == tag->key)
- break;
- if(t == nil) {
- p = malloc(size);
- if(p == nil) {
- _spinunlock(&tag->l);
- return nil;
- }
- _thread_tag_insert(tag, p);
- }
- _spinunlock(&tag->l);
- return tag->data;
-}
-
-void *
-_thread_tag_storage(void **tag, void *storage, size_t n, void *err)
-{
- struct thread_tag *t;
- void *r;
-
- if(*tag == nil)
- _thread_tag_init(tag);
- t = *tag;
-
- r = _thread_tag_lookup(t, n);
- if(r == nil)
- r = err;
- else
- memcpy(r, storage, n);
- return r;
-}
-
-void
-_pthreadinit(void)
-{
- __isthreaded = 1;
- dlctl(nil, DL_SETTHREADLCK, _thread_dl_lock);
- signal(SIGUSR2, sigusr2handler);
-}
diff --git a/src/libthread/README.Linux b/src/libthread/README.Linux
deleted file mode 100644
index 04c491a8..00000000
--- a/src/libthread/README.Linux
+++ /dev/null
@@ -1,40 +0,0 @@
-Thread support on Linux is confused by the recent thread local storage (TLS)
-support that has been put into the ELF tool chain. The TLS libraries are
-installed in /lib/tls on most Linux systems.
-
-We provide two different implementations of the os-dependent parts
-of libthread for Linux. The first is intended for use on Linux 2.4 and earlier
-kernels, which do not support TLS. It is in Linux.c and Linuxasm.c and
-does not use the pthread interface. The second is intended for Linux 2.6
-and later kernels, which do support TLS. It is in pthread.c and uses the
-standard pthread interface. It expects to be linked against the TLS-aware
-thread library aka NPTL.
-
-If you use Linux.c and Linuxasm.c with TLS libraries, they do not
-set up the TLS properly so you will get incorrect programs.
-For example, there will only be one errno among all the procs
-in your program instead of one per proc. The pthread NPTL
-implementation is needed to use the TLS libraries properly.
-
-If you use pthread.c without TLS libraries (i.e., with the old Linux
-pthread library known as LinuxThreads), then you will also get
-incorrect programs, although more obviously so. The LinuxThreads
-library assumes it can look at the stack pointer to distinguish between
-threads, but libthread does its own stack management, breaking this
-assumption. If you run a pthread-compiled program with the
-LinuxThreads library, LinuxThreads itself will cause a segmentation
-fault in __pthread_getspecific() the first time it is called from a
-non-standard stack.
-
-So, it is important that you compile binaries that match your
-system's choice of TLS vs. not-TLS libraries. The hard part is figuring
-out which your system has chosen. Plan9port looks at the kernel
-version you are running and assumes that on kernels that support
-TLS (2.6+) you will be using TLS.
-
-Apparently Gentoo and maybe other distributions do not follow this rule.
-They use non-TLS libraries even on kernels that can support TLS.
-To accomodate them, you can add a line SYSVERSION=2.4 to $PLAN9/config
-to force the build to think you are running an old kernel.
-The INSTALL script sets up this file automatically on Linux systems.
-
diff --git a/src/libthread/Linux-arm-swapcontext.c b/src/libthread/arm-ucontext.c
index fc0dfdda..512ca973 100644
--- a/src/libthread/Linux-arm-swapcontext.c
+++ b/src/libthread/arm-ucontext.c
@@ -6,7 +6,7 @@ makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
int i, *sp;
va_list arg;
- sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4;
+ sp = USPALIGN(uc, 4);
va_start(arg, argc);
for(i=0; i<4 && i<argc; i++)
(&uc->uc_mcontext.arm_r0)[i] = va_arg(arg, uint);
diff --git a/src/libthread/mkfile b/src/libthread/mkfile
index f621ac60..8a77a316 100644
--- a/src/libthread/mkfile
+++ b/src/libthread/mkfile
@@ -16,8 +16,6 @@ OFILES=\
<$PLAN9/src/mksyslib
HFILES=thread.h threadimpl.h
-FreeBSD.$O: BSD.c
-NetBSD.$O: Linux.c
tprimes: test/tprimes.$O
9l -o $target test/$target.$O
@@ -26,6 +24,8 @@ tspawn: test/tspawn.$O
tspawnloop: test/tspawnloop.$O
9l -o $target test/$target.$O
+tprimes tspawn tspawnloop: $PLAN9/lib/$LIB
+
%.$O: %.c
$CC -o $target $CFLAGS -I. $stem.c
@@ -39,8 +39,8 @@ OpenBSD-%-asm.$O: OpenBSD-%-asm.S
Linux-sparc64-context.$O: Linux-sparc64-context.S
$CC -m64 -mcpu=v9 $CFLAGS Linux-sparc64-context.S
-Linux-sparc64-swapcontext.$O: Linux-sparc64-swapcontext.c
- $CC -m64 -mcpu=v9 $CFLAGS Linux-sparc64-swapcontext.c
+sparc64-ucontext.$O: sparc64-ucontext.c
+ $CC -m64 -mcpu=v9 $CFLAGS sparc64-ucontext.c
test:V: tprimes tspawn
primes 1 10007 >p1.txt
@@ -52,4 +52,5 @@ test:V: tprimes tspawn
echo tspawn should take 3 seconds, not 6
$PLAN9/bin/time ./tspawn sleep 3 >/dev/null
-CLEANFILES=p1.txt p2.txt tp1.txt tp2.txt test/*.$O
+CLEANFILES=p1.txt p2.txt tp1.txt tp2.txt test/*.$O tprimes tspawn
+
diff --git a/src/libthread/Darwin-power.c b/src/libthread/power-ucontext.c
index 3f2bf566..32a8e931 100644
--- a/src/libthread/Darwin-power.c
+++ b/src/libthread/power-ucontext.c
@@ -6,12 +6,14 @@ makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
ulong *sp, *tos;
va_list arg;
- tos = (ulong*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(ulong);
- sp = tos - 16;
+ if(argc != 2)
+ sysfatal("libthread: makecontext misused");
+ sp = USPALIGN(ucp, 16);
ucp->mc.pc = (long)func;
ucp->mc.sp = (long)sp;
va_start(arg, argc);
ucp->mc.r3 = va_arg(arg, long);
+ ucp->mc.r4 = va_arg(arg, long);
va_end(arg);
}
diff --git a/src/libthread/sparc-ucontext.h b/src/libthread/sparc-ucontext.h
deleted file mode 100644
index 36b88171..00000000
--- a/src/libthread/sparc-ucontext.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#define setcontext(u) _setmcontext(&(u)->mc)
-#define getcontext(u) _getmcontext(&(u)->mc)
-typedef struct mcontext mcontext_t;
-typedef struct ucontext ucontext_t;
-struct mcontext
-{
- int r[16];
-};
-
-struct ucontext
-{
- struct {
- void *ss_sp;
- uint ss_size;
- } uc_stack;
- sigset_t uc_sigmask;
- mcontext_t mc;
-};
-
-void makecontext(ucontext_t*, void(*)(void), int, ...);
-int swapcontext(ucontext_t*, ucontext_t*);
-int _getmcontext(mcontext_t*);
-void _setmcontext(mcontext_t*);
diff --git a/src/libthread/Linux-sparc64-swapcontext.c b/src/libthread/sparc64-ucontext.c
index e4800c19..e4800c19 100644
--- a/src/libthread/Linux-sparc64-swapcontext.c
+++ b/src/libthread/sparc64-ucontext.c
diff --git a/src/libthread/stkmalloc.c b/src/libthread/stkmalloc.c
new file mode 100644
index 00000000..083aea1b
--- /dev/null
+++ b/src/libthread/stkmalloc.c
@@ -0,0 +1,13 @@
+#include "threadimpl.h"
+
+void*
+_threadstkalloc(int n)
+{
+ return malloc(n);
+}
+
+void
+_threadstkfree(void *v, int n)
+{
+ free(v);
+}
diff --git a/src/libthread/stkmmap.c b/src/libthread/stkmmap.c
new file mode 100644
index 00000000..f4a24630
--- /dev/null
+++ b/src/libthread/stkmmap.c
@@ -0,0 +1,25 @@
+#include <u.h>
+#include <sys/mman.h>
+#include "threadimpl.h"
+
+#ifndef MAP_STACK
+#define MAP_STACK 0
+#endif
+
+void*
+_threadstkalloc(int n)
+{
+ void *p;
+
+ p = mmap(nil, n, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON|MAP_STACK, -1, 0);
+ if(p == (void*)-1)
+ return nil;
+ return p;
+}
+
+void
+_threadstkfree(void *v, int n)
+{
+ if(n > 0)
+ munmap(v, n);
+}
diff --git a/src/libthread/sysofiles.sh b/src/libthread/sysofiles.sh
index 9eeea606..20811cdf 100644
--- a/src/libthread/sysofiles.sh
+++ b/src/libthread/sysofiles.sh
@@ -2,40 +2,27 @@
test -f $PLAN9/config && . $PLAN9/config
-tag="$OBJTYPE-$SYSNAME-${SYSVERSION:-`uname -r`}-${CC9:-cc}"
-case "$tag" in
-*-Linux-2.[0-5]*)
- # will have to fix this for linux power pc
- echo ${SYSNAME}-${OBJTYPE}-asm.o $SYSNAME.o
+case "$SYSNAME" in
+NetBSD)
+ echo ${SYSNAME}-${OBJTYPE}-asm.o $SYSNAME.o stkmalloc.o
;;
-*-FreeBSD-[0-4].*)
- echo ${SYSNAME}-${OBJTYPE}-asm.o $SYSNAME.o
- ;;
-*-NetBSD-*)
- echo ${SYSNAME}-${OBJTYPE}-asm.o $SYSNAME.o
- ;;
-*-Darwin-10.[5-6].* | *-Darwin-[89].*)
- echo ${SYSNAME}-${OBJTYPE}-asm.o $SYSNAME-${OBJTYPE}.o pthread.o
- ;;
-*-OpenBSD-*)
- echo ${SYSNAME}-${OBJTYPE}-asm.o ${SYSNAME}-${OBJTYPE}.o pthread.o
+OpenBSD)
+ echo pthread.o stkmmap.o
;;
*)
- echo pthread.o
+ echo pthread.o stkmalloc.o
esac
-case "$OBJTYPE-$SYSNAME" in
-sparc64-Linux)
- # Debian glibc doesn't supply swapcontext, makecontext
- # so we supply our own copy from the latest glibc.
- echo Linux-sparc64-context.o Linux-sparc64-swapcontext.o
- ;;
-arm-Linux)
- # ARM doesn't supply them either.
- echo Linux-arm-context.o Linux-arm-swapcontext.o
- ;;
-x86_64-Darwin)
- echo Darwin-x86_64-asm.o Darwin-x86_64-swapcontext.o
+# Various libc don't supply swapcontext, makecontext, so we do.
+case "$SYSNAME-$OBJTYPE" in
+Darwin-x86_64 | Linux-arm | Linux-sparc64 | NetBSD-arm | OpenBSD-386 | OpenBSD-power | OpenBSD-x86_64)
+ echo $OBJTYPE-ucontext.o
;;
esac
+# A few libc don't supply setcontext, getcontext, so we do.
+case "$SYSNAME-$OBJTYPE" in
+Darwin-x86_64 | Linux-arm | Linux-sparc64 | OpenBSD-386 | OpenBSD-power | OpenBSD-x86_64)
+ echo $SYSNAME-$OBJTYPE-asm.o
+ ;;
+esac
diff --git a/src/libthread/thread.c b/src/libthread/thread.c
index d041efcc..f657b5b2 100644
--- a/src/libthread/thread.c
+++ b/src/libthread/thread.c
@@ -109,7 +109,7 @@ threadalloc(void (*fn)(void*), void *arg, uint stack)
ulong z;
/* allocate the task and stack together */
- t = malloc(sizeof *t+stack);
+ t = malloc(sizeof *t);
if(t == nil)
sysfatal("threadalloc malloc: %r");
memset(t, 0, sizeof *t);
@@ -122,7 +122,9 @@ threadalloc(void (*fn)(void*), void *arg, uint stack)
/* do a reasonable initialization */
if(stack == 0)
return t;
- t->stk = (uchar*)(t+1);
+ t->stk = _threadstkalloc(stack);
+ if(t->stk == nil)
+ sysfatal("threadalloc malloc stack: %r");
t->stksize = stack;
memset(&t->context.uc, 0, sizeof t->context.uc);
sigemptyset(&zero);
@@ -134,10 +136,16 @@ threadalloc(void (*fn)(void*), void *arg, uint stack)
sysfatal("threadalloc getcontext: %r");
//print("makecontext sp=%p t=%p startfn=%p\n", (char*)t->stk+t->stksize, t, t->startfn);
- /* call makecontext to do the real work. */
- /* leave a few words open on both ends */
- t->context.uc.uc_stack.ss_sp = (void*)(t->stk+8);
- t->context.uc.uc_stack.ss_size = t->stksize-64;
+ /*
+ * Call makecontext to do the real work.
+ * To avoid various mistakes on other system software,
+ * debuggers, and so on, don't get too close to both
+ * ends of the stack. Just staying away is much easier
+ * than debugging everything (outside our control)
+ * that has off-by-one errors.
+ */
+ t->context.uc.uc_stack.ss_sp = (void*)(t->stk+64);
+ t->context.uc.uc_stack.ss_size = t->stksize-2*64;
#if defined(__sun__) && !defined(__MAKECONTEXT_V2_SOURCE) /* sigh */
/* can avoid this with __MAKECONTEXT_V2_SOURCE but only on SunOS 5.9 */
t->context.uc.uc_stack.ss_sp =
@@ -353,6 +361,7 @@ Top:
delthreadinproc(p, t);
p->nthread--;
/*print("nthread %d\n", p->nthread); */
+ _threadstkfree(t->stk, t->stksize);
free(t);
}
@@ -509,6 +518,8 @@ needstack(int n)
_Thread *t;
t = proc()->thread;
+ if(t->stk == nil)
+ return;
if((char*)&t <= (char*)t->stk
|| (char*)&t - (char*)t->stk < 256+n){
diff --git a/src/libthread/threadimpl.h b/src/libthread/threadimpl.h
index 76ca57e5..cceb1b8e 100644
--- a/src/libthread/threadimpl.h
+++ b/src/libthread/threadimpl.h
@@ -15,15 +15,6 @@
#include "libc.h"
#include "thread.h"
-#if defined(__FreeBSD__) && __FreeBSD__ < 5
-extern int getmcontext(mcontext_t*);
-extern void setmcontext(mcontext_t*);
-#define setcontext(u) setmcontext(&(u)->uc_mcontext)
-#define getcontext(u) getmcontext(&(u)->uc_mcontext)
-extern int swapcontext(ucontext_t*, ucontext_t*);
-extern void makecontext(ucontext_t*, void(*)(), int, ...);
-#endif
-
#if defined(__APPLE__)
/*
* OS X before 10.5 (Leopard) does not provide
@@ -64,20 +55,6 @@ extern void makecontext(ucontext_t*, void(*)(), int, ...);
extern pid_t rfork_thread(int, void*, int(*)(void*), void*);
#endif
-/* THIS DOES NOT WORK! Don't do this!
-(At least, not on Solaris. Maybe this is right for Linux,
-in which case it should say if defined(__linux__) && defined(__sun__),
-but surely the latter would be defined(__sparc__).
-
-#if defined(__sun__)
-# define mcontext libthread_mcontext
-# define mcontext_t libthread_mcontext_t
-# define ucontext libthread_ucontext
-# define ucontext_t libthread_ucontext_t
-# include "sparc-ucontext.h"
-#endif
-*/
-
#if defined(__arm__)
int mygetmcontext(ulong*);
void mysetmcontext(const ulong*);
@@ -209,3 +186,8 @@ extern void _threadsetupdaemonize(void);
extern void _threaddodaemonize(char*);
extern void _threadpexit(void);
extern void _threaddaemonize(void);
+extern void *_threadstkalloc(int);
+extern void _threadstkfree(void*, int);
+
+#define USPALIGN(ucp, align) \
+ (void*)((((uintptr)(ucp)->uc_stack.ss_sp+(ucp)->uc_stack.ss_size)-(align))&~((align)-1))
diff --git a/src/libthread/OpenBSD-x86_64.c b/src/libthread/x86_64-ucontext.c
index 27931456..5d1aaefc 100644
--- a/src/libthread/OpenBSD-x86_64.c
+++ b/src/libthread/x86_64-ucontext.c
@@ -6,16 +6,14 @@ makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
uintptr *sp;
va_list arg;
-//fprint(2, "makecontext %d\n", argc);
if(argc != 2)
sysfatal("libthread: makecontext misused");
va_start(arg, argc);
uc->mc.di = va_arg(arg, uint);
uc->mc.si = va_arg(arg, uint);
-//fprint(2, "%ux %ux\n", uc->mc.di, uc->mc.si);
va_end(arg);
- sp = (uintptr*)((char*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size);
+ sp = USPALIGN(uc, 16);
*--sp = 0; // fn's return address
*--sp = (uintptr)fn; // return address of setcontext
uc->mc.sp = (uintptr)sp;