OpenBSD/power support.
This commit is contained in:
parent
e9ad899486
commit
cea10000c5
9 changed files with 567 additions and 369 deletions
384
src/libthread/BSD.c
Normal file
384
src/libthread/BSD.c
Normal file
|
|
@ -0,0 +1,384 @@
|
||||||
|
#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;
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 = "";
|
||||||
|
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
|
||||||
|
_pthreadinit(void)
|
||||||
|
{
|
||||||
|
__isthreaded = 1;
|
||||||
|
signal(SIGUSR2, sigusr2handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_threadpexit(void)
|
||||||
|
{
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,368 +1,6 @@
|
||||||
#include "threadimpl.h"
|
#include "threadimpl.h"
|
||||||
|
|
||||||
#undef exits
|
#include "BSD.c"
|
||||||
#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;
|
|
||||||
sched_yield();
|
|
||||||
}
|
|
||||||
/* 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 FreeBSD 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 = "";
|
|
||||||
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
|
|
||||||
*
|
|
||||||
* 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: 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
|
|
||||||
_pthreadinit(void)
|
|
||||||
{
|
|
||||||
__isthreaded = 1;
|
|
||||||
signal(SIGUSR2, sigusr2handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_threadpexit(void)
|
|
||||||
{
|
|
||||||
_exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FreeBSD 4 and earlier needs the context functions.
|
* FreeBSD 4 and earlier needs the context functions.
|
||||||
|
|
|
||||||
125
src/libthread/OpenBSD-power-asm.S
Normal file
125
src/libthread/OpenBSD-power-asm.S
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <machine/asm.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
ENTRY(_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
|
||||||
|
|
||||||
|
ENTRY(rfork_thread)
|
||||||
|
/* sanity check */
|
||||||
|
cmpwi %r4, 0
|
||||||
|
beq 1f
|
||||||
|
cmpwi %r5, 0
|
||||||
|
beq 1f
|
||||||
|
|
||||||
|
mr %r7,%r4
|
||||||
|
|
||||||
|
/* call rfork */
|
||||||
|
li %r0, SYS_rfork
|
||||||
|
sc
|
||||||
|
cmpwi %r0, 0
|
||||||
|
bne 2f
|
||||||
|
|
||||||
|
/* check if we are parent or child */
|
||||||
|
cmpwi %r3, 0
|
||||||
|
bnelr
|
||||||
|
|
||||||
|
/* child */
|
||||||
|
mtlr %r5 /* fp */
|
||||||
|
mr %r3, %r6 /* arg */
|
||||||
|
mr %r1, %r7 /* new sp */
|
||||||
|
blrl
|
||||||
|
|
||||||
|
/* child returned, call _exit */
|
||||||
|
li %r0, SYS_exit
|
||||||
|
sc
|
||||||
|
1:
|
||||||
|
li %r3, -1
|
||||||
|
2:
|
||||||
|
b PIC_PLT(_C_LABEL(__cerror))
|
||||||
|
|
||||||
38
src/libthread/OpenBSD-power.c
Normal file
38
src/libthread/OpenBSD-power.c
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#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
|
||||||
|
getcontext(ucontext_t *uc)
|
||||||
|
{
|
||||||
|
return _getmcontext(&uc->mc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
setcontext(ucontext_t *uc)
|
||||||
|
{
|
||||||
|
_setmcontext(&uc->mc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
swapcontext(ucontext_t *oucp, ucontext_t *ucp)
|
||||||
|
{
|
||||||
|
if(getcontext(oucp) == 0)
|
||||||
|
setcontext(ucp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
4
src/libthread/OpenBSD.c
Normal file
4
src/libthread/OpenBSD.c
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#include "threadimpl.h"
|
||||||
|
|
||||||
|
#include "BSD.c"
|
||||||
|
|
||||||
|
|
@ -15,6 +15,8 @@ OFILES=\
|
||||||
<$PLAN9/src/mksyslib
|
<$PLAN9/src/mksyslib
|
||||||
|
|
||||||
HFILES=thread.h threadimpl.h
|
HFILES=thread.h threadimpl.h
|
||||||
|
OpenBSD.$O FreeBSD.$O: BSD.c
|
||||||
|
NetBSD.$O: Linux.c
|
||||||
|
|
||||||
tprimes: tprimes.$O
|
tprimes: tprimes.$O
|
||||||
9l -o $target $target.$O $PLAN9/lib/$LIB -l9 -lpthread
|
9l -o $target $target.$O $PLAN9/lib/$LIB -l9 -lpthread
|
||||||
|
|
@ -24,9 +26,8 @@ tspawnloop: tspawnloop.$O
|
||||||
9l -o $target $target.$O $PLAN9/lib/$LIB -l9 -lpthread
|
9l -o $target $target.$O $PLAN9/lib/$LIB -l9 -lpthread
|
||||||
|
|
||||||
%.$O: %.c
|
%.$O: %.c
|
||||||
$CC -I. $stem.c
|
$CC $CFLAGS -I. $stem.c
|
||||||
|
|
||||||
NetBSD.$O: Linux.c
|
|
||||||
|
|
||||||
test:V: tprimes tspawn
|
test:V: tprimes tspawn
|
||||||
primes 1 10007 >p1.txt
|
primes 1 10007 >p1.txt
|
||||||
|
|
@ -40,5 +41,3 @@ test:V: tprimes tspawn
|
||||||
|
|
||||||
CLEANFILES=p1.txt p2.txt tp1.txt tp2.txt
|
CLEANFILES=p1.txt p2.txt tp1.txt tp2.txt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@ case "$tag" in
|
||||||
*-Darwin-*)
|
*-Darwin-*)
|
||||||
echo ${SYSNAME}-${OBJTYPE}-asm.o ${SYSNAME}-${OBJTYPE}.o pthread.o
|
echo ${SYSNAME}-${OBJTYPE}-asm.o ${SYSNAME}-${OBJTYPE}.o pthread.o
|
||||||
;;
|
;;
|
||||||
|
*-OpenBSD-*)
|
||||||
|
echo ${SYSNAME}-${OBJTYPE}-asm.o ${SYSNAME}-${OBJTYPE}.o $SYSNAME.o
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo pthread.o
|
echo pthread.o
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <ucontext.h>
|
#if !defined(_OpenBSD__)
|
||||||
|
# include <ucontext.h>
|
||||||
|
#endif
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include "libc.h"
|
#include "libc.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
@ -22,7 +24,12 @@ extern void makecontext(ucontext_t*, void(*)(), int, ...);
|
||||||
# define mcontext_t libthread_mcontext_t
|
# define mcontext_t libthread_mcontext_t
|
||||||
# define ucontext libthread_ucontext
|
# define ucontext libthread_ucontext
|
||||||
# define ucontext_t libthread_ucontext_t
|
# define ucontext_t libthread_ucontext_t
|
||||||
# include "Darwin-ucontext.h"
|
# include "power-ucontext.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__)
|
||||||
|
# include "power-ucontext.h"
|
||||||
|
extern pid_t rfork_thread(int, void*, int(*)(void*), void*);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct Context Context;
|
typedef struct Context Context;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue