aboutsummaryrefslogtreecommitdiff
path: root/src/libthread
diff options
context:
space:
mode:
Diffstat (limited to 'src/libthread')
-rw-r--r--src/libthread/386.c5
-rw-r--r--src/libthread/fdwait.c44
-rw-r--r--src/libthread/label.h8
-rw-r--r--src/libthread/main.c4
-rw-r--r--src/libthread/sched.c126
-rw-r--r--src/libthread/threadimpl.h5
-rw-r--r--src/libthread/ucontext.c41
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");
+}
+