diff options
author | rsc <devnull@localhost> | 2004-09-21 01:11:28 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-09-21 01:11:28 +0000 |
commit | c6687d4591964cb13df87f55ec4770e778a4a55c (patch) | |
tree | ee669a419904e929ae8ae54fd04c2bb41b5a57b1 /src/lib9 | |
parent | 3d5e34e146b5ba5c973230abb624ce9126024569 (diff) | |
download | plan9port-c6687d4591964cb13df87f55ec4770e778a4a55c.tar.gz plan9port-c6687d4591964cb13df87f55ec4770e778a4a55c.tar.bz2 plan9port-c6687d4591964cb13df87f55ec4770e778a4a55c.zip |
Continue the pthreads torture.
Diffstat (limited to 'src/lib9')
-rw-r--r-- | src/lib9/9proc.h | 3 | ||||
-rw-r--r-- | src/lib9/_p9proc-Linux.c | 5 | ||||
-rw-r--r-- | src/lib9/_p9proc-getpid.c | 113 | ||||
-rw-r--r-- | src/lib9/fork.c | 11 | ||||
-rw-r--r-- | src/lib9/lock-Darwin.c | 1 | ||||
-rw-r--r-- | src/lib9/lock-FreeBSD.c | 1 | ||||
-rw-r--r-- | src/lib9/lock-Linux.c | 5 | ||||
-rw-r--r-- | src/lib9/lock-pthread.c | 54 | ||||
-rw-r--r-- | src/lib9/lock-tas.c | 57 | ||||
-rw-r--r-- | src/lib9/mkfile | 5 | ||||
-rw-r--r-- | src/lib9/qlock.c | 22 | ||||
-rw-r--r-- | src/lib9/rendez-signal.c | 1 |
12 files changed, 261 insertions, 17 deletions
diff --git a/src/lib9/9proc.h b/src/lib9/9proc.h index 0eb5f410..0c359c9e 100644 --- a/src/lib9/9proc.h +++ b/src/lib9/9proc.h @@ -13,9 +13,6 @@ struct Uproc int pid; int state; void *priv[NPRIV]; - ulong rendval; - ulong rendtag; - Uproc *rendhash; p9jmp_buf notejb; }; diff --git a/src/lib9/_p9proc-Linux.c b/src/lib9/_p9proc-Linux.c new file mode 100644 index 00000000..902a9579 --- /dev/null +++ b/src/lib9/_p9proc-Linux.c @@ -0,0 +1,5 @@ +#ifdef __Linux26__ +#include "_p9proc-pthread.c" +#else +#include "_p9proc-getpid.c" +#endif diff --git a/src/lib9/_p9proc-getpid.c b/src/lib9/_p9proc-getpid.c new file mode 100644 index 00000000..9543bf24 --- /dev/null +++ b/src/lib9/_p9proc-getpid.c @@ -0,0 +1,113 @@ +/* + * This needs to be callable from a signal handler, so it has been + * written to avoid locks. The only lock is the one used to acquire + * an entry in the table, and we make sure that acquiring is done + * when not in a handler. Lookup and delete do not need locks. + * It's a scan-forward hash table. To avoid breaking chains, + * T ((void*)-1) is used as a non-breaking nil. + */ + +#include <u.h> +#include <libc.h> +#include "9proc.h" + +enum { PIDHASH = 1021 }; + +#define T ((void*)-1) +static Uproc *alluproc[PIDHASH]; +static int allupid[PIDHASH]; +static Lock uproclock; + +void +_clearuproc(void) +{ + int i; + + /* called right after fork - no locking needed */ + for(i=0; i<PIDHASH; i++) + if(alluproc[i] != T && alluproc[i] != 0) + free(alluproc[i]); + memset(alluproc, 0, sizeof alluproc); + memset(allupid, 0, sizeof allupid); +} + +Uproc* +_p9uproc(int inhandler) +{ + int i, h, pid; + Uproc *up; + + /* for now, assume getpid is fast or cached */ + pid = getpid(); + + /* + * this part - the lookup - needs to run without locks + * so that it can safely be called from within the notify handler. + * notify calls _p9uproc, and fork and rfork call _p9uproc + * in both parent and child, so if we're in a signal handler, + * we should find something in the table. + */ + h = pid%PIDHASH; + for(i=0; i<PIDHASH; i++){ + up = alluproc[h]; + if(up == nil) + break; + if(allupid[h] == pid) + return up; + if(++h == PIDHASH) + h = 0; + } + + if(inhandler){ + fprint(2, "%s: did not find uproc for pid %d in signal handler\n", argv0, pid); + abort(); + } + + /* need to allocate */ + while((up = mallocz(sizeof(Uproc), 1)) == nil) + sleep(1000); + + /* fprint(2, "alloc uproc for pid %d\n", pid); */ + up->pid = pid; + lock(&uproclock); + h = pid%PIDHASH; + for(i=0; i<PIDHASH; i++){ + if(alluproc[h]==T || alluproc[h]==nil){ + alluproc[h] = up; + allupid[h] = pid; + unlock(&uproclock); + return up; + } + if(++h == PIDHASH) + h = 0; + } + unlock(&uproclock); + + /* out of pids! */ + sysfatal("too many processes in uproc table"); + return nil; +} + +void +_p9uprocdie(void) +{ + Uproc *up; + int pid, i, h; + + pid = getpid(); + /* fprint(2, "reap uproc for pid %d\n", pid); */ + h = pid%PIDHASH; + for(i=0; i<PIDHASH; i++){ + up = alluproc[h]; + if(up == nil) + break; + if(up == T) + continue; + if(allupid[h] == pid){ + up = alluproc[h]; + alluproc[h] = T; + free(up); + allupid[h] = 0; + } + } +} diff --git a/src/lib9/fork.c b/src/lib9/fork.c index 4dbff87b..841d2c2d 100644 --- a/src/lib9/fork.c +++ b/src/lib9/fork.c @@ -1,4 +1,5 @@ #include <u.h> +#include <signal.h> #include <libc.h> #include "9proc.h" #undef fork @@ -7,9 +8,15 @@ int p9fork(void) { int pid; + sigset_t all, old; + sigfillset(&all); + sigprocmask(SIG_SETMASK, &all, &old); pid = fork(); - _clearuproc(); - _p9uproc(0); + if(pid == 0){ + _clearuproc(); + _p9uproc(0); + } + sigprocmask(SIG_SETMASK, &old, nil); return pid; } diff --git a/src/lib9/lock-Darwin.c b/src/lib9/lock-Darwin.c new file mode 100644 index 00000000..231ca713 --- /dev/null +++ b/src/lib9/lock-Darwin.c @@ -0,0 +1 @@ +#include "lock-pthread.c" diff --git a/src/lib9/lock-FreeBSD.c b/src/lib9/lock-FreeBSD.c new file mode 100644 index 00000000..bdd48a28 --- /dev/null +++ b/src/lib9/lock-FreeBSD.c @@ -0,0 +1 @@ +#include "lock-tas.c" diff --git a/src/lib9/lock-Linux.c b/src/lib9/lock-Linux.c new file mode 100644 index 00000000..c25596b9 --- /dev/null +++ b/src/lib9/lock-Linux.c @@ -0,0 +1,5 @@ +#ifdef __Linux26__ +#include "lock-pthread.c" +#else +#include "lock-tas.c" +#endif diff --git a/src/lib9/lock-pthread.c b/src/lib9/lock-pthread.c new file mode 100644 index 00000000..689261f6 --- /dev/null +++ b/src/lib9/lock-pthread.c @@ -0,0 +1,54 @@ +#include <u.h> +#include <unistd.h> +#include <sys/time.h> +#include <sched.h> +#include <libc.h> + +static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER; + +static void +lockinit(Lock *lk) +{ + pthread_mutexattr_t attr; + + pthread_mutex_lock(&initmutex); + if(lk->init == 0){ + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&lk->mutex, &attr); + pthread_mutexattr_destroy(&attr); + lk->init = 1; + } + pthread_mutex_unlock(&initmutex); +} + +void +lock(Lock *lk) +{ + if(!lk->init) + lockinit(lk); + if(pthread_mutex_lock(&lk->mutex) != 0) + abort(); +} + +int +canlock(Lock *lk) +{ + int r; + + if(!lk->init) + lockinit(lk); + r = pthread_mutex_trylock(&lk->mutex); + if(r == 0) + return 1; + if(r == EBUSY) + return 0; + abort(); +} + +void +unlock(Lock *lk) +{ + if(pthread_mutex_unlock(&lk->mutex) != 0) + abort(); +} diff --git a/src/lib9/lock-tas.c b/src/lib9/lock-tas.c new file mode 100644 index 00000000..e6f54de6 --- /dev/null +++ b/src/lib9/lock-tas.c @@ -0,0 +1,57 @@ +#include <u.h> +#include <unistd.h> +#include <sys/time.h> +#include <sched.h> +#include <libc.h> + +int _ntas; +static int +_xtas(void *v) +{ + int x; + + _ntas++; + x = _tas(v); + if(x != 0 && x != 0xcafebabe){ + print("bad tas value %d\n", x); + abort(); + } + return x; +} + +int +canlock(Lock *l) +{ + return !_xtas(&l->val); +} + +void +unlock(Lock *l) +{ + l->val = 0; +} + +void +lock(Lock *lk) +{ + int i; + + /* once fast */ + if(!_xtas(&lk->val)) + return; + /* a thousand times pretty fast */ + for(i=0; i<1000; i++){ + if(!_xtas(&lk->val)) + return; + sched_yield(); + } + /* now nice and slow */ + for(i=0; i<1000; i++){ + if(!_xtas(&lk->val)) + return; + usleep(100*1000); + } + /* take your time */ + while(_xtas(&lk->val)) + usleep(1000*1000); +} diff --git a/src/lib9/mkfile b/src/lib9/mkfile index ed430ff8..9200d81c 100644 --- a/src/lib9/mkfile +++ b/src/lib9/mkfile @@ -67,7 +67,7 @@ LIB9OFILES=\ _exits.$O\ _p9dialparse.$O\ _p9dir.$O\ - _p9proc.$O\ + _p9proc-$SYSNAME.$O\ announce.$O\ argv0.$O\ atexit.$O\ @@ -111,7 +111,7 @@ LIB9OFILES=\ jmp.$O\ lrand.$O\ lnrand.$O\ - lock.$O\ + lock-$SYSNAME.$O\ main.$O\ malloc.$O\ malloctag.$O\ @@ -141,6 +141,7 @@ 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 index 625c100f..0eacccd7 100644 --- a/src/lib9/qlock.c +++ b/src/lib9/qlock.c @@ -18,6 +18,8 @@ enum static void (*procsleep)(_Procrend*) = _procsleep; static void (*procwakeup)(_Procrend*) = _procwakeup; +#define _procsleep donotcall_procsleep +#define _procwakeup donotcall_procwakeup /* this gets called by the thread library ONLY to get us to use its rendezvous */ void @@ -73,7 +75,7 @@ qlock(QLock *q) q->tail = mp; mp->state = Queuing; mp->rend.l = &q->lock; - _procsleep(&mp->rend); + procsleep(&mp->rend); unlock(&q->lock); assert(mp->state == Waking); unlock(&mp->inuse); @@ -92,7 +94,7 @@ qunlock(QLock *q) if(q->head == nil) q->tail = nil; p->state = Waking; - _procwakeup(&p->rend); + procwakeup(&p->rend); unlock(&q->lock); return; } @@ -137,7 +139,7 @@ rlock(RWLock *q) mp->next = nil; mp->state = QueuingR; mp->rend.l = &q->lock; - _procsleep(&mp->rend); + procsleep(&mp->rend); unlock(&q->lock); assert(mp->state == Waking); unlock(&mp->inuse); @@ -181,7 +183,7 @@ runlock(RWLock *q) /* wakeup waiter */ p->state = Waking; - _procwakeup(&p->rend); + procwakeup(&p->rend); unlock(&q->lock); } @@ -211,7 +213,7 @@ wlock(RWLock *q) /* wait in kernel */ mp->rend.l = &q->lock; - _procsleep(&mp->rend); + procsleep(&mp->rend); unlock(&q->lock); assert(mp->state == Waking); unlock(&mp->inuse); @@ -253,7 +255,7 @@ wunlock(RWLock *q) if(q->head == nil) q->tail = nil; p->state = Waking; - _procwakeup(&p->rend); + procwakeup(&p->rend); unlock(&q->lock); return; } @@ -269,7 +271,7 @@ wunlock(RWLock *q) q->head = p->next; q->readers++; p->state = Waking; - _procwakeup(&p->rend); + procwakeup(&p->rend); } if(q->head == nil) q->tail = nil; @@ -310,20 +312,20 @@ rsleep(Rendez *r) if(r->l->head == nil) r->l->tail = nil; t->state = Waking; - _procwakeup(&t->rend); + procwakeup(&t->rend); }else r->l->locked = 0; /* wait for a wakeup */ me->rend.l = &r->l->lock; - _procsleep(&me->rend); - + procsleep(&me->rend); assert(me->state == Waking); unlock(&me->inuse); if(!r->l->locked){ fprint(2, "rsleep: not locked after wakeup\n"); abort(); } + unlock(&r->l->lock); } int diff --git a/src/lib9/rendez-signal.c b/src/lib9/rendez-signal.c index e2abc3d3..744a8fc8 100644 --- a/src/lib9/rendez-signal.c +++ b/src/lib9/rendez-signal.c @@ -52,6 +52,7 @@ _procsleep(_Procrend *r) */ ignusr1(1); assert(r->asleep == 0); + lock(r->l); } void |