Files
plan9port/src/libthread/pthread.c

272 lines
4.4 KiB
C
Raw Normal View History

2004-09-23 19:03:46 +00:00
#include <u.h>
#include <errno.h>
#include "threadimpl.h"
/*
2004-11-08 16:03:20 +00:00
* Basic kernel thread management.
2004-09-23 19:03:46 +00:00
*/
2004-11-08 16:03:20 +00:00
static pthread_key_t key;
2004-09-23 19:03:46 +00:00
void
2004-11-08 16:03:20 +00:00
_kthreadinit(void)
2004-09-23 19:03:46 +00:00
{
2004-11-08 16:03:20 +00:00
pthread_key_create(&key, 0);
2004-09-23 19:03:46 +00:00
}
void
2004-11-08 16:03:20 +00:00
_kthreadsetproc(Proc *p)
2004-09-23 19:03:46 +00:00
{
2004-11-08 16:03:20 +00:00
sigset_t all;
p->pthreadid = pthread_self();
sigfillset(&all);
pthread_sigmask(SIG_SETMASK, &all, nil);
2004-09-23 19:03:46 +00:00
pthread_setspecific(key, p);
}
Proc*
2004-11-08 16:03:20 +00:00
_kthreadgetproc(void)
2004-09-23 19:03:46 +00:00
{
return pthread_getspecific(key);
}
2004-10-22 18:45:08 +00:00
void
2004-11-08 16:03:20 +00:00
_kthreadstartproc(Proc *p)
2004-10-22 18:45:08 +00:00
{
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;
}
2004-09-23 19:03:46 +00:00
void
2004-11-08 16:03:20 +00:00
_kthreadexitproc(char *exitstr)
2004-09-23 19:03:46 +00:00
{
2004-10-22 17:15:30 +00:00
_threaddebug(DBGSCHED, "_pthreadexit");
2004-09-23 19:03:46 +00:00
pthread_exit(nil);
}
void
2004-11-08 16:03:20 +00:00
_kthreadexitallproc(char *exitstr)
2004-09-23 19:03:46 +00:00
{
2004-10-22 17:15:30 +00:00
_threaddebug(DBGSCHED, "_threadexitallproc");
exits(exitstr);
2004-09-23 19:03:46 +00:00
}
/*
2004-11-08 16:03:20 +00:00
* 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.
2004-09-23 19:03:46 +00:00
*/
2004-11-08 16:03:20 +00:00
static Channel *_threadexecwaitchan;
2004-09-23 19:03:46 +00:00
2004-10-22 18:45:08 +00:00
static void
2004-09-23 19:03:46 +00:00
_threadwaitproc(void *v)
{
Channel *c;
Waitmsg *w;
2004-11-08 16:03:20 +00:00
_threadinternalproc();
2004-09-23 19:03:46 +00:00
USED(v);
for(;;){
w = wait();
if(w == nil){
2004-11-08 16:03:20 +00:00
if(errno == ECHILD) /* wait for more */
recvul(_threadexecwaitchan);
2004-09-23 19:03:46 +00:00
continue;
}
if((c = _threadwaitchan) != nil)
sendp(c, w);
else
free(w);
}
2004-11-08 16:03:20 +00:00
fprint(2, "_threadwaitproc exits\n"); /* not reached */
2004-09-23 19:03:46 +00:00
}
2004-11-08 16:03:20 +00:00
2004-09-23 19:03:46 +00:00
/*
2004-11-08 16:03:20 +00:00
* Call _threadexec in the right conditions.
2004-09-23 19:03:46 +00:00
*/
2004-11-08 16:03:20 +00:00
int
_kthreadexec(Channel *c, int fd[3], char *prog, char *args[], int freeargs)
2004-09-23 19:03:46 +00:00
{
2004-11-08 16:03:20 +00:00
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;
2004-09-23 19:03:46 +00:00
}
2004-10-22 18:45:08 +00:00
/*
2004-11-08 16:03:20 +00:00
* 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.
2004-10-22 18:45:08 +00:00
*/
2004-11-08 16:03:20 +00:00
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);
}
2004-09-23 19:03:46 +00:00
void
2004-11-08 16:03:20 +00:00
_threadbackgroundinit(void)
2004-09-23 19:03:46 +00:00
{
2004-11-08 16:03:20 +00:00
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);
}
2004-09-23 19:03:46 +00:00
2004-11-08 16:03:20 +00:00
void
threadbackground(void)
{
if(passerpid <= 1)
return;
postnote(PNPROC, passerpid, "sys: usr2");
2004-09-23 19:03:46 +00:00
}
2004-10-22 18:45:08 +00:00
/*
2004-11-08 16:03:20 +00:00
* Notes.
2004-10-22 18:45:08 +00:00
*/
2004-11-08 16:03:20 +00:00
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<<i)) == 0)
continue;
sigs &= ~(1<<i);
if(i == 0)
continue;
sendp(c, _p9sigstr(i));
}
}
}
2004-09-23 19:03:46 +00:00
void
2004-11-08 16:03:20 +00:00
_threadschednote(void)
2004-09-23 19:03:46 +00:00
{
}
2004-11-08 16:03:20 +00:00
void
_kmaininit(void)
{
sigset_t all;
sigfillset(&all);
pthread_sigmask(SIG_SETMASK, &all, 0);
}