commit 8d82ccefd2b4b058e20ae0a7e3d9ef9b6b8cf8c3 from: Russ Cox date: Mon Jan 20 04:04:58 2020 UTC libthread: remove Linux 2.4 code Linux.c was for Linux 2.4 and is no longer used directly, only indirectly because NetBSD.c was a 1-line file #including Linux.c. So mv Linux.c NetBSD.c. Also rm Linux-*-asm.s which was for Linux 2.4 as well. commit - c181e39eeab0eb8cad274b7b22ce5343bd55630d commit + 8d82ccefd2b4b058e20ae0a7e3d9ef9b6b8cf8c3 blob - 197f12b54d646eb2eaf297eaacfe923aec2b9a43 (mode 644) blob + /dev/null --- 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 - blob - 721ea43b5e9b8c3569a13825f5a8510b3b01c47e (mode 644) blob + /dev/null --- src/libthread/Linux-arm-asm.s +++ /dev/null @@ -1,10 +0,0 @@ - -.globl _tas -_tas: - mov r3, #0xCA000000 - add r3, r3, #0xFE0000 - add r3, r3, #0xBA00 - add r3, r3, #0xBE - swp r3, r3, [r0] - mov r0, r3 - mov pc, lr blob - d6e21c157b50a515a08e33e31a949dafa41e08a2 (mode 644) blob + /dev/null --- 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 - blob - 422a1b244b8895849f71086bb85a5a00cd648655 (mode 644) blob + /dev/null --- 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) - blob - 31577e876dc7be7d2c6d59e67e02887eadf5c25c (mode 644) blob + /dev/null --- 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; ipid == 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; ipid == 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 && iuc_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 blob - 37dabe9c909f047f45cd39c8daf9ec699061528c blob + 31577e876dc7be7d2c6d59e67e02887eadf5c25c --- src/libthread/NetBSD.c +++ src/libthread/NetBSD.c @@ -1 +1,462 @@ -#include "Linux.c" +#include "threadimpl.h" + +#undef exits +#undef _exits + +static int +timefmt(Fmt *fmt) +{ + static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + vlong ns; + Tm tm; + ns = nsec(); + tm = *localtime(time(0)); + return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d", + mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec, + (int)(ns%1000000000)/1000000); +} + +/* + * spin locks + */ +extern int _tas(int*); + +void +_threadunlock(Lock *l, ulong pc) +{ + USED(pc); + + l->held = 0; +} + +int +_threadlock(Lock *l, int block, ulong pc) +{ + int i; +static int first=1; +if(first) {first=0; fmtinstall('\001', timefmt);} + + USED(pc); + + /* once fast */ + if(!_tas(&l->held)) + return 1; + if(!block) + return 0; + + /* a thousand times pretty fast */ + for(i=0; i<1000; i++){ + if(!_tas(&l->held)) + return 1; + sched_yield(); + } + /* now increasingly slow */ + for(i=0; i<10; i++){ + if(!_tas(&l->held)) + return 1; + usleep(1); + } +fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc); + for(i=0; i<10; i++){ + if(!_tas(&l->held)) + return 1; + usleep(10); + } +fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc); + for(i=0; i<10; i++){ + if(!_tas(&l->held)) + return 1; + usleep(100); + } +fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc); + for(i=0; i<10; i++){ + if(!_tas(&l->held)) + return 1; + usleep(1000); + } +fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc); + for(i=0; i<10; i++){ + if(!_tas(&l->held)) + return 1; + usleep(10*1000); + } +fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc); + for(i=0; i<1000; i++){ + if(!_tas(&l->held)) + return 1; + usleep(100*1000); + } +fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc); + /* take your time */ + while(_tas(&l->held)) + usleep(1000*1000); + return 1; +} + +/* + * sleep and wakeup + */ +static void +ign(int x) +{ + USED(x); +} + +static void /*__attribute__((constructor))*/ +ignusr1(int restart) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_handler = ign; + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGUSR1); + if(restart) + sa.sa_flags = SA_RESTART; + sigaction(SIGUSR1, &sa, nil); +} + +void +_procsleep(_Procrendez *r) +{ + sigset_t mask; + + /* + * Go to sleep. + * + * Block USR1, set the handler to interrupt system calls, + * unlock the vouslock so our waker can wake us, + * and then suspend. + */ +again: + r->asleep = 1; + r->pid = getpid(); + + sigprocmask(SIG_SETMASK, nil, &mask); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_SETMASK, &mask, nil); + ignusr1(0); + unlock(r->l); + sigdelset(&mask, SIGUSR1); + sigsuspend(&mask); + + /* + * We're awake. Make USR1 not interrupt system calls. + */ + lock(r->l); + ignusr1(1); + if(r->asleep && r->pid == getpid()){ + /* Didn't really wake up - signal from something else */ + goto again; + } +} + +void +_procwakeupandunlock(_Procrendez *r) +{ + int pid; + + pid = 0; + if(r->asleep){ + r->asleep = 0; + assert(r->pid >= 1); + pid = r->pid; + } + assert(r->l); + unlock(r->l); + if(pid) + kill(pid, SIGUSR1); +} + +/* + * process creation and exit + */ +typedef struct Stackfree Stackfree; +struct Stackfree +{ + Stackfree *next; + int pid; + int pid1; +}; +static Lock stacklock; +static Stackfree *stackfree; + +static void +delayfreestack(uchar *stk, int pid, int pid1) +{ + Stackfree *sf; + + sf = (Stackfree*)stk; + sf->pid = pid; + sf->pid1 = pid1; + lock(&stacklock); + sf->next = stackfree; + stackfree = sf; + unlock(&stacklock); +} + +static void +dofreestacks(void) +{ + Stackfree *sf, *last, *next; + + if(stackfree==nil || !canlock(&stacklock)) + return; + + for(last=nil,sf=stackfree; sf; last=sf,sf=next){ + next = sf->next; + if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH) + if(sf->pid1 >= 1 && kill(sf->pid1, 0) < 0 && errno == ESRCH){ + free(sf); + if(last) + last->next = next; + else + stackfree = next; + sf = last; + } + } + unlock(&stacklock); +} + +static int +startprocfn(void *v) +{ + void **a; + uchar *stk; + void (*fn)(void*); + Proc *p; + int pid0, pid1; + + a = (void**)v; + fn = a[0]; + p = a[1]; + stk = a[2]; + pid0 = (int)a[4]; + pid1 = getpid(); + free(a); + p->osprocid = pid1; + + (*fn)(p); + + delayfreestack(stk, pid0, pid1); + _exit(0); + return 0; +} + +/* + * indirect through here so that parent need not wait for child zombie + * + * slight race - if child exits and then another process starts before we + * manage to exit, we'll be running on a freed stack. + */ +static int +trampnowait(void *v) +{ + void **a; + int *kidpid; + + a = (void*)v; + kidpid = a[3]; + a[4] = (void*)getpid(); + *kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a); + _exit(0); + return 0; +} + +void +_procstart(Proc *p, void (*fn)(Proc*)) +{ + void **a; + uchar *stk; + int pid, kidpid, status; + + dofreestacks(); + a = malloc(5*sizeof a[0]); + if(a == nil) + sysfatal("_procstart malloc: %r"); + stk = malloc(65536); + if(stk == nil) + sysfatal("_procstart malloc stack: %r"); + + a[0] = fn; + a[1] = p; + a[2] = stk; + a[3] = &kidpid; + kidpid = -1; + + pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a); + if(pid > 0) + if(wait4(pid, &status, __WALL, 0) < 0) + fprint(2, "ffork wait4: %r\n"); + if(pid < 0 || kidpid < 0){ + fprint(2, "_procstart clone: %r\n"); + abort(); + } +} + +static char *threadexitsmsg; +void +sigusr2handler(int s) +{ +/* fprint(2, "%d usr2 %d\n", time(0), getpid()); */ + if(threadexitsmsg) + _exits(threadexitsmsg); +} + +void +threadexitsall(char *msg) +{ + static int pid[1024]; + int i, npid, mypid; + Proc *p; + + if(msg == nil) + msg = ""; + + /* + * Only one guy, ever, gets to run this. + * If two guys do it, inevitably they end up + * tripping over each other in the underlying + * C library exit() implementation, which is + * trying to run the atexit handlers and apparently + * not thread safe. This has been observed on + * both Linux and OpenBSD. Sigh. + */ + { + static Lock onelock; + if(!canlock(&onelock)) + _exits(threadexitsmsg); + threadexitsmsg = msg; + } + + mypid = getpid(); + lock(&_threadprocslock); + npid = 0; + for(p=_threadprocs; p; p=p->next) + if(p->osprocid != mypid && p->osprocid >= 1) + pid[npid++] = p->osprocid; + for(i=0; ipid == 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; ipid == 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 && iuc_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 blob - 31c4c7e5d754dcc0a948dc9188b14d2bdfc1dfdf blob + a083fd013fe9741647b61ee5888dc96d49aa5487 --- src/libthread/mkfile +++ src/libthread/mkfile @@ -16,7 +16,6 @@ OFILES=\ <$PLAN9/src/mksyslib HFILES=thread.h threadimpl.h -NetBSD.$O: Linux.c tprimes: test/tprimes.$O 9l -o $target test/$target.$O