tContinue switching library over to pthreads when possible. Tprimes works on Li… | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit bcf527a98e295548629620a7cb06ada951db7822 | |
parent 06bb4ed20d855b60e39c1125d8d715ba8892265b | |
Author: rsc <devnull@localhost> | |
Date: Fri, 17 Sep 2004 03:34:32 +0000 | |
Continue switching library over to pthreads when possible. | |
Tprimes works on Linux 2.6. You can only have 128 procs | |
tthough. | |
Diffstat: | |
M include/libc.h | 1 + | |
M include/u.h | 1 + | |
M src/lib9/9proc.h | 4 ++++ | |
M src/lib9/ffork-Linux.c | 201 +++--------------------------… | |
M src/lib9/mkfile | 1 - | |
M src/lib9/qlock.c | 20 -------------------- | |
M src/lib9/rendez-Linux.c | 59 +++++++++++++++++++++++++++++… | |
M src/lib9/rendez-pthread.c | 173 +++--------------------------… | |
M src/lib9/rendez-signal.c | 199 +++++------------------------… | |
M src/libthread/channel.c | 6 +++--- | |
M src/libthread/main.c | 4 ---- | |
M src/libthread/mkfile | 3 +++ | |
M src/libthread/sched.c | 28 +++++++++------------------- | |
M src/libthread/threadimpl.h | 4 ++++ | |
M src/libthread/tprimes.c | 1 - | |
15 files changed, 145 insertions(+), 560 deletions(-) | |
--- | |
diff --git a/include/libc.h b/include/libc.h | |
t@@ -454,6 +454,7 @@ struct _Procrend | |
int asleep; | |
Lock *l; | |
void *arg; | |
+ int pid; | |
#ifdef PLAN9_PTHREADS | |
pthread_cond_t cond; | |
#endif | |
diff --git a/include/u.h b/include/u.h | |
t@@ -24,6 +24,7 @@ extern "C" { | |
#include <fmt.h> | |
#include <math.h> | |
#include <ctype.h> /* for tolower */ | |
+#include <pthread.h> /* for Locks */ | |
/* | |
* OS-specific crap | |
diff --git a/src/lib9/9proc.h b/src/lib9/9proc.h | |
t@@ -1,3 +1,6 @@ | |
+#ifndef _9PROC_H_ | |
+#define _9PROC_H_ 1 | |
+ | |
enum | |
{ | |
NPRIV = 16, | |
t@@ -20,3 +23,4 @@ extern Uproc *_p9uproc(int); | |
extern void _p9uprocdie(void); | |
extern void _clearuproc(void); | |
+#endif | |
diff --git a/src/lib9/ffork-Linux.c b/src/lib9/ffork-Linux.c | |
t@@ -1,197 +1,32 @@ | |
+#define ffork ffork_clone | |
+#define getfforkid getfforkid_clone | |
+#include "ffork-Linux-clone.c" | |
+#undef ffork | |
+#undef getfforkid | |
+ | |
+#define ffork ffork_pthread | |
+#define getfforkid getfforkid_pthread | |
#include "ffork-pthread.c" | |
+#undef ffork | |
+#undef getfforkid | |
-#ifdef OLD | |
-/* | |
- * Is nothing simple? | |
- * | |
- * We can't free the stack until we've finished executing, | |
- * but once we've finished executing, we can't do anything | |
- * at all, including call free. So instead we keep a linked list | |
- * of all stacks for all processes, and every few times we try | |
- * to allocate a new stack we scan the current stack list for | |
- * dead processes and reclaim those stacks. | |
- */ | |
- | |
-#include <u.h> | |
-#include <sys/types.h> | |
-#include <sys/wait.h> | |
-#include <sched.h> | |
-#include <signal.h> | |
-#include <errno.h> | |
-#include <libc.h> | |
-#include "9proc.h" | |
- | |
-int fforkstacksize = 16384; | |
- | |
-typedef struct Stack Stack; | |
-struct Stack | |
-{ | |
- Stack *next; | |
- Stack *fnext; | |
- int pid; | |
-}; | |
- | |
-static Lock stacklock; | |
-static Stack *freestacks; | |
-static Stack *allstacks; | |
-static int stackmallocs; | |
-static void gc(void); | |
- | |
-static void* | |
-mallocstack(void) | |
-{ | |
- Stack *p; | |
- | |
- lock(&stacklock); | |
-top: | |
- p = freestacks; | |
- if(p) | |
- freestacks = p->fnext; | |
- else{ | |
- if(stackmallocs++%1 == 0) | |
- gc(); | |
- if(freestacks) | |
- goto top; | |
- p = malloc(fforkstacksize); | |
- p->next = allstacks; | |
- allstacks = p; | |
- } | |
- if(p) | |
- p->pid = 1; | |
- unlock(&stacklock); | |
- return p; | |
-} | |
- | |
-static void | |
-gc(void) | |
-{ | |
- Stack *p; | |
- | |
- for(p=allstacks; p; p=p->next){ | |
- if(p->pid > 1) | |
- if(kill(p->pid, 0) < 0 && errno == ESRCH){ | |
- if(0) fprint(2, "reclaim stack from %d\n", p->pid); | |
- p->pid = 0; | |
- } | |
- if(p->pid == 0){ | |
- p->fnext = freestacks; | |
- freestacks = p; | |
- } | |
- } | |
-} | |
- | |
-static void | |
-freestack(void *v) | |
-{ | |
- Stack *p; | |
- | |
- p = v; | |
- if(p == nil) | |
- return; | |
- lock(&stacklock); | |
- p->fnext = freestacks; | |
- p->pid = 0; | |
- freestacks = p; | |
- unlock(&stacklock); | |
- return; | |
-} | |
- | |
-static int | |
-tramp(void *v) | |
-{ | |
- void (*fn)(void*), *arg; | |
- void **v2; | |
- void *p; | |
- | |
- _p9uproc(0); | |
- v2 = v; | |
- fn = v2[0]; | |
- arg = v2[1]; | |
- p = v2[2]; | |
- free(v2); | |
- fn(arg); | |
- _exit(0); | |
- return 0; | |
-} | |
- | |
-static int | |
-trampnowait(void *v) | |
-{ | |
- int pid; | |
- int cloneflag; | |
- void **v2; | |
- int *pidp; | |
- void *p; | |
- | |
- v2 = v; | |
- cloneflag = (int)v2[4]; | |
- pidp = v2[3]; | |
- p = v2[2]; | |
- pid = clone(tramp, p+fforkstacksize-512, cloneflag, v); | |
- *pidp = pid; | |
- _exit(0); | |
- return 0; | |
-} | |
+extern int _islinuxnptl(void); | |
int | |
ffork(int flags, void (*fn)(void*), void *arg) | |
{ | |
- void **v; | |
- char *p; | |
- int cloneflag, pid, thepid, status, nowait; | |
- | |
- _p9uproc(0); | |
- p = mallocstack(); | |
- v = malloc(sizeof(void*)*5); | |
- if(p==nil || v==nil){ | |
- freestack(p); | |
- free(v); | |
- return -1; | |
- } | |
- cloneflag = 0; | |
- flags &= ~RFPROC; | |
- if(flags&RFMEM){ | |
- cloneflag |= CLONE_VM; | |
- flags &= ~RFMEM; | |
- } | |
- if(!(flags&RFFDG)) | |
- cloneflag |= CLONE_FILES; | |
+ if(_islinuxnptl()) | |
+ return ffork_pthread(flags, fn, arg); | |
else | |
- flags &= ~RFFDG; | |
- nowait = flags&RFNOWAIT; | |
- if(!(flags&RFNOWAIT)) | |
- cloneflag |= SIGCHLD; | |
- else | |
- flags &= ~RFNOWAIT; | |
- if(flags){ | |
- fprint(2, "unknown rfork flags %x\n", flags); | |
- freestack(p); | |
- free(v); | |
- return -1; | |
- } | |
- v[0] = fn; | |
- v[1] = arg; | |
- v[2] = p; | |
- v[3] = &thepid; | |
- v[4] = (void*)cloneflag; | |
- thepid = -1; | |
- pid = clone(nowait ? trampnowait : tramp, p+fforkstacksize-16, clonefl… | |
- if(pid > 0 && nowait){ | |
- if(wait4(pid, &status, __WALL, 0) < 0) | |
- fprint(2, "ffork wait4: %r\n"); | |
- }else | |
- thepid = pid; | |
- if(thepid == -1) | |
- freestack(p); | |
- else | |
- ((Stack*)p)->pid = thepid; | |
- return thepid; | |
+ return ffork_clone(flags, fn, arg); | |
} | |
int | |
getfforkid(void) | |
{ | |
- return getpid(); | |
+ if(_islinuxnptl()) | |
+ return getfforkid_pthread(); | |
+ else | |
+ return getfforkid_clone(); | |
} | |
-#endif | |
diff --git a/src/lib9/mkfile b/src/lib9/mkfile | |
t@@ -141,7 +141,6 @@ LIB9OFILES=\ | |
strecpy.$O\ | |
sysfatal.$O\ | |
sysname.$O\ | |
- tas-$OBJTYPE.$O\ | |
time.$O\ | |
tokenize.$O\ | |
truerand.$O\ | |
diff --git a/src/lib9/qlock.c b/src/lib9/qlock.c | |
t@@ -375,23 +375,3 @@ rwakeupall(Rendez *r) | |
; | |
return i; | |
} | |
- | |
-void | |
-_procsleep(_Procrend *rend) | |
-{ | |
-//print("sleep %p %d\n", rend, getpid()); | |
- pthread_cond_init(&rend->cond, 0); | |
- rend->asleep = 1; | |
- while(rend->asleep) | |
- pthread_cond_wait(&rend->cond, &rend->l->mutex); | |
- pthread_cond_destroy(&rend->cond); | |
-} | |
- | |
-void | |
-_procwakeup(_Procrend *rend) | |
-{ | |
-//print("wakeup %p\n", rend); | |
- rend->asleep = 0; | |
- pthread_cond_signal(&rend->cond); | |
-} | |
- | |
diff --git a/src/lib9/rendez-Linux.c b/src/lib9/rendez-Linux.c | |
t@@ -1,3 +1,60 @@ | |
-/* Could use futex(2) here instead of signals? */ | |
+/* | |
+ * On Linux 2.6 and later, we can use pthreads (in fact, we must), | |
+ * but on earlier Linux, pthreads are incompatible with using our | |
+ * own coroutines in libthread. In order to make binaries that work | |
+ * on either system, we detect the pthread library in use and call | |
+ * the appropriate functions. | |
+ */ | |
+#include <u.h> | |
+#include <signal.h> | |
+#include <pthread.h> | |
+#include <libc.h> | |
+ | |
+#define _procsleep _procsleep_signal | |
+#define _procwakeup _procwakeup_signal | |
#include "rendez-signal.c" | |
+ | |
+#undef _procsleep | |
+#undef _procwakeup | |
+#define _procsleep _procsleep_pthread | |
+#define _procwakeup _procwakeup_pthread | |
+#include "rendez-pthread.c" | |
+ | |
+#undef _procsleep | |
+#undef _procwakeup | |
+ | |
+int | |
+_islinuxnptl(void) | |
+{ | |
+ static char buf[100]; | |
+ static int isnptl = -1; | |
+ | |
+ if(isnptl == -1){ | |
+ if(confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof buf) > 0 | |
+ && strncmp(buf, "NPTL", 4) == 0) | |
+ isnptl = 1; | |
+ else | |
+ isnptl = 0; | |
+ } | |
+ return isnptl; | |
+} | |
+ | |
+void | |
+_procsleep(_Procrend *r) | |
+{ | |
+ if(_islinuxnptl()) | |
+ return _procsleep_pthread(r); | |
+ else | |
+ return _procsleep_signal(r); | |
+} | |
+ | |
+void | |
+_procwakeup(_Procrend *r) | |
+{ | |
+ if(_islinuxnptl()) | |
+ return _procwakeup_pthread(r); | |
+ else | |
+ return _procwakeup_signal(r); | |
+} | |
+ | |
diff --git a/src/lib9/rendez-pthread.c b/src/lib9/rendez-pthread.c | |
t@@ -1,170 +1,23 @@ | |
-/* | |
- NAME | |
- rendezvous - user level process synchronization | |
- | |
- SYNOPSIS | |
- ulong rendezvous(ulong tag, ulong value) | |
- | |
- DESCRIPTION | |
- The rendezvous system call allows two processes to synchro- | |
- nize and exchange a value. In conjunction with the shared | |
- memory system calls (see segattach(2) and fork(2)), it | |
- enables parallel programs to control their scheduling. | |
- | |
- Two processes wishing to synchronize call rendezvous with a | |
- common tag, typically an address in memory they share. One | |
- process will arrive at the rendezvous first; it suspends | |
- execution until a second arrives. When a second process | |
- meets the rendezvous the value arguments are exchanged | |
- between the processes and returned as the result of the | |
- respective rendezvous system calls. Both processes are | |
- awakened when the rendezvous succeeds. | |
- | |
- The set of tag values which two processes may use to | |
- rendezvous-their tag space-is inherited when a process | |
- forks, unless RFREND is set in the argument to rfork; see | |
- fork(2). | |
- | |
- If a rendezvous is interrupted the return value is ~0, so | |
- that value should not be used in normal communication. | |
- | |
- * This assumes we're using pthreads and simulates rendezvous using | |
- * shared memory and mutexes. | |
- */ | |
- | |
#include <u.h> | |
#include <pthread.h> | |
-#include <signal.h> | |
#include <libc.h> | |
-enum | |
+void | |
+_procsleep(_Procrend *rend) | |
{ | |
- VOUSHASH = 257, | |
-}; | |
- | |
-typedef struct Vous Vous; | |
-struct Vous | |
-{ | |
- Vous *link; | |
- Lock lk; | |
- ulong val; | |
- ulong tag; | |
- pthread_mutex_t mutex; | |
-}; | |
- | |
-static void | |
-ign(int x) | |
-{ | |
- USED(x); | |
+//print("sleep %p %d\n", rend, getpid()); | |
+ pthread_cond_init(&rend->cond, 0); | |
+ rend->asleep = 1; | |
+ while(rend->asleep) | |
+ pthread_cond_wait(&rend->cond, &rend->l->mutex); | |
+ pthread_cond_destroy(&rend->cond); | |
} | |
-void /*__attribute__((constructor))*/ | |
-ignusr1(void) | |
+void | |
+_procwakeup(_Procrend *rend) | |
{ | |
- signal(SIGUSR1, ign); | |
-} | |
- | |
-static Vous vouspool[2048]; | |
-static int nvousused; | |
-static Vous *vousfree; | |
-static Vous *voushash[VOUSHASH]; | |
-static Lock vouslock; | |
- | |
-static Vous* | |
-getvous(void) | |
-{ | |
- Vous *v; | |
- | |
- if(vousfree){ | |
- v = vousfree; | |
- vousfree = v->link; | |
- }else if(nvousused < nelem(vouspool)){ | |
- v = &vouspool[nvousused++]; | |
- pthread_mutex_init(&v->mutex, NULL); | |
- }else | |
- abort(); | |
- return v; | |
-} | |
- | |
-static void | |
-putvous(Vous *v) | |
-{ | |
- lock(&vouslock); | |
- v->link = vousfree; | |
- vousfree = v; | |
- unlock(&vouslock); | |
-} | |
- | |
-static Vous* | |
-findvous(ulong tag, ulong val, int *found) | |
-{ | |
- int h; | |
- Vous *v, **l; | |
- | |
- lock(&vouslock); | |
- h = tag%VOUSHASH; | |
- for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){ | |
- if(v->tag == tag){ | |
- *l = v->link; | |
- *found = 1; | |
- unlock(&vouslock); | |
- return v; | |
- } | |
- } | |
- v = getvous(); | |
- v->link = voushash[h]; | |
- v->val = val; | |
- v->tag = tag; | |
- lock(&v->lk); | |
- voushash[h] = v; | |
- unlock(&vouslock); | |
- *found = 0; | |
- return v; | |
-} | |
- | |
-#define DBG 0 | |
-ulong | |
-rendezvous(ulong tag, ulong val) | |
-{ | |
- int found; | |
- ulong rval; | |
- Vous *v; | |
- | |
- v = findvous(tag, val, &found); | |
- if(!found){ | |
- if(DBG)fprint(2, "tag %lux, sleeping on %p\n", tag, v); | |
- /* | |
- * No rendezvous partner was found; the next guy | |
- * through will find v and wake us, so we must go | |
- * to sleep. Do this by locking the mutex (it is | |
- * unlocked) and then locking it again (our waker will | |
- * unlock it for us). | |
- */ | |
- if(pthread_mutex_lock(&v->mutex) != 0) | |
- abort(); | |
- unlock(&v->lk); | |
- if(pthread_mutex_lock(&v->mutex) != 0) | |
- abort(); | |
- rval = v->val; | |
- pthread_mutex_unlock(&v->mutex); | |
- if(DBG)fprint(2, " awake on %p\n", v); | |
- unlock(&v->lk); | |
- putvous(v); | |
- }else{ | |
- /* | |
- * Found someone to meet. Wake him: | |
- * | |
- * A. lock v->lk (waits for him to lock the mutex once. | |
- * B. unlock the mutex (wakes him up) | |
- */ | |
- if(DBG)fprint(2, "found tag %lux on %p, waking\n", tag, v); | |
- lock(&v->lk); | |
- rval = v->val; | |
- v->val = val; | |
- if(pthread_mutex_unlock(&v->mutex) != 0) | |
- abort(); | |
- /* lock passes to him */ | |
- } | |
- return rval; | |
+//print("wakeup %p\n", rend); | |
+ rend->asleep = 0; | |
+ pthread_cond_signal(&rend->cond); | |
} | |
diff --git a/src/lib9/rendez-signal.c b/src/lib9/rendez-signal.c | |
t@@ -1,58 +1,9 @@ | |
-/* | |
- NAME | |
- rendezvous - user level process synchronization | |
- | |
- SYNOPSIS | |
- ulong rendezvous(ulong tag, ulong value) | |
- | |
- DESCRIPTION | |
- The rendezvous system call allows two processes to synchro- | |
- nize and exchange a value. In conjunction with the shared | |
- memory system calls (see segattach(2) and fork(2)), it | |
- enables parallel programs to control their scheduling. | |
- | |
- Two processes wishing to synchronize call rendezvous with a | |
- common tag, typically an address in memory they share. One | |
- process will arrive at the rendezvous first; it suspends | |
- execution until a second arrives. When a second process | |
- meets the rendezvous the value arguments are exchanged | |
- between the processes and returned as the result of the | |
- respective rendezvous system calls. Both processes are | |
- awakened when the rendezvous succeeds. | |
- | |
- The set of tag values which two processes may use to | |
- rendezvous-their tag space-is inherited when a process | |
- forks, unless RFREND is set in the argument to rfork; see | |
- fork(2). | |
- | |
- If a rendezvous is interrupted the return value is ~0, so | |
- that value should not be used in normal communication. | |
- | |
- * This simulates rendezvous with shared memory, sigsuspend, and SIGUSR1. | |
- */ | |
- | |
#include <u.h> | |
#include <signal.h> | |
#include <libc.h> | |
#define DBG 0 | |
-enum | |
-{ | |
- VOUSHASH = 257, | |
-}; | |
- | |
-typedef struct Vous Vous; | |
-struct Vous | |
-{ | |
- Vous *link; | |
- int pid; | |
- int wokeup; | |
- ulong tag; | |
- ulong val1; /* value for the sleeper */ | |
- ulong val2; /* value for the waker */ | |
-}; | |
- | |
static void | |
ign(int x) | |
{ | |
t@@ -73,128 +24,40 @@ ignusr1(int restart) | |
sigaction(SIGUSR1, &sa, nil); | |
} | |
-static Vous vouspool[2048]; | |
-static int nvousused; | |
-static Vous *vousfree; | |
-static Vous *voushash[VOUSHASH]; | |
-static Lock vouslock; | |
- | |
-static Vous* | |
-getvous(void) | |
-{ | |
- Vous *v; | |
- | |
- if(vousfree){ | |
- v = vousfree; | |
- vousfree = v->link; | |
- }else if(nvousused < nelem(vouspool)) | |
- v = &vouspool[nvousused++]; | |
- else{ | |
- fprint(2, "rendezvous: out of vous!\n"); | |
- abort(); | |
- } | |
- return v; | |
-} | |
- | |
-static void | |
-putvous(Vous *v) | |
-{ | |
- v->link = vousfree; | |
- vousfree = v; | |
-} | |
- | |
-static Vous* | |
-findvous(ulong tag) | |
-{ | |
- int h; | |
- Vous *v, **l; | |
- | |
- h = tag%VOUSHASH; | |
- for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){ | |
- if(v->tag == tag){ | |
- *l = v->link; | |
- v->link = nil; | |
- return v; | |
- } | |
- } | |
- return nil; | |
-} | |
- | |
-static Vous* | |
-mkvous(ulong tag) | |
+void | |
+_procsleep(_Procrend *r) | |
{ | |
- Vous *v; | |
- int h; | |
+ sigset_t mask; | |
- h = tag%VOUSHASH; | |
- v = getvous(); | |
- v->link = voushash[h]; | |
- v->tag = tag; | |
- voushash[h] = v; | |
- return v; | |
+ /* | |
+ * Go to sleep. | |
+ * | |
+ * Block USR1, set the handler to interrupt system calls, | |
+ * unlock the vouslock so our waker can wake us, | |
+ * and then suspend. | |
+ */ | |
+ r->asleep = 1; | |
+ r->pid = getpid(); | |
+ | |
+ sigprocmask(SIG_SETMASK, nil, &mask); | |
+ sigaddset(&mask, SIGUSR1); | |
+ sigprocmask(SIG_SETMASK, &mask, nil); | |
+ ignusr1(0); | |
+ unlock(r->l); | |
+ sigdelset(&mask, SIGUSR1); | |
+ sigsuspend(&mask); | |
+ | |
+ /* | |
+ * We're awake. Make USR1 not interrupt system calls. | |
+ */ | |
+ ignusr1(1); | |
+ assert(r->asleep == 0); | |
} | |
-ulong | |
-rendezvous(ulong tag, ulong val) | |
+void | |
+_procwakeup(_Procrend *r) | |
{ | |
- int vpid, pid; | |
- ulong rval; | |
- Vous *v; | |
- sigset_t mask; | |
- | |
- pid = getpid(); | |
- lock(&vouslock); | |
- if((v = findvous(tag)) == nil){ | |
- /* | |
- * Go to sleep. | |
- * | |
- * Block USR1, set the handler to interrupt system calls, | |
- * unlock the vouslock so our waker can wake us, | |
- * and then suspend. | |
- */ | |
- v = mkvous(tag); | |
- v->pid = pid; | |
- v->val2 = val; | |
- v->wokeup = 0; | |
- sigprocmask(SIG_SETMASK, nil, &mask); | |
- sigaddset(&mask, SIGUSR1); | |
- sigprocmask(SIG_SETMASK, &mask, nil); | |
- ignusr1(0); | |
- if(DBG) fprint(2, "%d rv(%lux, %lux) -> s\n", pid, tag, val); | |
- unlock(&vouslock); | |
- sigdelset(&mask, SIGUSR1); | |
- sigsuspend(&mask); | |
- | |
- /* | |
- * We're awake. Make USR1 not interrupt system calls. | |
- * Were we awakened or interrupted? | |
- */ | |
- ignusr1(1); | |
- lock(&vouslock); | |
- if(v->wokeup){ | |
- rval = v->val1; | |
- if(DBG) fprint(2, "%d rv(%lux, %lux) -> g %lux\n", pid… | |
- }else{ | |
- if(findvous(tag) != v){ | |
- fprint(2, "rendezvous: interrupted but not fou… | |
- abort(); | |
- } | |
- rval = ~(ulong)0; | |
- if(DBG) fprint(2, "%d rv(%lux, %lux) -> g i\n", pid, t… | |
- } | |
- putvous(v); | |
- unlock(&vouslock); | |
- }else{ | |
- /* | |
- * Wake up sleeper. | |
- */ | |
- rval = v->val2; | |
- v->val1 = val; | |
- vpid = v->pid; | |
- v->wokeup = 1; | |
- if(DBG) fprint(2, "%d rv(%lux, %lux) -> g %lux, w %d\n", pid, … | |
- unlock(&vouslock); | |
- kill(vpid, SIGUSR1); | |
- } | |
- return rval; | |
+ r->asleep = 0; | |
+ assert(r->pid >= 1); | |
+ kill(r->pid, SIGUSR1); | |
} | |
diff --git a/src/libthread/channel.c b/src/libthread/channel.c | |
t@@ -29,7 +29,7 @@ canexec(Alt *a) | |
/* are there senders or receivers blocked? */ | |
otherop = (CHANSND+CHANRCV) - a->op; | |
for(i=0; i<c->nentry; i++) | |
- if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->… | |
+ if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->… | |
_threaddebug(DBGCHAN, "can rendez alt %p chan %p", a, … | |
return 1; | |
} | |
t@@ -460,7 +460,7 @@ altexec(Alt *a, int spl) | |
b = nil; | |
me = a->v; | |
for(i=0; i<c->nentry; i++) | |
- if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->… | |
+ if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->… | |
if(nrand(++n) == 0) | |
b = c->qentry[i]; | |
if(b != nil){ | |
t@@ -488,7 +488,7 @@ altexec(Alt *a, int spl) | |
altcopy(waiter, me, c->e); | |
} | |
b->thread->altc = c; | |
- _procwakeup(&b->thread->altrend); | |
+ _threadwakeup(&b->thread->altrend); | |
_threaddebug(DBGCHAN, "chanlock is %lud", *(ulong*)(void*)&cha… | |
_threaddebug(DBGCHAN, "unlocking the chanlock"); | |
unlock(&chanlock); | |
diff --git a/src/libthread/main.c b/src/libthread/main.c | |
t@@ -49,9 +49,7 @@ main(int argc, char **argv) | |
a = _threadmalloc(sizeof *a, 1); | |
a->argc = argc; | |
a->argv = argv; | |
-malloc(10); | |
p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0); | |
-malloc(10); | |
_schedinit(p); | |
abort(); /* not reached */ | |
return 0; | |
t@@ -62,9 +60,7 @@ mainlauncher(void *arg) | |
{ | |
Mainarg *a; | |
-malloc(10); | |
a = arg; | |
-malloc(10); | |
threadmain(a->argc, a->argv); | |
threadexits("threadmain"); | |
} | |
diff --git a/src/libthread/mkfile b/src/libthread/mkfile | |
t@@ -41,6 +41,9 @@ HFILES=\ | |
<$PLAN9/src/mksyslib | |
+tfork: tfork.$O $PLAN9/lib/$LIB | |
+ $LD -o tfork tfork.$O $LDFLAGS -lthread -l9 | |
+ | |
tprimes: tprimes.$O $PLAN9/lib/$LIB | |
$LD -o tprimes tprimes.$O $LDFLAGS -lthread -l9 | |
diff --git a/src/libthread/sched.c b/src/libthread/sched.c | |
t@@ -36,7 +36,6 @@ _schedinit(void *arg) | |
unlock(&p->lock); | |
while(_setlabel(&p->sched)) | |
; | |
-malloc(10); | |
_threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _… | |
if(_threadexitsallstatus) | |
_exits(_threadexitsallstatus); | |
t@@ -148,12 +147,10 @@ relock: | |
_threaddebug(DBGSCHED, "sleeping for more work (%d threads)", … | |
q->asleep = 1; | |
- unlock(&p->readylock); | |
- while(rendezvous((ulong)q, 0) == ~0){ | |
- if(_threadexitsallstatus) | |
- _exits(_threadexitsallstatus); | |
- } | |
- /* lock picked up from _threadready */ | |
+ p->rend.l = &p->readylock; | |
+ _procsleep(&p->rend); | |
+ if(_threadexitsallstatus) | |
+ _exits(_threadexitsallstatus); | |
} | |
t = q->head; | |
q->head = t->next; | |
t@@ -185,18 +182,15 @@ _sched(void) | |
Resched: | |
p = _threadgetproc(); | |
//fprint(2, "p %p\n", p); | |
-malloc(10); | |
if((t = p->thread) != nil){ | |
needstack(512); | |
// _threaddebug(DBGSCHED, "pausing, state=%s set %p goto %p", | |
// psstate(t->state), &t->sched, &p->sched); | |
-print("swap\n"); | |
if(_setlabel(&t->sched)==0) | |
_gotolabel(&p->sched); | |
_threadstacklimit(t->stk, t->stk+t->stksize); | |
return p->nsched++; | |
}else{ | |
-malloc(10); | |
t = runthread(p); | |
if(t == nil){ | |
_threaddebug(DBGSCHED, "all threads gone; exiting"); | |
t@@ -211,8 +205,6 @@ malloc(10); | |
} | |
t->state = Running; | |
t->nextstate = Ready; | |
-malloc(10); | |
-print("gotolabel\n"); | |
_gotolabel(&t->sched); | |
for(;;); | |
} | |
t@@ -253,13 +245,11 @@ _threadready(Thread *t) | |
assert(q->asleep == 1); | |
q->asleep = 0; | |
/* lock passes to runthread */ | |
- _threaddebug(DBGSCHED, "waking process %d", t->proc->pid); | |
- while(rendezvous((ulong)q, 0) == ~0){ | |
- if(_threadexitsallstatus) | |
- _exits(_threadexitsallstatus); | |
- } | |
- }else | |
- unlock(&t->proc->readylock); | |
+ _procwakeup(&t->proc->rend); | |
+ } | |
+ unlock(&t->proc->readylock); | |
+ if(_threadexitsallstatus) | |
+ _exits(_threadexitsallstatus); | |
} | |
void | |
diff --git a/src/libthread/threadimpl.h b/src/libthread/threadimpl.h | |
t@@ -95,6 +95,8 @@ struct Thread | |
Chanstate chan; /* which channel operation is cu… | |
Alt *alt; /* pointer to current … | |
ulong userpc; | |
+ Channel *c; | |
+ pthread_cond_t cond; | |
void* udata[NPRIV]; /* User per-thread data pointer */ | |
int lastfd; | |
t@@ -136,6 +138,8 @@ struct Proc | |
uint nextID; /* ID of most recently crea… | |
Proc *next; /* linked list of Procs */ | |
+ _Procrend rend; /* sleep here for more ready threads */ | |
+ | |
void *arg; /* passed between sha… | |
char str[ERRMAX]; /* used by threadexits to avoi… | |
char errbuf[ERRMAX]; /* errstr */ | |
diff --git a/src/libthread/tprimes.c b/src/libthread/tprimes.c | |
t@@ -41,7 +41,6 @@ threadmain(int argc, char **argv) | |
int i; | |
Channel *c; | |
-malloc(10); | |
ARGBEGIN{ | |
case 'D': | |
_threaddebuglevel = atoi(ARGF()); |