Continue the pthreads torture.
diff --git a/include/libc.h b/include/libc.h
index 87b6bfd..da9f9dc 100644
--- a/include/libc.h
+++ b/include/libc.h
@@ -436,6 +436,7 @@
#endif
};
+extern int _tas(int*);
extern void lock(Lock*);
extern void unlock(Lock*);
extern int canlock(Lock*);
diff --git a/include/u.h b/include/u.h
index 8e79ba6..c1ca033 100644
--- a/include/u.h
+++ b/include/u.h
@@ -24,7 +24,6 @@
#include <fmt.h>
#include <math.h>
#include <ctype.h> /* for tolower */
-#include <pthread.h> /* for Locks */
/*
* OS-specific crap
@@ -42,8 +41,10 @@
# undef _NEEDUSHORT
# undef _NEEDUINT
# undef _NEEDULONG
-# include <pthread.h>
-# define PLAN9_PTHREADS
+# endif
+# if defined(__Linux26__)
+# include <pthread.h>
+# define PLAN9_PTHREADS 1
# endif
#endif
#if defined(__sun__)
diff --git a/src/cmd/9term/9term.c b/src/cmd/9term/9term.c
index 51e733a..f183f11 100644
--- a/src/cmd/9term/9term.c
+++ b/src/cmd/9term/9term.c
@@ -884,12 +884,8 @@
case 0x7F: /* DEL: send interrupt */
t.qh = t.q0 = t.q1 = t.nr;
show(t.q0);
-{int x; x=tcgetpgrp(rcfd);
-print("postnote %d pgrp %d\n", rcpid, x);
- postnote(PNGROUP, x, "interrupt");
-if(x >= 2) killpg(x, 2);
-}
- // write(rcfd, "\x7F", 1);
+ // postnote(PNGROUP, x, "interrupt");
+ write(rcfd, "\x7F", 1);
return;
}
diff --git a/src/cmd/9term/rcstart.c b/src/cmd/9term/rcstart.c
index 7ee4935..ddaadb5 100644
--- a/src/cmd/9term/rcstart.c
+++ b/src/cmd/9term/rcstart.c
@@ -3,6 +3,25 @@
#include <libc.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
rcstart(int argc, char **argv, int *pfd, int *tfd)
{
@@ -33,11 +52,14 @@
dup(sfd, 0);
dup(sfd, 1);
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)
- system("stty -echo");
+ sys("stty -echo");
for(i=3; i<100; i++)
close(i);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
execvp(argv[0], argv);
fprint(2, "exec %s failed: %r\n", argv[0]);
_exits("oops");
diff --git a/src/lib9/9proc.h b/src/lib9/9proc.h
index 0eb5f41..0c359c9 100644
--- a/src/lib9/9proc.h
+++ b/src/lib9/9proc.h
@@ -13,9 +13,6 @@
int pid;
int state;
void *priv[NPRIV];
- ulong rendval;
- ulong rendtag;
- Uproc *rendhash;
p9jmp_buf notejb;
};
diff --git a/src/lib9/_p9proc-Linux.c b/src/lib9/_p9proc-Linux.c
new file mode 100644
index 0000000..902a957
--- /dev/null
+++ b/src/lib9/_p9proc-Linux.c
@@ -0,0 +1,5 @@
+#ifdef __Linux26__
+#include "_p9proc-pthread.c"
+#else
+#include "_p9proc-getpid.c"
+#endif
diff --git a/src/lib9/_p9proc-getpid.c b/src/lib9/_p9proc-getpid.c
new file mode 100644
index 0000000..9543bf2
--- /dev/null
+++ b/src/lib9/_p9proc-getpid.c
@@ -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;
+ }
+ }
+}
diff --git a/src/lib9/fork.c b/src/lib9/fork.c
index 4dbff87..841d2c2 100644
--- a/src/lib9/fork.c
+++ b/src/lib9/fork.c
@@ -1,4 +1,5 @@
#include <u.h>
+#include <signal.h>
#include <libc.h>
#include "9proc.h"
#undef fork
@@ -7,9 +8,15 @@
p9fork(void)
{
int pid;
+ sigset_t all, old;
+ sigfillset(&all);
+ sigprocmask(SIG_SETMASK, &all, &old);
pid = fork();
- _clearuproc();
- _p9uproc(0);
+ if(pid == 0){
+ _clearuproc();
+ _p9uproc(0);
+ }
+ sigprocmask(SIG_SETMASK, &old, nil);
return pid;
}
diff --git a/src/lib9/lock-Darwin.c b/src/lib9/lock-Darwin.c
new file mode 100644
index 0000000..231ca71
--- /dev/null
+++ b/src/lib9/lock-Darwin.c
@@ -0,0 +1 @@
+#include "lock-pthread.c"
diff --git a/src/lib9/lock-FreeBSD.c b/src/lib9/lock-FreeBSD.c
new file mode 100644
index 0000000..bdd48a2
--- /dev/null
+++ b/src/lib9/lock-FreeBSD.c
@@ -0,0 +1 @@
+#include "lock-tas.c"
diff --git a/src/lib9/lock-Linux.c b/src/lib9/lock-Linux.c
new file mode 100644
index 0000000..c25596b
--- /dev/null
+++ b/src/lib9/lock-Linux.c
@@ -0,0 +1,5 @@
+#ifdef __Linux26__
+#include "lock-pthread.c"
+#else
+#include "lock-tas.c"
+#endif
diff --git a/src/lib9/lock-pthread.c b/src/lib9/lock-pthread.c
new file mode 100644
index 0000000..689261f
--- /dev/null
+++ b/src/lib9/lock-pthread.c
@@ -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();
+}
diff --git a/src/lib9/lock-tas.c b/src/lib9/lock-tas.c
new file mode 100644
index 0000000..e6f54de
--- /dev/null
+++ b/src/lib9/lock-tas.c
@@ -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);
+}
diff --git a/src/lib9/mkfile b/src/lib9/mkfile
index ed430ff..9200d81 100644
--- a/src/lib9/mkfile
+++ b/src/lib9/mkfile
@@ -67,7 +67,7 @@
_exits.$O\
_p9dialparse.$O\
_p9dir.$O\
- _p9proc.$O\
+ _p9proc-$SYSNAME.$O\
announce.$O\
argv0.$O\
atexit.$O\
@@ -111,7 +111,7 @@
jmp.$O\
lrand.$O\
lnrand.$O\
- lock.$O\
+ lock-$SYSNAME.$O\
main.$O\
malloc.$O\
malloctag.$O\
@@ -141,6 +141,7 @@
strecpy.$O\
sysfatal.$O\
sysname.$O\
+ tas-$OBJTYPE.$O\
time.$O\
tokenize.$O\
truerand.$O\
diff --git a/src/lib9/qlock.c b/src/lib9/qlock.c
index 625c100..0eacccd 100644
--- a/src/lib9/qlock.c
+++ b/src/lib9/qlock.c
@@ -18,6 +18,8 @@
static void (*procsleep)(_Procrend*) = _procsleep;
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 */
void
@@ -73,7 +75,7 @@
q->tail = mp;
mp->state = Queuing;
mp->rend.l = &q->lock;
- _procsleep(&mp->rend);
+ procsleep(&mp->rend);
unlock(&q->lock);
assert(mp->state == Waking);
unlock(&mp->inuse);
@@ -92,7 +94,7 @@
if(q->head == nil)
q->tail = nil;
p->state = Waking;
- _procwakeup(&p->rend);
+ procwakeup(&p->rend);
unlock(&q->lock);
return;
}
@@ -137,7 +139,7 @@
mp->next = nil;
mp->state = QueuingR;
mp->rend.l = &q->lock;
- _procsleep(&mp->rend);
+ procsleep(&mp->rend);
unlock(&q->lock);
assert(mp->state == Waking);
unlock(&mp->inuse);
@@ -181,7 +183,7 @@
/* wakeup waiter */
p->state = Waking;
- _procwakeup(&p->rend);
+ procwakeup(&p->rend);
unlock(&q->lock);
}
@@ -211,7 +213,7 @@
/* wait in kernel */
mp->rend.l = &q->lock;
- _procsleep(&mp->rend);
+ procsleep(&mp->rend);
unlock(&q->lock);
assert(mp->state == Waking);
unlock(&mp->inuse);
@@ -253,7 +255,7 @@
if(q->head == nil)
q->tail = nil;
p->state = Waking;
- _procwakeup(&p->rend);
+ procwakeup(&p->rend);
unlock(&q->lock);
return;
}
@@ -269,7 +271,7 @@
q->head = p->next;
q->readers++;
p->state = Waking;
- _procwakeup(&p->rend);
+ procwakeup(&p->rend);
}
if(q->head == nil)
q->tail = nil;
@@ -310,20 +312,20 @@
if(r->l->head == nil)
r->l->tail = nil;
t->state = Waking;
- _procwakeup(&t->rend);
+ procwakeup(&t->rend);
}else
r->l->locked = 0;
/* wait for a wakeup */
me->rend.l = &r->l->lock;
- _procsleep(&me->rend);
-
+ procsleep(&me->rend);
assert(me->state == Waking);
unlock(&me->inuse);
if(!r->l->locked){
fprint(2, "rsleep: not locked after wakeup\n");
abort();
}
+ unlock(&r->l->lock);
}
int
diff --git a/src/lib9/rendez-signal.c b/src/lib9/rendez-signal.c
index e2abc3d..744a8fc 100644
--- a/src/lib9/rendez-signal.c
+++ b/src/lib9/rendez-signal.c
@@ -52,6 +52,7 @@
*/
ignusr1(1);
assert(r->asleep == 0);
+ lock(r->l);
}
void
diff --git a/src/libmux/mux.c b/src/libmux/mux.c
index 2d5074e..aa92c20 100644
--- a/src/libmux/mux.c
+++ b/src/libmux/mux.c
@@ -55,8 +55,9 @@
enqueue(mux, r);
/* wait for our packet */
- while(mux->muxer && !r->p)
+ while(mux->muxer && !r->p){
rsleep(&r->r);
+ }
/* if not done, there's no muxer: start muxing */
if(!r->p){
diff --git a/src/libthread/386.c b/src/libthread/386.c
index 2c611e4..fb4c674 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 @@
VALGRIND_SET_STACK_LIMIT(1, bottom, top);
#endif
}
+#endif
diff --git a/src/libthread/fdwait.c b/src/libthread/fdwait.c
index a715706..8768e60 100644
--- a/src/libthread/fdwait.c
+++ b/src/libthread/fdwait.c
@@ -241,15 +241,16 @@
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 @@
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 @@
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 @@
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 c3cef2d..5081f48 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 679a334..8cdd8ca 100644
--- a/src/libthread/main.c
+++ b/src/libthread/main.c
@@ -50,7 +50,7 @@
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 @@
{
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 81cc343..7f7b6da 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 @@
}
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 @@
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 @@
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 @@
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 d6a2390..fea309d 100644
--- a/src/libthread/threadimpl.h
+++ b/src/libthread/threadimpl.h
@@ -167,8 +167,7 @@
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 @@
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 0000000..60f803d
--- /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");
+}
+
diff --git a/src/mkfile b/src/mkfile
index bed2755..87df6c1 100644
--- a/src/mkfile
+++ b/src/mkfile
@@ -9,6 +9,14 @@
<mkdirs
+libs:V: libs-all
+
+libs-%:V:
+ for i in $LIBDIRS
+ do
+ (cd $i; mk $stem)
+ done
+
MKDIRS=\
libbio\
libregexp\