From 195645536743aeb99eb336726823c38716cec02d Mon Sep 17 00:00:00 2001 From: rsc Date: Mon, 8 Nov 2004 16:03:20 +0000 Subject: more thread work --- src/libthread/pthread.c | 268 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 182 insertions(+), 86 deletions(-) (limited to 'src/libthread/pthread.c') diff --git a/src/libthread/pthread.c b/src/libthread/pthread.c index 8d661c16..83d8b023 100644 --- a/src/libthread/pthread.c +++ b/src/libthread/pthread.c @@ -2,53 +2,36 @@ #include #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; @@ -63,69 +46,43 @@ _threadstartproc(Proc *p) np->pthreadid = tid; } -/* - * Called to associate p with the current pthread. - */ void -_threadinitproc(Proc *p) -{ - p->pthreadid = pthread_self(); - _threadsetproc(p); -} - -/* - * Called to exit the current pthread. - */ -void -_threadexitproc(char *exitstr) +_kthreadexitproc(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) @@ -133,43 +90,182 @@ _threadwaitproc(void *v) 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; + + 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); +} - /* - * 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); +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 +_threadnote(void *x, char *msg) +{ + 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<