diff options
Diffstat (limited to 'src/libthread')
-rw-r--r-- | src/libthread/386.c | 5 | ||||
-rw-r--r-- | src/libthread/fdwait.c | 44 | ||||
-rw-r--r-- | src/libthread/label.h | 8 | ||||
-rw-r--r-- | src/libthread/main.c | 4 | ||||
-rw-r--r-- | src/libthread/sched.c | 126 | ||||
-rw-r--r-- | src/libthread/threadimpl.h | 5 | ||||
-rw-r--r-- | src/libthread/ucontext.c | 41 |
7 files changed, 138 insertions, 95 deletions
diff --git a/src/libthread/386.c b/src/libthread/386.c index 2c611e45..fb4c6746 100644 --- a/src/libthread/386.c +++ b/src/libthread/386.c @@ -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 diff --git a/src/libthread/fdwait.c b/src/libthread/fdwait.c index a715706a..8768e60d 100644 --- a/src/libthread/fdwait.c +++ b/src/libthread/fdwait.c @@ -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; } diff --git a/src/libthread/label.h b/src/libthread/label.h index c3cef2d0..5081f48f 100644 --- a/src/libthread/label.h +++ b/src/libthread/label.h @@ -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; diff --git a/src/libthread/main.c b/src/libthread/main.c index 679a334b..8cdd8ca3 100644 --- a/src/libthread/main.c +++ b/src/libthread/main.c @@ -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; diff --git a/src/libthread/sched.c b/src/libthread/sched.c index 81cc3439..7f7b6daa 100644 --- a/src/libthread/sched.c +++ b/src/libthread/sched.c @@ -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; + + 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; - extern void ignusr1(int), _threaddie(int); - signal(SIGTERM, _threaddie); - + 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) { diff --git a/src/libthread/threadimpl.h b/src/libthread/threadimpl.h index d6a23905..fea309d9 100644 --- a/src/libthread/threadimpl.h +++ b/src/libthread/threadimpl.h @@ -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*, ...); diff --git a/src/libthread/ucontext.c b/src/libthread/ucontext.c new file mode 100644 index 00000000..60f803d3 --- /dev/null +++ b/src/libthread/ucontext.c @@ -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"); +} + |