Continue the pthreads torture.
This commit is contained in:
parent
3d5e34e146
commit
c6687d4591
25 changed files with 440 additions and 124 deletions
|
|
@ -436,6 +436,7 @@ struct Lock
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern int _tas(int*);
|
||||||
extern void lock(Lock*);
|
extern void lock(Lock*);
|
||||||
extern void unlock(Lock*);
|
extern void unlock(Lock*);
|
||||||
extern int canlock(Lock*);
|
extern int canlock(Lock*);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ extern "C" {
|
||||||
#include <fmt.h>
|
#include <fmt.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <ctype.h> /* for tolower */
|
#include <ctype.h> /* for tolower */
|
||||||
#include <pthread.h> /* for Locks */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OS-specific crap
|
* OS-specific crap
|
||||||
|
|
@ -42,8 +41,10 @@ typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
|
||||||
# undef _NEEDUSHORT
|
# undef _NEEDUSHORT
|
||||||
# undef _NEEDUINT
|
# undef _NEEDUINT
|
||||||
# undef _NEEDULONG
|
# undef _NEEDULONG
|
||||||
# include <pthread.h>
|
# endif
|
||||||
# define PLAN9_PTHREADS
|
# if defined(__Linux26__)
|
||||||
|
# include <pthread.h>
|
||||||
|
# define PLAN9_PTHREADS 1
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#if defined(__sun__)
|
#if defined(__sun__)
|
||||||
|
|
|
||||||
|
|
@ -884,12 +884,8 @@ key(Rune r)
|
||||||
case 0x7F: /* DEL: send interrupt */
|
case 0x7F: /* DEL: send interrupt */
|
||||||
t.qh = t.q0 = t.q1 = t.nr;
|
t.qh = t.q0 = t.q1 = t.nr;
|
||||||
show(t.q0);
|
show(t.q0);
|
||||||
{int x; x=tcgetpgrp(rcfd);
|
// postnote(PNGROUP, x, "interrupt");
|
||||||
print("postnote %d pgrp %d\n", rcpid, x);
|
write(rcfd, "\x7F", 1);
|
||||||
postnote(PNGROUP, x, "interrupt");
|
|
||||||
if(x >= 2) killpg(x, 2);
|
|
||||||
}
|
|
||||||
// write(rcfd, "\x7F", 1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,25 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include "term.h"
|
#include "term.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
sys(char *buf)
|
||||||
|
{
|
||||||
|
char buf2[100];
|
||||||
|
char *f[20];
|
||||||
|
int nf, pid;
|
||||||
|
|
||||||
|
strcpy(buf2, buf);
|
||||||
|
nf = tokenize(buf2, f, nelem(f));
|
||||||
|
f[nf] = nil;
|
||||||
|
switch(pid = fork()){
|
||||||
|
case 0:
|
||||||
|
execvp(f[0], f);
|
||||||
|
_exits("oops");
|
||||||
|
default:
|
||||||
|
waitpid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rcstart(int argc, char **argv, int *pfd, int *tfd)
|
rcstart(int argc, char **argv, int *pfd, int *tfd)
|
||||||
{
|
{
|
||||||
|
|
@ -33,11 +52,14 @@ rcstart(int argc, char **argv, int *pfd, int *tfd)
|
||||||
dup(sfd, 0);
|
dup(sfd, 0);
|
||||||
dup(sfd, 1);
|
dup(sfd, 1);
|
||||||
dup(sfd, 2);
|
dup(sfd, 2);
|
||||||
system("stty tabs -onlcr onocr icanon echo erase '^h' intr '^?'");
|
sys("stty tabs -onlcr onocr icanon echo erase '^h' intr '^?'");
|
||||||
if(noecho)
|
if(noecho)
|
||||||
system("stty -echo");
|
sys("stty -echo");
|
||||||
for(i=3; i<100; i++)
|
for(i=3; i<100; i++)
|
||||||
close(i);
|
close(i);
|
||||||
|
signal(SIGINT, SIG_DFL);
|
||||||
|
signal(SIGHUP, SIG_DFL);
|
||||||
|
signal(SIGTERM, SIG_DFL);
|
||||||
execvp(argv[0], argv);
|
execvp(argv[0], argv);
|
||||||
fprint(2, "exec %s failed: %r\n", argv[0]);
|
fprint(2, "exec %s failed: %r\n", argv[0]);
|
||||||
_exits("oops");
|
_exits("oops");
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,6 @@ struct Uproc
|
||||||
int pid;
|
int pid;
|
||||||
int state;
|
int state;
|
||||||
void *priv[NPRIV];
|
void *priv[NPRIV];
|
||||||
ulong rendval;
|
|
||||||
ulong rendtag;
|
|
||||||
Uproc *rendhash;
|
|
||||||
p9jmp_buf notejb;
|
p9jmp_buf notejb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
5
src/lib9/_p9proc-Linux.c
Normal file
5
src/lib9/_p9proc-Linux.c
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#ifdef __Linux26__
|
||||||
|
#include "_p9proc-pthread.c"
|
||||||
|
#else
|
||||||
|
#include "_p9proc-getpid.c"
|
||||||
|
#endif
|
||||||
113
src/lib9/_p9proc-getpid.c
Normal file
113
src/lib9/_p9proc-getpid.c
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* This needs to be callable from a signal handler, so it has been
|
||||||
|
* written to avoid locks. The only lock is the one used to acquire
|
||||||
|
* an entry in the table, and we make sure that acquiring is done
|
||||||
|
* when not in a handler. Lookup and delete do not need locks.
|
||||||
|
* It's a scan-forward hash table. To avoid breaking chains,
|
||||||
|
* T ((void*)-1) is used as a non-breaking nil.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include "9proc.h"
|
||||||
|
|
||||||
|
enum { PIDHASH = 1021 };
|
||||||
|
|
||||||
|
#define T ((void*)-1)
|
||||||
|
static Uproc *alluproc[PIDHASH];
|
||||||
|
static int allupid[PIDHASH];
|
||||||
|
static Lock uproclock;
|
||||||
|
|
||||||
|
void
|
||||||
|
_clearuproc(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* called right after fork - no locking needed */
|
||||||
|
for(i=0; i<PIDHASH; i++)
|
||||||
|
if(alluproc[i] != T && alluproc[i] != 0)
|
||||||
|
free(alluproc[i]);
|
||||||
|
memset(alluproc, 0, sizeof alluproc);
|
||||||
|
memset(allupid, 0, sizeof allupid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uproc*
|
||||||
|
_p9uproc(int inhandler)
|
||||||
|
{
|
||||||
|
int i, h, pid;
|
||||||
|
Uproc *up;
|
||||||
|
|
||||||
|
/* for now, assume getpid is fast or cached */
|
||||||
|
pid = getpid();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this part - the lookup - needs to run without locks
|
||||||
|
* so that it can safely be called from within the notify handler.
|
||||||
|
* notify calls _p9uproc, and fork and rfork call _p9uproc
|
||||||
|
* in both parent and child, so if we're in a signal handler,
|
||||||
|
* we should find something in the table.
|
||||||
|
*/
|
||||||
|
h = pid%PIDHASH;
|
||||||
|
for(i=0; i<PIDHASH; i++){
|
||||||
|
up = alluproc[h];
|
||||||
|
if(up == nil)
|
||||||
|
break;
|
||||||
|
if(allupid[h] == pid)
|
||||||
|
return up;
|
||||||
|
if(++h == PIDHASH)
|
||||||
|
h = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(inhandler){
|
||||||
|
fprint(2, "%s: did not find uproc for pid %d in signal handler\n", argv0, pid);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* need to allocate */
|
||||||
|
while((up = mallocz(sizeof(Uproc), 1)) == nil)
|
||||||
|
sleep(1000);
|
||||||
|
|
||||||
|
/* fprint(2, "alloc uproc for pid %d\n", pid); */
|
||||||
|
up->pid = pid;
|
||||||
|
lock(&uproclock);
|
||||||
|
h = pid%PIDHASH;
|
||||||
|
for(i=0; i<PIDHASH; i++){
|
||||||
|
if(alluproc[h]==T || alluproc[h]==nil){
|
||||||
|
alluproc[h] = up;
|
||||||
|
allupid[h] = pid;
|
||||||
|
unlock(&uproclock);
|
||||||
|
return up;
|
||||||
|
}
|
||||||
|
if(++h == PIDHASH)
|
||||||
|
h = 0;
|
||||||
|
}
|
||||||
|
unlock(&uproclock);
|
||||||
|
|
||||||
|
/* out of pids! */
|
||||||
|
sysfatal("too many processes in uproc table");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_p9uprocdie(void)
|
||||||
|
{
|
||||||
|
Uproc *up;
|
||||||
|
int pid, i, h;
|
||||||
|
|
||||||
|
pid = getpid();
|
||||||
|
/* fprint(2, "reap uproc for pid %d\n", pid); */
|
||||||
|
h = pid%PIDHASH;
|
||||||
|
for(i=0; i<PIDHASH; i++){
|
||||||
|
up = alluproc[h];
|
||||||
|
if(up == nil)
|
||||||
|
break;
|
||||||
|
if(up == T)
|
||||||
|
continue;
|
||||||
|
if(allupid[h] == pid){
|
||||||
|
up = alluproc[h];
|
||||||
|
alluproc[h] = T;
|
||||||
|
free(up);
|
||||||
|
allupid[h] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include "9proc.h"
|
#include "9proc.h"
|
||||||
#undef fork
|
#undef fork
|
||||||
|
|
@ -7,9 +8,15 @@ int
|
||||||
p9fork(void)
|
p9fork(void)
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
sigset_t all, old;
|
||||||
|
|
||||||
|
sigfillset(&all);
|
||||||
|
sigprocmask(SIG_SETMASK, &all, &old);
|
||||||
pid = fork();
|
pid = fork();
|
||||||
_clearuproc();
|
if(pid == 0){
|
||||||
_p9uproc(0);
|
_clearuproc();
|
||||||
|
_p9uproc(0);
|
||||||
|
}
|
||||||
|
sigprocmask(SIG_SETMASK, &old, nil);
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
src/lib9/lock-Darwin.c
Normal file
1
src/lib9/lock-Darwin.c
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "lock-pthread.c"
|
||||||
1
src/lib9/lock-FreeBSD.c
Normal file
1
src/lib9/lock-FreeBSD.c
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "lock-tas.c"
|
||||||
5
src/lib9/lock-Linux.c
Normal file
5
src/lib9/lock-Linux.c
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#ifdef __Linux26__
|
||||||
|
#include "lock-pthread.c"
|
||||||
|
#else
|
||||||
|
#include "lock-tas.c"
|
||||||
|
#endif
|
||||||
54
src/lib9/lock-pthread.c
Normal file
54
src/lib9/lock-pthread.c
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static void
|
||||||
|
lockinit(Lock *lk)
|
||||||
|
{
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&initmutex);
|
||||||
|
if(lk->init == 0){
|
||||||
|
pthread_mutexattr_init(&attr);
|
||||||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||||
|
pthread_mutex_init(&lk->mutex, &attr);
|
||||||
|
pthread_mutexattr_destroy(&attr);
|
||||||
|
lk->init = 1;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&initmutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lock(Lock *lk)
|
||||||
|
{
|
||||||
|
if(!lk->init)
|
||||||
|
lockinit(lk);
|
||||||
|
if(pthread_mutex_lock(&lk->mutex) != 0)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
canlock(Lock *lk)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(!lk->init)
|
||||||
|
lockinit(lk);
|
||||||
|
r = pthread_mutex_trylock(&lk->mutex);
|
||||||
|
if(r == 0)
|
||||||
|
return 1;
|
||||||
|
if(r == EBUSY)
|
||||||
|
return 0;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unlock(Lock *lk)
|
||||||
|
{
|
||||||
|
if(pthread_mutex_unlock(&lk->mutex) != 0)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
57
src/lib9/lock-tas.c
Normal file
57
src/lib9/lock-tas.c
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
int _ntas;
|
||||||
|
static int
|
||||||
|
_xtas(void *v)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
_ntas++;
|
||||||
|
x = _tas(v);
|
||||||
|
if(x != 0 && x != 0xcafebabe){
|
||||||
|
print("bad tas value %d\n", x);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
canlock(Lock *l)
|
||||||
|
{
|
||||||
|
return !_xtas(&l->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unlock(Lock *l)
|
||||||
|
{
|
||||||
|
l->val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lock(Lock *lk)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* once fast */
|
||||||
|
if(!_xtas(&lk->val))
|
||||||
|
return;
|
||||||
|
/* a thousand times pretty fast */
|
||||||
|
for(i=0; i<1000; i++){
|
||||||
|
if(!_xtas(&lk->val))
|
||||||
|
return;
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
/* now nice and slow */
|
||||||
|
for(i=0; i<1000; i++){
|
||||||
|
if(!_xtas(&lk->val))
|
||||||
|
return;
|
||||||
|
usleep(100*1000);
|
||||||
|
}
|
||||||
|
/* take your time */
|
||||||
|
while(_xtas(&lk->val))
|
||||||
|
usleep(1000*1000);
|
||||||
|
}
|
||||||
|
|
@ -67,7 +67,7 @@ LIB9OFILES=\
|
||||||
_exits.$O\
|
_exits.$O\
|
||||||
_p9dialparse.$O\
|
_p9dialparse.$O\
|
||||||
_p9dir.$O\
|
_p9dir.$O\
|
||||||
_p9proc.$O\
|
_p9proc-$SYSNAME.$O\
|
||||||
announce.$O\
|
announce.$O\
|
||||||
argv0.$O\
|
argv0.$O\
|
||||||
atexit.$O\
|
atexit.$O\
|
||||||
|
|
@ -111,7 +111,7 @@ LIB9OFILES=\
|
||||||
jmp.$O\
|
jmp.$O\
|
||||||
lrand.$O\
|
lrand.$O\
|
||||||
lnrand.$O\
|
lnrand.$O\
|
||||||
lock.$O\
|
lock-$SYSNAME.$O\
|
||||||
main.$O\
|
main.$O\
|
||||||
malloc.$O\
|
malloc.$O\
|
||||||
malloctag.$O\
|
malloctag.$O\
|
||||||
|
|
@ -141,6 +141,7 @@ LIB9OFILES=\
|
||||||
strecpy.$O\
|
strecpy.$O\
|
||||||
sysfatal.$O\
|
sysfatal.$O\
|
||||||
sysname.$O\
|
sysname.$O\
|
||||||
|
tas-$OBJTYPE.$O\
|
||||||
time.$O\
|
time.$O\
|
||||||
tokenize.$O\
|
tokenize.$O\
|
||||||
truerand.$O\
|
truerand.$O\
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ enum
|
||||||
|
|
||||||
static void (*procsleep)(_Procrend*) = _procsleep;
|
static void (*procsleep)(_Procrend*) = _procsleep;
|
||||||
static void (*procwakeup)(_Procrend*) = _procwakeup;
|
static void (*procwakeup)(_Procrend*) = _procwakeup;
|
||||||
|
#define _procsleep donotcall_procsleep
|
||||||
|
#define _procwakeup donotcall_procwakeup
|
||||||
|
|
||||||
/* this gets called by the thread library ONLY to get us to use its rendezvous */
|
/* this gets called by the thread library ONLY to get us to use its rendezvous */
|
||||||
void
|
void
|
||||||
|
|
@ -73,7 +75,7 @@ qlock(QLock *q)
|
||||||
q->tail = mp;
|
q->tail = mp;
|
||||||
mp->state = Queuing;
|
mp->state = Queuing;
|
||||||
mp->rend.l = &q->lock;
|
mp->rend.l = &q->lock;
|
||||||
_procsleep(&mp->rend);
|
procsleep(&mp->rend);
|
||||||
unlock(&q->lock);
|
unlock(&q->lock);
|
||||||
assert(mp->state == Waking);
|
assert(mp->state == Waking);
|
||||||
unlock(&mp->inuse);
|
unlock(&mp->inuse);
|
||||||
|
|
@ -92,7 +94,7 @@ qunlock(QLock *q)
|
||||||
if(q->head == nil)
|
if(q->head == nil)
|
||||||
q->tail = nil;
|
q->tail = nil;
|
||||||
p->state = Waking;
|
p->state = Waking;
|
||||||
_procwakeup(&p->rend);
|
procwakeup(&p->rend);
|
||||||
unlock(&q->lock);
|
unlock(&q->lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +139,7 @@ rlock(RWLock *q)
|
||||||
mp->next = nil;
|
mp->next = nil;
|
||||||
mp->state = QueuingR;
|
mp->state = QueuingR;
|
||||||
mp->rend.l = &q->lock;
|
mp->rend.l = &q->lock;
|
||||||
_procsleep(&mp->rend);
|
procsleep(&mp->rend);
|
||||||
unlock(&q->lock);
|
unlock(&q->lock);
|
||||||
assert(mp->state == Waking);
|
assert(mp->state == Waking);
|
||||||
unlock(&mp->inuse);
|
unlock(&mp->inuse);
|
||||||
|
|
@ -181,7 +183,7 @@ runlock(RWLock *q)
|
||||||
|
|
||||||
/* wakeup waiter */
|
/* wakeup waiter */
|
||||||
p->state = Waking;
|
p->state = Waking;
|
||||||
_procwakeup(&p->rend);
|
procwakeup(&p->rend);
|
||||||
unlock(&q->lock);
|
unlock(&q->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,7 +213,7 @@ wlock(RWLock *q)
|
||||||
|
|
||||||
/* wait in kernel */
|
/* wait in kernel */
|
||||||
mp->rend.l = &q->lock;
|
mp->rend.l = &q->lock;
|
||||||
_procsleep(&mp->rend);
|
procsleep(&mp->rend);
|
||||||
unlock(&q->lock);
|
unlock(&q->lock);
|
||||||
assert(mp->state == Waking);
|
assert(mp->state == Waking);
|
||||||
unlock(&mp->inuse);
|
unlock(&mp->inuse);
|
||||||
|
|
@ -253,7 +255,7 @@ wunlock(RWLock *q)
|
||||||
if(q->head == nil)
|
if(q->head == nil)
|
||||||
q->tail = nil;
|
q->tail = nil;
|
||||||
p->state = Waking;
|
p->state = Waking;
|
||||||
_procwakeup(&p->rend);
|
procwakeup(&p->rend);
|
||||||
unlock(&q->lock);
|
unlock(&q->lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +271,7 @@ wunlock(RWLock *q)
|
||||||
q->head = p->next;
|
q->head = p->next;
|
||||||
q->readers++;
|
q->readers++;
|
||||||
p->state = Waking;
|
p->state = Waking;
|
||||||
_procwakeup(&p->rend);
|
procwakeup(&p->rend);
|
||||||
}
|
}
|
||||||
if(q->head == nil)
|
if(q->head == nil)
|
||||||
q->tail = nil;
|
q->tail = nil;
|
||||||
|
|
@ -310,20 +312,20 @@ rsleep(Rendez *r)
|
||||||
if(r->l->head == nil)
|
if(r->l->head == nil)
|
||||||
r->l->tail = nil;
|
r->l->tail = nil;
|
||||||
t->state = Waking;
|
t->state = Waking;
|
||||||
_procwakeup(&t->rend);
|
procwakeup(&t->rend);
|
||||||
}else
|
}else
|
||||||
r->l->locked = 0;
|
r->l->locked = 0;
|
||||||
|
|
||||||
/* wait for a wakeup */
|
/* wait for a wakeup */
|
||||||
me->rend.l = &r->l->lock;
|
me->rend.l = &r->l->lock;
|
||||||
_procsleep(&me->rend);
|
procsleep(&me->rend);
|
||||||
|
|
||||||
assert(me->state == Waking);
|
assert(me->state == Waking);
|
||||||
unlock(&me->inuse);
|
unlock(&me->inuse);
|
||||||
if(!r->l->locked){
|
if(!r->l->locked){
|
||||||
fprint(2, "rsleep: not locked after wakeup\n");
|
fprint(2, "rsleep: not locked after wakeup\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
unlock(&r->l->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ _procsleep(_Procrend *r)
|
||||||
*/
|
*/
|
||||||
ignusr1(1);
|
ignusr1(1);
|
||||||
assert(r->asleep == 0);
|
assert(r->asleep == 0);
|
||||||
|
lock(r->l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,9 @@ muxrpc(Mux *mux, void *tx)
|
||||||
enqueue(mux, r);
|
enqueue(mux, r);
|
||||||
|
|
||||||
/* wait for our packet */
|
/* wait for our packet */
|
||||||
while(mux->muxer && !r->p)
|
while(mux->muxer && !r->p){
|
||||||
rsleep(&r->r);
|
rsleep(&r->r);
|
||||||
|
}
|
||||||
|
|
||||||
/* if not done, there's no muxer: start muxing */
|
/* if not done, there's no muxer: start muxing */
|
||||||
if(!r->p){
|
if(!r->p){
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
#include "ucontext.c"
|
||||||
|
|
||||||
|
#ifdef OLD
|
||||||
|
|
||||||
#include "threadimpl.h"
|
#include "threadimpl.h"
|
||||||
/*
|
/*
|
||||||
* To use this you need some patches to Valgrind that
|
* To use this you need some patches to Valgrind that
|
||||||
|
|
@ -55,3 +59,4 @@ _threadstacklimit(void *bottom, void *top)
|
||||||
VALGRIND_SET_STACK_LIMIT(1, bottom, top);
|
VALGRIND_SET_STACK_LIMIT(1, bottom, top);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -241,15 +241,16 @@ threadread(int fd, void *a, long n)
|
||||||
|
|
||||||
threadfdnoblock(fd);
|
threadfdnoblock(fd);
|
||||||
again:
|
again:
|
||||||
|
/*
|
||||||
|
* Always call wait (i.e. don't optimistically try the read)
|
||||||
|
* so that the scheduler gets a chance to run other threads.
|
||||||
|
*/
|
||||||
|
_threadfdwait(fd, 'r', getcallerpc(&fd));
|
||||||
errno = 0;
|
errno = 0;
|
||||||
nn = read(fd, a, n);
|
nn = read(fd, a, n);
|
||||||
if(nn <= 0){
|
if(nn <= 0){
|
||||||
if(errno == EINTR)
|
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
goto again;
|
goto again;
|
||||||
if(errno == EAGAIN || errno == EWOULDBLOCK){
|
|
||||||
_threadfdwait(fd, 'r', getcallerpc(&fd));
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nn;
|
return nn;
|
||||||
}
|
}
|
||||||
|
|
@ -261,14 +262,15 @@ threadrecvfd(int fd)
|
||||||
|
|
||||||
threadfdnoblock(fd);
|
threadfdnoblock(fd);
|
||||||
again:
|
again:
|
||||||
|
/*
|
||||||
|
* Always call wait (i.e. don't optimistically try the recvfd)
|
||||||
|
* so that the scheduler gets a chance to run other threads.
|
||||||
|
*/
|
||||||
|
_threadfdwait(fd, 'r', getcallerpc(&fd));
|
||||||
nn = recvfd(fd);
|
nn = recvfd(fd);
|
||||||
if(nn < 0){
|
if(nn < 0){
|
||||||
if(errno == EINTR)
|
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
goto again;
|
goto again;
|
||||||
if(errno == EAGAIN || errno == EWOULDBLOCK){
|
|
||||||
_threadfdwait(fd, 'r', getcallerpc(&fd));
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nn;
|
return nn;
|
||||||
}
|
}
|
||||||
|
|
@ -280,14 +282,15 @@ threadsendfd(int fd, int sfd)
|
||||||
|
|
||||||
threadfdnoblock(fd);
|
threadfdnoblock(fd);
|
||||||
again:
|
again:
|
||||||
|
/*
|
||||||
|
* Always call wait (i.e. don't optimistically try the sendfd)
|
||||||
|
* so that the scheduler gets a chance to run other threads.
|
||||||
|
*/
|
||||||
|
_threadfdwait(fd, 'w', getcallerpc(&fd));
|
||||||
nn = sendfd(fd, sfd);
|
nn = sendfd(fd, sfd);
|
||||||
if(nn < 0){
|
if(nn < 0){
|
||||||
if(errno == EINTR)
|
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
goto again;
|
goto again;
|
||||||
if(errno == EAGAIN || errno == EWOULDBLOCK){
|
|
||||||
_threadfdwait(fd, 'w', getcallerpc(&fd));
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nn;
|
return nn;
|
||||||
}
|
}
|
||||||
|
|
@ -315,14 +318,15 @@ _threadwrite(int fd, const void *a, long n)
|
||||||
|
|
||||||
threadfdnoblock(fd);
|
threadfdnoblock(fd);
|
||||||
again:
|
again:
|
||||||
|
/*
|
||||||
|
* Always call wait (i.e. don't optimistically try the write)
|
||||||
|
* so that the scheduler gets a chance to run other threads.
|
||||||
|
*/
|
||||||
|
_threadfdwait(fd, 'w', getcallerpc(&fd));
|
||||||
nn = write(fd, a, n);
|
nn = write(fd, a, n);
|
||||||
if(nn < 0){
|
if(nn < 0){
|
||||||
if(errno == EINTR)
|
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
goto again;
|
goto again;
|
||||||
if(errno == EAGAIN || errno == EWOULDBLOCK){
|
|
||||||
_threadfdwait(fd, 'w', getcallerpc(&fd));
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nn;
|
return nn;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,13 @@
|
||||||
typedef struct Label Label;
|
typedef struct Label Label;
|
||||||
#define LABELDPC 0
|
#define LABELDPC 0
|
||||||
|
|
||||||
#if defined (__i386__) && (defined(__FreeBSD__) || defined(__linux__) || defined(__OpenBSD__))
|
#if defined(__linux__)
|
||||||
|
#include <ucontext.h>
|
||||||
|
struct Label
|
||||||
|
{
|
||||||
|
ucontext_t uc;
|
||||||
|
};
|
||||||
|
#elif defined (__i386__) && (defined(__FreeBSD__) || defined(__linux__) || defined(__OpenBSD__))
|
||||||
struct Label
|
struct Label
|
||||||
{
|
{
|
||||||
ulong pc;
|
ulong pc;
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ main(int argc, char **argv)
|
||||||
a->argc = argc;
|
a->argc = argc;
|
||||||
a->argv = argv;
|
a->argv = argv;
|
||||||
p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0);
|
p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0);
|
||||||
_schedinit(p);
|
_scheduler(p);
|
||||||
abort(); /* not reached */
|
abort(); /* not reached */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +80,7 @@ _schedfork(Proc *p)
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
lock(&p->lock);
|
lock(&p->lock);
|
||||||
pid = ffork(RFMEM|RFNOWAIT, _schedinit, p);
|
pid = ffork(RFMEM|RFNOWAIT, _scheduler, p);
|
||||||
p->pid = pid;
|
p->pid = pid;
|
||||||
unlock(&p->lock);
|
unlock(&p->lock);
|
||||||
return pid;
|
return pid;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "threadimpl.h"
|
#include "threadimpl.h"
|
||||||
|
|
||||||
//static Thread *runthread(Proc*);
|
static Thread *runthread(Proc*);
|
||||||
|
|
||||||
static char *_psstate[] = {
|
static char *_psstate[] = {
|
||||||
"Dead",
|
"Dead",
|
||||||
|
|
@ -21,27 +21,54 @@ psstate(int s)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_schedinit(void *arg)
|
needstack(int howmuch)
|
||||||
{
|
{
|
||||||
Proc *p;
|
Proc *p;
|
||||||
Thread *t;
|
Thread *t;
|
||||||
extern void ignusr1(int), _threaddie(int);
|
|
||||||
signal(SIGTERM, _threaddie);
|
p = _threadgetproc();
|
||||||
|
if(p == nil || (t=p->thread) == nil)
|
||||||
|
return;
|
||||||
|
if((ulong)&howmuch < (ulong)t->stk+howmuch){ /* stack overflow waiting to happen */
|
||||||
|
fprint(2, "stack overflow: stack at 0x%lux, limit at 0x%lux, need 0x%lux\n", (ulong)&p, (ulong)t->stk, howmuch);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_scheduler(void *arg)
|
||||||
|
{
|
||||||
|
Proc *p;
|
||||||
|
Thread *t;
|
||||||
|
|
||||||
p = arg;
|
p = arg;
|
||||||
lock(&p->lock);
|
lock(&p->lock);
|
||||||
p->pid = _threadgetpid();
|
p->pid = _threadgetpid();
|
||||||
_threadsetproc(p);
|
_threadsetproc(p);
|
||||||
unlock(&p->lock);
|
|
||||||
while(_setlabel(&p->sched))
|
for(;;){
|
||||||
;
|
t = runthread(p);
|
||||||
_threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
|
if(t == nil){
|
||||||
if(_threadexitsallstatus)
|
_threaddebug(DBGSCHED, "all threads gone; exiting");
|
||||||
_exits(_threadexitsallstatus);
|
_threaddelproc();
|
||||||
lock(&p->lock);
|
_schedexit(p);
|
||||||
if((t=p->thread) != nil){
|
}
|
||||||
|
_threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
|
||||||
|
p->thread = t;
|
||||||
|
if(t->moribund){
|
||||||
|
_threaddebug(DBGSCHED, "%d.%d marked to die");
|
||||||
|
goto Moribund;
|
||||||
|
}
|
||||||
|
t->state = Running;
|
||||||
|
t->nextstate = Ready;
|
||||||
|
unlock(&p->lock);
|
||||||
|
|
||||||
|
_swaplabel(&p->sched, &t->sched);
|
||||||
|
|
||||||
|
lock(&p->lock);
|
||||||
p->thread = nil;
|
p->thread = nil;
|
||||||
if(t->moribund){
|
if(t->moribund){
|
||||||
|
Moribund:
|
||||||
if(t->moribund != 1)
|
if(t->moribund != 1)
|
||||||
fprint(2, "moribund %d\n", t->moribund);
|
fprint(2, "moribund %d\n", t->moribund);
|
||||||
assert(t->moribund == 1);
|
assert(t->moribund == 1);
|
||||||
|
|
@ -65,7 +92,8 @@ _schedinit(void *arg)
|
||||||
free(t); /* XXX how do we know there are no references? */
|
free(t); /* XXX how do we know there are no references? */
|
||||||
p->nthreads--;
|
p->nthreads--;
|
||||||
t = nil;
|
t = nil;
|
||||||
_sched();
|
lock(&p->lock);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if(p->needexec){
|
if(p->needexec){
|
||||||
|
|
@ -78,15 +106,27 @@ _schedinit(void *arg)
|
||||||
if(t->ret < 0){
|
if(t->ret < 0){
|
||||||
//fprint(2, "_schedfork: %r\n");
|
//fprint(2, "_schedfork: %r\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
p->newproc = nil;
|
p->newproc = nil;
|
||||||
}
|
}
|
||||||
t->state = t->nextstate;
|
t->state = t->nextstate;
|
||||||
if(t->state == Ready)
|
if(t->state == Ready)
|
||||||
_threadready(t);
|
_threadready(t);
|
||||||
|
unlock(&p->lock);
|
||||||
}
|
}
|
||||||
unlock(&p->lock);
|
}
|
||||||
_sched();
|
|
||||||
|
int
|
||||||
|
_sched(void)
|
||||||
|
{
|
||||||
|
Proc *p;
|
||||||
|
Thread *t;
|
||||||
|
|
||||||
|
p = _threadgetproc();
|
||||||
|
t = p->thread;
|
||||||
|
assert(t != nil);
|
||||||
|
_swaplabel(&t->sched, &p->sched);
|
||||||
|
return p->nsched++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Thread*
|
static Thread*
|
||||||
|
|
@ -157,58 +197,6 @@ relock:
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
needstack(int howmuch)
|
|
||||||
{
|
|
||||||
Proc *p;
|
|
||||||
Thread *t;
|
|
||||||
|
|
||||||
p = _threadgetproc();
|
|
||||||
if(p == nil || (t=p->thread) == nil)
|
|
||||||
return;
|
|
||||||
if((ulong)&howmuch < (ulong)t->stk+howmuch){ /* stack overflow waiting to happen */
|
|
||||||
fprint(2, "stack overflow: stack at 0x%lux, limit at 0x%lux, need 0x%lux\n", (ulong)&p, (ulong)t->stk, howmuch);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
_sched(void)
|
|
||||||
{
|
|
||||||
Proc *p;
|
|
||||||
Thread *t;
|
|
||||||
|
|
||||||
Resched:
|
|
||||||
p = _threadgetproc();
|
|
||||||
//fprint(2, "p %p\n", p);
|
|
||||||
if((t = p->thread) != nil){
|
|
||||||
needstack(512);
|
|
||||||
// _threaddebug(DBGSCHED, "pausing, state=%s set %p goto %p",
|
|
||||||
// psstate(t->state), &t->sched, &p->sched);
|
|
||||||
if(_setlabel(&t->sched)==0)
|
|
||||||
_gotolabel(&p->sched);
|
|
||||||
_threadstacklimit(t->stk, t->stk+t->stksize);
|
|
||||||
return p->nsched++;
|
|
||||||
}else{
|
|
||||||
t = runthread(p);
|
|
||||||
if(t == nil){
|
|
||||||
_threaddebug(DBGSCHED, "all threads gone; exiting");
|
|
||||||
_threaddelproc();
|
|
||||||
_schedexit(p);
|
|
||||||
}
|
|
||||||
_threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
|
|
||||||
p->thread = t;
|
|
||||||
if(t->moribund){
|
|
||||||
_threaddebug(DBGSCHED, "%d.%d marked to die");
|
|
||||||
goto Resched;
|
|
||||||
}
|
|
||||||
t->state = Running;
|
|
||||||
t->nextstate = Ready;
|
|
||||||
_gotolabel(&t->sched);
|
|
||||||
for(;;);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long
|
long
|
||||||
threadstack(void)
|
threadstack(void)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -167,8 +167,7 @@ struct Ioproc
|
||||||
Ioproc *next;
|
Ioproc *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
void _gotolabel(Label*);
|
void _swaplabel(Label*, Label*);
|
||||||
int _setlabel(Label*);
|
|
||||||
void _freeproc(Proc*);
|
void _freeproc(Proc*);
|
||||||
Proc* _newproc(void(*)(void*), void*, uint, char*, int, int);
|
Proc* _newproc(void(*)(void*), void*, uint, char*, int, int);
|
||||||
int _procsplhi(void);
|
int _procsplhi(void);
|
||||||
|
|
@ -178,7 +177,7 @@ int _schedexec(Execargs*);
|
||||||
void _schedexecwait(void);
|
void _schedexecwait(void);
|
||||||
void _schedexit(Proc*);
|
void _schedexit(Proc*);
|
||||||
int _schedfork(Proc*);
|
int _schedfork(Proc*);
|
||||||
void _schedinit(void*);
|
void _scheduler(void*);
|
||||||
void _systhreadinit(void);
|
void _systhreadinit(void);
|
||||||
void _threadassert(char*);
|
void _threadassert(char*);
|
||||||
void __threaddebug(ulong, char*, ...);
|
void __threaddebug(ulong, char*, ...);
|
||||||
|
|
|
||||||
41
src/libthread/ucontext.c
Normal file
41
src/libthread/ucontext.c
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#include "threadimpl.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
_threadinitstack(Thread *t, void (*f)(void*), void *arg)
|
||||||
|
{
|
||||||
|
sigset_t zero;
|
||||||
|
|
||||||
|
/* do a reasonable initialization */
|
||||||
|
memset(&t->sched.uc, 0, sizeof t->sched.uc);
|
||||||
|
sigemptyset(&zero);
|
||||||
|
sigprocmask(SIG_BLOCK, &zero, &t->sched.uc.uc_sigmask);
|
||||||
|
|
||||||
|
/* call getcontext, because on Linux makecontext neglects floating point */
|
||||||
|
getcontext(&t->sched.uc);
|
||||||
|
|
||||||
|
/* call makecontext to do the real work. */
|
||||||
|
t->sched.uc.uc_stack.ss_sp = t->stk;
|
||||||
|
t->sched.uc.uc_stack.ss_size = t->stksize;
|
||||||
|
makecontext(&t->sched.uc, (void(*)())f, 1, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_threadinswitch(int enter)
|
||||||
|
{
|
||||||
|
USED(enter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_threadstacklimit(void *bottom, void *top)
|
||||||
|
{
|
||||||
|
USED(bottom);
|
||||||
|
USED(top);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_swaplabel(Label *old, Label *new)
|
||||||
|
{
|
||||||
|
if(swapcontext(&old->uc, &new->uc) < 0)
|
||||||
|
sysfatal("swapcontext: %r");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -9,6 +9,14 @@ DIRS=\
|
||||||
|
|
||||||
<mkdirs
|
<mkdirs
|
||||||
|
|
||||||
|
libs:V: libs-all
|
||||||
|
|
||||||
|
libs-%:V:
|
||||||
|
for i in $LIBDIRS
|
||||||
|
do
|
||||||
|
(cd $i; mk $stem)
|
||||||
|
done
|
||||||
|
|
||||||
MKDIRS=\
|
MKDIRS=\
|
||||||
libbio\
|
libbio\
|
||||||
libregexp\
|
libregexp\
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue