aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-09-23 19:03:46 +0000
committerrsc <devnull@localhost>2004-09-23 19:03:46 +0000
commite7821682ea0105c74f00986131cf59b07d4966cc (patch)
tree2f6d74418f37b4f91b30402a19f44a5f5396d02c
parent4fbe07e1db9282a09a3f021922a3e13346b5e932 (diff)
downloadplan9port-e7821682ea0105c74f00986131cf59b07d4966cc.tar.gz
plan9port-e7821682ea0105c74f00986131cf59b07d4966cc.tar.bz2
plan9port-e7821682ea0105c74f00986131cf59b07d4966cc.zip
add pthread
-rw-r--r--src/libthread/pthread.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/libthread/pthread.c b/src/libthread/pthread.c
new file mode 100644
index 00000000..b2c1c026
--- /dev/null
+++ b/src/libthread/pthread.c
@@ -0,0 +1,164 @@
+#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)
+{
+ pthread_exit(nil);
+}
+
+/*
+ * Called to exit all pthreads.
+ */
+void
+_threadexitallproc(char *exitstr)
+{
+ exits(0);
+}
+
+/*
+ * 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);
+ }
+}
+
+/*
+ * 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;
+}