more thread work
This commit is contained in:
parent
77dcf88474
commit
1956455367
12 changed files with 294 additions and 340 deletions
|
|
@ -2,53 +2,36 @@
|
|||
#include <errno.h>
|
||||
#include "threadimpl.h"
|
||||
|
||||
static int multi;
|
||||
static Proc *theproc;
|
||||
/*
|
||||
* Basic kernel thread management.
|
||||
*/
|
||||
static pthread_key_t key;
|
||||
|
||||
/*
|
||||
* Called before we go multiprocess.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void
|
||||
_threadmaininit(void)
|
||||
{
|
||||
_threadexecchan = chancreate(sizeof(ulong), 1);
|
||||
proccreate(_threadwaitproc, nil, 32*1024);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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
|
||||
_threadbackgroundinit(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
threadbackground(void)
|
||||
{
|
||||
if(passerpid <= 1)
|
||||
return;
|
||||
postnote(PNPROC, passerpid, "sys: usr2");
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after forking the exec child.
|
||||
* Notes.
|
||||
*/
|
||||
void
|
||||
_threadafterexec(void)
|
||||
Channel *_threadnotechan;
|
||||
static ulong sigs;
|
||||
static Lock _threadnotelk;
|
||||
static void _threadnoteproc(void*);
|
||||
extern int _p9strsig(char*);
|
||||
extern char *_p9sigstr(int);
|
||||
|
||||
Channel*
|
||||
threadnotechan(void)
|
||||
{
|
||||
nbsendul(_threadexecchan, 1);
|
||||
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<<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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue