New thread library
This commit is contained in:
parent
7788fd5409
commit
1544f90960
70 changed files with 1041 additions and 4684 deletions
|
|
@ -1,271 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <errno.h>
|
||||
#include "threadimpl.h"
|
||||
|
||||
/*
|
||||
* Basic kernel thread management.
|
||||
*/
|
||||
static pthread_key_t key;
|
||||
|
||||
void
|
||||
_kthreadinit(void)
|
||||
{
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
|
||||
void
|
||||
_kthreadsetproc(Proc *p)
|
||||
{
|
||||
sigset_t all;
|
||||
|
||||
p->pthreadid = pthread_self();
|
||||
sigfillset(&all);
|
||||
pthread_sigmask(SIG_SETMASK, &all, nil);
|
||||
pthread_setspecific(key, p);
|
||||
}
|
||||
|
||||
Proc*
|
||||
_kthreadgetproc(void)
|
||||
{
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
void
|
||||
_kthreadstartproc(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;
|
||||
}
|
||||
|
||||
void
|
||||
_kthreadexitproc(char *exitstr)
|
||||
{
|
||||
_threaddebug(DBGSCHED, "_pthreadexit");
|
||||
pthread_exit(nil);
|
||||
}
|
||||
|
||||
void
|
||||
_kthreadexitallproc(char *exitstr)
|
||||
{
|
||||
_threaddebug(DBGSCHED, "_threadexitallproc");
|
||||
exits(exitstr);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static Channel *_threadexecwaitchan;
|
||||
|
||||
static void
|
||||
_threadwaitproc(void *v)
|
||||
{
|
||||
Channel *c;
|
||||
Waitmsg *w;
|
||||
|
||||
_threadinternalproc();
|
||||
|
||||
USED(v);
|
||||
|
||||
for(;;){
|
||||
w = wait();
|
||||
if(w == nil){
|
||||
if(errno == ECHILD) /* wait for more */
|
||||
recvul(_threadexecwaitchan);
|
||||
continue;
|
||||
}
|
||||
if((c = _threadwaitchan) != nil)
|
||||
sendp(c, w);
|
||||
else
|
||||
free(w);
|
||||
}
|
||||
fprint(2, "_threadwaitproc exits\n"); /* not reached */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Call _threadexec in the right conditions.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
_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");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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<<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