aboutsummaryrefslogtreecommitdiff
path: root/src/libthread/pthread.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-11-08 16:03:20 +0000
committerrsc <devnull@localhost>2004-11-08 16:03:20 +0000
commit195645536743aeb99eb336726823c38716cec02d (patch)
treeaccb04698efde81ad1228adfddcea695d544ca25 /src/libthread/pthread.c
parent77dcf88474c55e040940be8a5f9e7fa1537af564 (diff)
downloadplan9port-195645536743aeb99eb336726823c38716cec02d.tar.gz
plan9port-195645536743aeb99eb336726823c38716cec02d.tar.bz2
plan9port-195645536743aeb99eb336726823c38716cec02d.zip
more thread work
Diffstat (limited to 'src/libthread/pthread.c')
-rw-r--r--src/libthread/pthread.c268
1 files changed, 182 insertions, 86 deletions
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 <errno.h>
#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<<i)) == 0)
+ continue;
+ sigs &= ~(1<<i);
+ if(i == 0)
+ continue;
+ sendp(c, _p9sigstr(i));
+ }
+ }
+}
+
void
-_threadafterexec(void)
+_threadschednote(void)
{
- nbsendul(_threadexecchan, 1);
}
+void
+_kmaininit(void)
+{
+ sigset_t all;
+
+ sigfillset(&all);
+ pthread_sigmask(SIG_SETMASK, &all, 0);
+}