commit - 77dcf88474c55e040940be8a5f9e7fa1537af564
commit + 195645536743aeb99eb336726823c38716cec02d
blob - 14791d05224a1a005b989f5e9ecfd3cd0fdfc98e
blob + b488dc9760bb00d7d12bdd1053b90c0d863b1c12
--- src/libthread/channel.c
+++ src/libthread/channel.c
static void enqueue(Alt*, Thread*);
static void dequeue(Alt*);
-static int altexec(Alt*, int);
+static int altexec(Alt*);
int _threadhighnentry;
int _threadnalt;
{
Alt *a, *xa;
Channel *c;
- int n, s;
+ int n;
Thread *t;
/*
t = _threadgetproc()->thread;
if((t && t->moribund) || _threadexitsallstatus)
yield(); /* won't return */
- s = _procsplhi();
lock(&chanlock);
/* test whether any channels can proceed */
c = xa->c;
if(c==nil){
unlock(&chanlock);
- _procsplx(s);
return -1;
}
if(canexec(xa))
/* nothing can proceed */
if(xa->op == CHANNOBLK){
unlock(&chanlock);
- _procsplx(s);
-_threadnalt++;
+ _threadnalt++;
return xa - alts;
}
t->alt = alts;
t->chan = Chanalt;
t->altrend.l = &chanlock;
- _procsplx(s);
_threadsleep(&t->altrend);
- s = _procsplhi();
/* dequeue from channels, find selected one */
a = nil;
dequeue(xa);
}
unlock(&chanlock);
- _procsplx(s);
if(a == nil){ /* we were interrupted */
assert(c==(Channel*)~0);
return -1;
}
}else{
- altexec(a, s); /* unlocks chanlock, does splx */
+ altexec(a); /* unlocks chanlock, does splx */
}
if(t)
t->chan = Channone;
}
static int
-altexec(Alt *a, int spl)
+altexec(Alt *a)
{
volatile Alt *b;
int i, n, otherop;
_threaddebug(DBGCHAN, "chanlock is %lud", *(ulong*)(void*)&chanlock);
_threaddebug(DBGCHAN, "unlocking the chanlock");
unlock(&chanlock);
- _procsplx(spl);
return 1;
}
altcopy(buf, me, c->e);
unlock(&chanlock);
- _procsplx(spl);
return 1;
}
blob - d2f4be259f5934c4d0624d72b9c6a1e0e56eede2
blob + 4e6bc6de2263575a932e63ff5396938bfa2134e2
--- src/libthread/create.c
+++ src/libthread/create.c
p = _threadgetproc();
np = _newproc();
p->newproc = np;
- p->schedfn = _threadstartproc;
+ p->schedfn = _kthreadstartproc;
id = _newthread(np, f, arg, stacksize, nil, p->thread->grp);
_sched(); /* call into scheduler to create proc XXX */
return id;
blob - f69fedcab30760353f432aeebcd39dd14cbc2745
blob + e5848eaa4d674a99cbbac26d60681ac4faf53c67
--- src/libthread/exec-unix.c
+++ src/libthread/exec-unix.c
int pfd[2];
int n, pid;
char exitstr[ERRMAX];
- static int firstexec = 1;
- static Lock lk;
_threaddebug(DBGEXEC, "threadexec %s", prog);
- if(firstexec){
- lock(&lk);
- if(firstexec){
- firstexec = 0;
- _threadfirstexec();
- }
- unlock(&lk);
- }
-
/*
* We want threadexec to behave like exec; if exec succeeds,
* never return, and if it fails, return with errstr set.
_threaddebug(DBGSCHED, "exit after efork");
_exit(0);
default:
- _threadafterexec();
if(freeargs)
free(args);
break;
void
threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
{
- if(_callthreadexec(pidc, fd, prog, args, 0) >= 0)
+ if(_kthreadexec(pidc, fd, prog, args, 0) >= 0)
threadexits(nil);
}
int
threadspawn(int fd[3], char *prog, char *args[])
{
- return _callthreadexec(nil, fd, prog, args, 0);
+ return _kthreadexec(nil, fd, prog, args, 0);
}
/*
args[n] = 0;
va_end(arg);
- if(_callthreadexec(pidc, fd, f, args, 1) >= 0)
+ if(_kthreadexec(pidc, fd, f, args, 1) >= 0)
threadexits(nil);
}
blob - 79aa7c7f9b82ba493522d5778ec0d0c8d9c47db5
blob + 69f3f738b2770fa6ff44e44a5da9f581986399c2
--- src/libthread/exit.c
+++ src/libthread/exit.c
_threadexitsallstatus = exitstr;
_threaddebug(DBGSCHED, "_threadexitsallstatus set to %p", _threadexitsallstatus);
/* leave */
- _threadexitallproc(exitstr);
+ _kthreadexitallproc(exitstr);
}
Channel*
blob - a46ea4567248428d791a631ae2a6cf5b77e72451
blob + d398341973c709d50e728ac3b3c90225c80713cf
--- src/libthread/fdwait.c
+++ src/libthread/fdwait.c
#include <unistd.h>
#include <fcntl.h>
-#define debugpoll 0
-
-#ifdef __APPLE__
-#include <sys/time.h>
-enum { POLLIN=1, POLLOUT=2, POLLERR=4 };
-struct pollfd
+void
+fdwait()
{
- int fd;
- int events;
- int revents;
-};
-
-int
-poll(struct pollfd *p, int np, int ms)
-{
- int i, maxfd, n;
- struct timeval tv, *tvp;
fd_set rfd, wfd, efd;
-
- maxfd = -1;
+
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&efd);
- for(i=0; i<np; i++){
- p[i].revents = 0;
- if(p[i].fd == -1)
- continue;
- if(p[i].fd > maxfd)
- maxfd = p[i].fd;
- if(p[i].events & POLLIN)
- FD_SET(p[i].fd, &rfd);
- if(p[i].events & POLLOUT)
- FD_SET(p[i].fd, &wfd);
- FD_SET(p[i].fd, &efd);
- }
-
- if(ms != -1){
- tv.tv_usec = (ms%1000)*1000;
- tv.tv_sec = ms/1000;
- tvp = &tv;
- }else
- tvp = nil;
-
- if(debugpoll){
- fprint(2, "select %d:", maxfd+1);
- for(i=0; i<=maxfd; i++){
- if(FD_ISSET(i, &rfd))
- fprint(2, " r%d", i);
- if(FD_ISSET(i, &wfd))
- fprint(2, " w%d", i);
- if(FD_ISSET(i, &efd))
- fprint(2, " e%d", i);
- }
- fprint(2, "; tp=%p, t=%d.%d\n", tvp, tv.tv_sec, tv.tv_usec);
- }
-
- n = select(maxfd+1, &rfd, &wfd, &efd, tvp);
-
- if(n <= 0)
- return n;
-
- for(i=0; i<np; i++){
- if(p[i].fd == -1)
- continue;
- if(FD_ISSET(p[i].fd, &rfd))
- p[i].revents |= POLLIN;
- if(FD_ISSET(p[i].fd, &wfd))
- p[i].revents |= POLLOUT;
- if(FD_ISSET(p[i].fd, &efd))
- p[i].revents |= POLLERR;
- }
- return n;
-}
-
-#else
-#include <poll.h>
-#endif
-
-/*
- * Poll file descriptors in an idle loop.
- */
-
-typedef struct Poll Poll;
-
-struct Poll
-{
- Channel *c; /* for sending back */
-};
-
-static Channel *sleepchan[64];
-static int sleeptime[64];
-static int nsleep;
-
-static struct pollfd pfd[64];
-static struct Poll polls[64];
-static int npoll;
-
-static void
-pollidle(void *v)
-{
- int i, n, t;
- uint now;
-
- for(;; yield()){
- if(debugpoll) fprint(2, "poll %d:", npoll);
- for(i=0; i<npoll; i++){
- if(debugpoll) fprint(2, " %d%c", pfd[i].fd, pfd[i].events==POLLIN ? 'r' : 'w');
- pfd[i].revents = 0;
- }
- t = -1;
- now = p9nsec()/1000000;
- for(i=0; i<nsleep; i++){
- n = sleeptime[i] - now;
- if(debugpoll) fprint(2, " s%d", n);
- if(n < 0)
- n = 0;
- if(t == -1 || n < t)
- t = n;
- }
- if(debugpoll) fprint(2, "; t=%d\n", t);
-
- n = poll(pfd, npoll, t);
- //fprint(2, "poll ret %d:", n);
- now = p9nsec()/1000000;
- for(i=0; i<nsleep; i++){
- if((int)(sleeptime[i] - now) < 0){
- nbsendul(sleepchan[i], 0);
- nsleep--;
- sleepchan[i] = sleepchan[nsleep];
- sleeptime[i] = sleeptime[nsleep];
- i--;
- }
- }
-
- if(n <= 0)
- continue;
- for(i=0; i<npoll; i++)
- if(pfd[i].fd != -1 && pfd[i].revents){
- //fprint(2, " %d", pfd[i].fd);
- pfd[i].fd = -1;
- pfd[i].events = 0;
- pfd[i].revents = 0;
- nbsendul(polls[i].c, 1);
- //fprint(2, " x%d", pfd[i].fd);
- }
- //fprint(2, "\n");
- }
+ if(mode=='w')
+ FD_SET(&wfd, fd);
+ else
+ FD_SET(&rfd, fd);
+ FD_SET(&efd, fd);
+ select(fd+1, &rfd, &wfd, &efd, nil);
}
void
threadfdwaitsetup(void)
{
- static int setup = 0;
-
- if(!setup){
- setup = 1;
- proccreate(pollidle, nil, 16384);
- }
}
void
polls[i].c = &s.c;
if(0) fprint(2, "%s [%3d] fdwait %d %c list *0x%lux\n",
argv0, threadid(), fd, rw, pc);
+ if(pollpid)
+ postnote(PNPROC, pollpid, "interrupt");
recvul(&s.c);
}
blob - ec0854304fd33a201f8503daf168d6120ecba7cb
blob + bc4efd276ac21e63455814bf88b92ea10831e125
--- src/libthread/main.c
+++ src/libthread/main.c
char **argv;
};
-int _threadmainpid;
int mainstacksize;
-int _callsthreaddaemonize;
-static int passtomainpid;
extern void (*_sysfatal)(char*, va_list);
+extern Jmp *(*_notejmpbuf)(void);
static void
mainlauncher(void *arg)
Mainarg *a;
a = arg;
- _threadmaininit();
+ _kmaininit();
threadmain(a->argc, a->argv);
threadexits("threadmain");
}
-static void
-passer(void *x, char *msg)
-{
- USED(x);
- Waitmsg *w;
-
- if(strcmp(msg, "sys: usr2") == 0)
- _exit(0); /* daemonize */
- else if(strcmp(msg, "sys: child") == 0){
- w = wait();
- if(w == nil)
- _exit(1);
- _exit(atoi(w->msg));
- }else
- postnote(PNPROC, passtomainpid, msg);
-}
-
int
main(int argc, char **argv)
{
- int pid;
Mainarg a;
Proc *p;
- sigset_t mask;
/*
- * Do daemonize hack here.
+ * In pthreads, threadmain is actually run in a subprocess,
+ * so that the main process can exit (if threaddaemonize is called).
+ * The main process relays notes to the subprocess.
+ * _Threadbackgroundsetup will return only in the subprocess.
*/
- if(_callsthreaddaemonize){
- passtomainpid = getpid();
- switch(pid = fork()){
- case -1:
- sysfatal("fork: %r");
+ _threadbackgroundinit();
- case 0:
- /* continue executing */
- _threadmainpid = getppid();
- break;
-
- default:
- /* wait for signal USR2 */
- notify(passer);
- for(;;)
- pause();
- _exit(0);
- }
- }
-
/*
* Instruct QLock et al. to use our scheduling functions
* so that they can operate at the thread level.
/*
* Install our own _threadsysfatal which takes down
- * the whole conglomeration of procs.
+ * the whole confederation of procs.
*/
_sysfatal = _threadsysfatal;
/*
- * XXX Install our own jump handler.
+ * Install our own jump handler.
*/
+ _notejmpbuf = _threadgetjmp;
/*
- * Install our own signal handlers.
+ * Install our own signal handler.
*/
notify(_threadnote);
_threadlinkmain(void)
{
}
+
+Jmp*
+_threadgetjmp(void)
+{
+ static Jmp j;
+ Proc *p;
+
+ p = _threadgetproc();
+ if(p == nil)
+ return &j;
+ return &p->sigjmp;
+}
blob - e51d195f32727b7d174beda4ab7ffb3f25358a07
blob + 6492bb931022862956197297c01dae48ce06e3c2
--- src/libthread/mkfile
+++ src/libthread/mkfile
<$PLAN9/src/mkhdr
LIB=libthread.a
-THREAD=`sh ./thread.sh`
+SYSOFILES=`sh ./sysofiles.sh`
OFILES=\
- $OBJTYPE.$O\
- $THREAD.$O\
- asm-$SYSNAME-$OBJTYPE.$O\
+ $SYSOFILES\
channel.$O\
chanprint.$O\
create.$O\
- daemon.$O\
debug.$O\
exec-unix.$O\
exit.$O\
main.$O\
memset.$O\
memsetd.$O\
- note.$O\
read9pmsg.$O\
ref.$O\
sched.$O\
+ setproc.$O\
sleep.$O\
HFILES=\
trend: trend.$O $PLAN9/lib/$LIB
$LD -o trend trend.$O $LDFLAGS -lthread -l9
+tsignal: tsignal.$O $PLAN9/lib/$LIB
+ $LD -o tsignal tsignal.$O $LDFLAGS -lthread -l9
+
CLEANFILES=$CLEANFILES tprimes texec
asm-Linux-ppc.$O: asm-Linux-386.s
blob - 8d661c166e0ad6786f0615081cb181da7dec4668
blob + 83d8b023576d6e0f3d0b0f4de42a7c8d05a59c31
--- src/libthread/pthread.c
+++ src/libthread/pthread.c
#include <errno.h>
#include "threadimpl.h"
-static int multi;
-static Proc *theproc;
-static pthread_key_t key;
-
/*
- * Called before we go multiprocess.
+ * Basic kernel thread management.
*/
+static pthread_key_t key;
+
void
-_threadmultiproc(void)
+_kthreadinit(void)
{
- if(multi == 0){
- multi = 1;
- pthread_key_create(&key, 0);
- _threadsetproc(theproc);
- }
+ pthread_key_create(&key, 0);
}
-/*
- * Set the proc for the current pthread.
- */
void
-_threadsetproc(Proc *p)
+_kthreadsetproc(Proc *p)
{
- if(!multi){
- theproc = p;
- return;
- }
+ sigset_t all;
+
+ p->pthreadid = pthread_self();
+ sigfillset(&all);
+ pthread_sigmask(SIG_SETMASK, &all, nil);
pthread_setspecific(key, p);
}
-/*
- * Get the proc for the current pthread.
- */
Proc*
-_threadgetproc(void)
+_kthreadgetproc(void)
{
- if(!multi)
- return theproc;
-
return pthread_getspecific(key);
}
-/*
- * Called to start a new proc.
- */
void
-_threadstartproc(Proc *p)
+_kthreadstartproc(Proc *p)
{
Proc *np;
pthread_t tid;
np->pthreadid = tid;
}
-/*
- * Called to associate p with the current pthread.
- */
void
-_threadinitproc(Proc *p)
+_kthreadexitproc(char *exitstr)
{
- p->pthreadid = pthread_self();
- _threadsetproc(p);
-}
-
-/*
- * Called to exit the current pthread.
- */
-void
-_threadexitproc(char *exitstr)
-{
_threaddebug(DBGSCHED, "_pthreadexit");
pthread_exit(nil);
}
-/*
- * Called to exit all pthreads.
- */
void
-_threadexitallproc(char *exitstr)
+_kthreadexitallproc(char *exitstr)
{
_threaddebug(DBGSCHED, "_threadexitallproc");
exits(exitstr);
}
/*
- * Called to poll for any kids of this pthread.
- * Wait messages aren't restricted to a particular
- * pthread, so we have a separate proc responsible
- * for them. So this is a no-op.
+ * Exec. Pthreads does the hard work of making it possible
+ * for any thread to do the waiting, so this is pretty easy.
+ * We create a separate proc whose job is to wait for children
+ * and deliver wait messages.
*/
-void
-_threadwaitkids(Proc *p)
-{
-}
+static Channel *_threadexecwaitchan;
-/*
- * Separate process to wait for child messages.
- * Also runs signal handlers.
- */
-static Channel *_threadexecchan;
static void
_threadwaitproc(void *v)
{
Channel *c;
Waitmsg *w;
- sigset_t none;
- sigemptyset(&none);
- pthread_sigmask(SIG_SETMASK, &none, 0);
+ _threadinternalproc();
USED(v);
for(;;){
w = wait();
if(w == nil){
- if(errno == ECHILD)
- recvul(_threadexecchan);
+ if(errno == ECHILD) /* wait for more */
+ recvul(_threadexecwaitchan);
continue;
}
if((c = _threadwaitchan) != nil)
else
free(w);
}
-fprint(2, "_threadwaitproc exits\n");
+ fprint(2, "_threadwaitproc exits\n"); /* not reached */
}
+
/*
- * Called before the first exec.
+ * Call _threadexec in the right conditions.
*/
-void
-_threadfirstexec(void)
+int
+_kthreadexec(Channel *c, int fd[3], char *prog, char *args[], int freeargs)
{
+ static Lock lk;
+ int rv;
+
+ if(!_threadexecwaitchan){
+ lock(&lk);
+ if(!_threadexecwaitchan){
+ _threadexecwaitchan = chancreate(sizeof(ulong), 1);
+ proccreate(_threadwaitproc, nil, 32*1024);
+ }
+ unlock(&lk);
+ }
+ rv = _threadexec(c, fd, prog, args, freeargs);
+ nbsendul(_threadexecwaitchan, 1);
+ return rv;
}
/*
- * Called from mainlauncher before threadmain.
+ * Some threaded applications want to run in the background.
+ * Calling fork() and exiting in the parent will result in a child
+ * with a single pthread (if we are using pthreads), and will screw
+ * up our internal process info if we are using clone/rfork.
+ * Instead, apps should call threadbackground(), which takes
+ * care of this.
+ *
+ * _threadbackgroundinit is called from main.
*/
+
+static int mainpid, passerpid;
+
+static void
+passer(void *x, char *msg)
+{
+ Waitmsg *w;
+
+ USED(x);
+ if(strcmp(msg, "sys: usr2") == 0)
+ _exit(0); /* daemonize */
+ else if(strcmp(msg, "sys: child") == 0){
+ /* child exited => so should we */
+ w = wait();
+ if(w == nil)
+ _exit(1);
+ _exit(atoi(w->msg));
+ }else
+ postnote(PNGROUP, mainpid, msg);
+}
+
void
-_threadmaininit(void)
+_threadbackgroundinit(void)
{
- _threadexecchan = chancreate(sizeof(ulong), 1);
- proccreate(_threadwaitproc, nil, 32*1024);
+ int pid;
+ sigset_t mask;
- /*
- * Sleazy: decrement threadnprocs so that
- * the existence of the _threadwaitproc proc
- * doesn't keep us from exiting.
- */
- lock(&_threadpq.lock);
- --_threadnprocs;
- /* print("change %d -> %d\n", _threadnprocs+1, _threadnprocs); */
- unlock(&_threadpq.lock);
+ sigfillset(&mask);
+ pthread_sigmask(SIG_BLOCK, &mask, 0);
+
+return;
+
+ passerpid = getpid();
+ switch(pid = fork()){
+ case -1:
+ sysfatal("fork: %r");
+
+ case 0:
+ rfork(RFNOTEG);
+ return;
+
+ default:
+ break;
+ }
+
+ mainpid = pid;
+ notify(passer);
+ notifyon("sys: child");
+ notifyon("sys: usr2"); /* should already be on */
+ for(;;)
+ pause();
+ _exit(0);
}
+void
+threadbackground(void)
+{
+ if(passerpid <= 1)
+ return;
+ postnote(PNPROC, passerpid, "sys: usr2");
+}
+
/*
- * Called after forking the exec child.
+ * Notes.
*/
+Channel *_threadnotechan;
+static ulong sigs;
+static Lock _threadnotelk;
+static void _threadnoteproc(void*);
+extern int _p9strsig(char*);
+extern char *_p9sigstr(int);
+
+Channel*
+threadnotechan(void)
+{
+ if(_threadnotechan == nil){
+ lock(&_threadnotelk);
+ if(_threadnotechan == nil){
+ _threadnotechan = chancreate(sizeof(char*), 1);
+ proccreate(_threadnoteproc, nil, 32*1024);
+ }
+ unlock(&_threadnotelk);
+ }
+ return _threadnotechan;
+}
+
void
-_threadafterexec(void)
+_threadnote(void *x, char *msg)
{
- nbsendul(_threadexecchan, 1);
+ USED(x);
+
+ if(_threadexitsallstatus)
+ _kthreadexitproc(_threadexitsallstatus);
+
+ if(strcmp(msg, "sys: usr2") == 0)
+ noted(NCONT);
+
+ if(_threadnotechan == nil)
+ noted(NDFLT);
+
+ sigs |= 1<<_p9strsig(msg);
+ noted(NCONT);
}
+void
+_threadnoteproc(void *x)
+{
+ int i;
+ sigset_t none;
+ Channel *c;
+
+ _threadinternalproc();
+ sigemptyset(&none);
+ pthread_sigmask(SIG_SETMASK, &none, 0);
+
+ c = _threadnotechan;
+ for(;;){
+ if(sigs == 0)
+ pause();
+ for(i=0; i<32; i++){
+ if((sigs&(1<<i)) == 0)
+ continue;
+ sigs &= ~(1<<i);
+ if(i == 0)
+ continue;
+ sendp(c, _p9sigstr(i));
+ }
+ }
+}
+
+void
+_threadschednote(void)
+{
+}
+
+void
+_kmaininit(void)
+{
+ sigset_t all;
+
+ sigfillset(&all);
+ pthread_sigmask(SIG_SETMASK, &all, 0);
+}
blob - 7e430193545527a15372f10801f57097f69d82e7
blob + ac982da86645d289a17c03c786ef1fefdb9e7174
--- src/libthread/sched.c
+++ src/libthread/sched.c
p = arg;
_threadlinkmain();
- _threadinitproc(p);
+ _threadsetproc(p);
for(;;){
/*
* Clean up zombie children.
*/
- _threadwaitkids(p);
/*
* Find next thread to run.
if(p->nthreads==0 || (p->nthreads==1 && p->idle))
return nil;
+ _threadschednote();
lock(&p->readylock);
q = &p->ready;
if(q->head == nil){
*/
q->asleep = 1;
p->rend.l = &p->readylock;
- _procsleep(&p->rend);
+ while(q->asleep){
+ _procsleep(&p->rend);
+ _threadschednote();
+ }
/*
* Maybe we were awakened to exit?
unlock(&p->readylock);
}
+/*
+ * Mark proc as internal so that if all but internal procs exit, we exit.
+ */
+void
+_threadinternalproc(void)
+{
+ Proc *p;
+
+ p = _threadgetproc();
+ if(p->internal)
+ return;
+ lock(&_threadpq.lock);
+ if(p->internal == 0){
+ p->internal = 1;
+ --_threadnprocs;
+ }
+ unlock(&_threadpq.lock);
+}
+
static void
schedexit(Proc *p)
{
break;
}
}
- n = --_threadnprocs;
+ if(p->internal)
+ n = _threadnprocs;
+ else
+ n = --_threadnprocs;
unlock(&_threadpq.lock);
strncpy(ex, p->exitstr, sizeof ex);
free(p);
if(n == 0){
_threaddebug(DBGSCHED, "procexit; no more procs");
- _threadexitallproc(ex);
+ _kthreadexitallproc(ex);
}else{
_threaddebug(DBGSCHED, "procexit");
- _threadexitproc(ex);
+ _kthreadexitproc(ex);
}
}
blob - d6c4dac4f1b099099976ebde57bd5615f1497ced
blob + 4b0d82a1ed1238f5eaee2a31a88cd919d90c530c
--- src/libthread/sleep.c
+++ src/libthread/sleep.c
_threadready(t);
unlock(&t->proc->lock);
}
+
blob - e3984b7965ad160adad54cfc0278204f1de91f0c
blob + 818b509febf47f393f0e2aed2b71f6ce5ae1113d
--- src/libthread/thread.sh
+++ src/libthread/thread.sh
if [ `uname` = Linux ]
then
- case "`uname | awk '{print $3}'`" in
- *)
- echo Linux-clone
- ;;
+ case `uname -r` in
2.[6789]*)
echo pthread
;;
+ *)
+ echo Linux-clone
+ ;;
esac
else
echo pthread
blob - 8d7a7a75d5dc30eb01af9111011dd01dad90bff7
blob + 0ad4568e19e705ead79233b0c96045b19b7fda75
--- src/libthread/threadimpl.h
+++ src/libthread/threadimpl.h
typedef struct Tqueue Tqueue;
typedef struct Pqueue Pqueue;
typedef struct Execargs Execargs;
+typedef struct Jmp Jmp;
+/* sync with ../lib9/notify.c */
+struct Jmp
+{
+ p9jmp_buf b;
+};
+
+
typedef enum
{
Dead,
Proc *newproc; /* fork argument */
char exitstr[ERRMAX]; /* exit status */
+ int internal;
int rforkflag;
int nthreads;
Tqueue threads; /* All threads of this proc */
uint nextID; /* ID of most recently created thread */
Proc *next; /* linked list of Procs */
+ Jmp sigjmp; /* for notify implementation */
void (*schedfn)(Proc*); /* function to call in scheduler */
void _swaplabel(Label*, Label*);
Proc* _newproc(void);
int _newthread(Proc*, void(*)(void*), void*, uint, char*, int);
-int _procsplhi(void);
-void _procsplx(int);
int _sched(void);
int _schedexec(Execargs*);
void _schedexecwait(void);
Proc* _threadgetproc(void);
extern void _threadmultiproc(void);
Proc* _threaddelproc(void);
-void _threadinitproc(Proc*);
-void _threadwaitkids(Proc*);
+void _kthreadinitproc(Proc*);
void _threadsetproc(Proc*);
void _threadinitstack(Thread*, void(*)(void*), void*);
void _threadlinkmain(void);
void* _threadmalloc(long, int);
void _threadnote(void*, char*);
void _threadready(Thread*);
+void _threadschednote(void);
void _threadsetidle(int);
void _threadsleep(_Procrend*);
void _threadwakeup(_Procrend*);
void _xinc(long*);
void _threadremove(Proc*, Thread*);
void threadstatus(void);
-void _threadstartproc(Proc*);
-void _threadexitproc(char*);
-void _threadexitallproc(char*);
void _threadefork(int[3], int[2], char*, char**);
+Jmp* _threadgetjmp(void);
+void _kthreadinit(void);
+void _kthreadsetproc(Proc*);
+Proc* _kthreadgetproc(void);
+void _kthreadstartproc(Proc*);
+void _kthreadexitproc(char*);
+void _kthreadexitallproc(char*);
+void _threadinternalproc(void);
+void _threadbackgroundinit(void);
+void _kmaininit(void);
-extern int _threadmainpid;
extern int _threadnprocs;
extern int _threaddebuglevel;
extern char* _threadexitsallstatus;
extern void _procdelthread(Proc*, Thread*);
extern void _procaddthread(Proc*, Thread*);
-extern void _threadafterexec(void);
extern void _threadmaininit(void);
-extern void _threadfirstexec(void);
extern int _threadexec(Channel*, int[3], char*, char*[], int);
-extern int _callthreadexec(Channel*, int[3], char*, char*[], int);
+extern int _kthreadexec(Channel*, int[3], char*, char*[], int);