Continue the pthreads torture.
This commit is contained in:
parent
3d5e34e146
commit
c6687d4591
25 changed files with 440 additions and 124 deletions
|
|
@ -1,3 +1,7 @@
|
|||
#include "ucontext.c"
|
||||
|
||||
#ifdef OLD
|
||||
|
||||
#include "threadimpl.h"
|
||||
/*
|
||||
* 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);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -241,15 +241,16 @@ threadread(int fd, void *a, long n)
|
|||
|
||||
threadfdnoblock(fd);
|
||||
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;
|
||||
nn = read(fd, a, n);
|
||||
if(nn <= 0){
|
||||
if(errno == EINTR)
|
||||
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
goto again;
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK){
|
||||
_threadfdwait(fd, 'r', getcallerpc(&fd));
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
return nn;
|
||||
}
|
||||
|
|
@ -261,14 +262,15 @@ threadrecvfd(int fd)
|
|||
|
||||
threadfdnoblock(fd);
|
||||
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);
|
||||
if(nn < 0){
|
||||
if(errno == EINTR)
|
||||
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
goto again;
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK){
|
||||
_threadfdwait(fd, 'r', getcallerpc(&fd));
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
return nn;
|
||||
}
|
||||
|
|
@ -280,14 +282,15 @@ threadsendfd(int fd, int sfd)
|
|||
|
||||
threadfdnoblock(fd);
|
||||
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);
|
||||
if(nn < 0){
|
||||
if(errno == EINTR)
|
||||
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
goto again;
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK){
|
||||
_threadfdwait(fd, 'w', getcallerpc(&fd));
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
return nn;
|
||||
}
|
||||
|
|
@ -315,14 +318,15 @@ _threadwrite(int fd, const void *a, long n)
|
|||
|
||||
threadfdnoblock(fd);
|
||||
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);
|
||||
if(nn < 0){
|
||||
if(errno == EINTR)
|
||||
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
goto again;
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK){
|
||||
_threadfdwait(fd, 'w', getcallerpc(&fd));
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
return nn;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,13 @@
|
|||
typedef struct Label Label;
|
||||
#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
|
||||
{
|
||||
ulong pc;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ main(int argc, char **argv)
|
|||
a->argc = argc;
|
||||
a->argv = argv;
|
||||
p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0);
|
||||
_schedinit(p);
|
||||
_scheduler(p);
|
||||
abort(); /* not reached */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ _schedfork(Proc *p)
|
|||
{
|
||||
int pid;
|
||||
lock(&p->lock);
|
||||
pid = ffork(RFMEM|RFNOWAIT, _schedinit, p);
|
||||
pid = ffork(RFMEM|RFNOWAIT, _scheduler, p);
|
||||
p->pid = pid;
|
||||
unlock(&p->lock);
|
||||
return pid;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <errno.h>
|
||||
#include "threadimpl.h"
|
||||
|
||||
//static Thread *runthread(Proc*);
|
||||
static Thread *runthread(Proc*);
|
||||
|
||||
static char *_psstate[] = {
|
||||
"Dead",
|
||||
|
|
@ -21,27 +21,54 @@ psstate(int s)
|
|||
}
|
||||
|
||||
void
|
||||
_schedinit(void *arg)
|
||||
needstack(int howmuch)
|
||||
{
|
||||
Proc *p;
|
||||
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;
|
||||
lock(&p->lock);
|
||||
p->pid = _threadgetpid();
|
||||
_threadsetproc(p);
|
||||
unlock(&p->lock);
|
||||
while(_setlabel(&p->sched))
|
||||
;
|
||||
_threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
|
||||
if(_threadexitsallstatus)
|
||||
_exits(_threadexitsallstatus);
|
||||
lock(&p->lock);
|
||||
if((t=p->thread) != nil){
|
||||
|
||||
for(;;){
|
||||
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 Moribund;
|
||||
}
|
||||
t->state = Running;
|
||||
t->nextstate = Ready;
|
||||
unlock(&p->lock);
|
||||
|
||||
_swaplabel(&p->sched, &t->sched);
|
||||
|
||||
lock(&p->lock);
|
||||
p->thread = nil;
|
||||
if(t->moribund){
|
||||
Moribund:
|
||||
if(t->moribund != 1)
|
||||
fprint(2, "moribund %d\n", t->moribund);
|
||||
assert(t->moribund == 1);
|
||||
|
|
@ -65,7 +92,8 @@ _schedinit(void *arg)
|
|||
free(t); /* XXX how do we know there are no references? */
|
||||
p->nthreads--;
|
||||
t = nil;
|
||||
_sched();
|
||||
lock(&p->lock);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
if(p->needexec){
|
||||
|
|
@ -78,15 +106,27 @@ _schedinit(void *arg)
|
|||
if(t->ret < 0){
|
||||
//fprint(2, "_schedfork: %r\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
p->newproc = nil;
|
||||
}
|
||||
t->state = t->nextstate;
|
||||
if(t->state == Ready)
|
||||
_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*
|
||||
|
|
@ -157,58 +197,6 @@ relock:
|
|||
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
|
||||
threadstack(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -167,8 +167,7 @@ struct Ioproc
|
|||
Ioproc *next;
|
||||
};
|
||||
|
||||
void _gotolabel(Label*);
|
||||
int _setlabel(Label*);
|
||||
void _swaplabel(Label*, Label*);
|
||||
void _freeproc(Proc*);
|
||||
Proc* _newproc(void(*)(void*), void*, uint, char*, int, int);
|
||||
int _procsplhi(void);
|
||||
|
|
@ -178,7 +177,7 @@ int _schedexec(Execargs*);
|
|||
void _schedexecwait(void);
|
||||
void _schedexit(Proc*);
|
||||
int _schedfork(Proc*);
|
||||
void _schedinit(void*);
|
||||
void _scheduler(void*);
|
||||
void _systhreadinit(void);
|
||||
void _threadassert(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");
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue