libthread: delete NetBSD special case

I added a direct call from thread.c to pthread.c's _threadpthreadstart
in May, and no one has complained about NetBSD being broken.
So probably no one is using this on NetBSD at all.
Make pthread the only option.
This commit is contained in:
Russ Cox 2020-12-30 00:06:35 -05:00
parent 69439fae67
commit 5b37d91264
4 changed files with 4 additions and 465 deletions

View file

@ -1,7 +0,0 @@
.globl _tas
_tas:
movl $0xCAFEBABE, %eax
movl 4(%esp), %ecx
xchgl %eax, 0(%ecx)
ret

View file

@ -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

View file

@ -1,437 +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);
}

View file

@ -2,15 +2,14 @@
test -f $PLAN9/config && . $PLAN9/config
echo pthread.o
case "$SYSNAME" in
NetBSD)
echo ${SYSNAME}-${OBJTYPE}-asm.o $SYSNAME.o stkmalloc.o
;;
OpenBSD)
echo pthread.o stkmmap.o
echo stkmmap.o
;;
*)
echo pthread.o stkmalloc.o
echo stkmalloc.o
esac
# Various libc don't supply swapcontext, makecontext, so we do.