blob: a914f433d12dbb51efa02f75e7a318095137209f [file] [log] [blame]
#include <u.h>
#include <errno.h>
#include "threadimpl.h"
static int multi;
static Proc *theproc;
static pthread_key_t key;
/*
* Called before we go multiprocess.
*/
void
_threadmultiproc(void)
{
if(multi == 0){
multi = 1;
pthread_key_create(&key, 0);
_threadsetproc(theproc);
}
}
/*
* Set the proc for the current pthread.
*/
void
_threadsetproc(Proc *p)
{
if(!multi){
theproc = p;
return;
}
pthread_setspecific(key, p);
}
/*
* Get the proc for the current pthread.
*/
Proc*
_threadgetproc(void)
{
if(!multi)
return theproc;
return pthread_getspecific(key);
}
/*
* 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)
{
_threaddebug(DBGSCHED, "_pthreadexit");
pthread_exit(nil);
}
/*
* Called to exit all pthreads.
*/
void
_threadexitallproc(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.
*/
void
_threadwaitkids(Proc *p)
{
}
/*
* Separate process to wait for child messages.
*/
Channel *_threadexecchan;
void
_threadwaitproc(void *v)
{
Channel *c;
Waitmsg *w;
sigset_t none;
sigemptyset(&none);
pthread_sigmask(SIG_SETMASK, &none, 0);
USED(v);
for(;;){
w = wait();
if(w == nil){
if(errno == ECHILD)
recvul(_threadexecchan);
continue;
}
if((c = _threadwaitchan) != nil)
sendp(c, w);
else
free(w);
}
fprint(2, "_threadwaitproc exits\n");
}
/*
* Called before the first exec.
*/
void
_threadfirstexec(void)
{
}
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);
}
void
_threadafterexec(void)
{
nbsendul(_threadexecchan, 1);
}
/*
* Called to start a new proc.
*/
void
_threadstartproc(Proc *p)
{
Proc *np;
pthread_t tid;
sigset_t all;
np = p->newproc;
sigfillset(&all);
pthread_sigmask(SIG_SETMASK, &all, nil);
if(pthread_create(&tid, nil, (void*(*)(void*))_threadscheduler,
np) < 0)
sysfatal("pthread_create: %r");
np->pthreadid = tid;
}