aboutsummaryrefslogtreecommitdiff
path: root/src/lib9
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-09-21 01:11:28 +0000
committerrsc <devnull@localhost>2004-09-21 01:11:28 +0000
commitc6687d4591964cb13df87f55ec4770e778a4a55c (patch)
treeee669a419904e929ae8ae54fd04c2bb41b5a57b1 /src/lib9
parent3d5e34e146b5ba5c973230abb624ce9126024569 (diff)
downloadplan9port-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.h3
-rw-r--r--src/lib9/_p9proc-Linux.c5
-rw-r--r--src/lib9/_p9proc-getpid.c113
-rw-r--r--src/lib9/fork.c11
-rw-r--r--src/lib9/lock-Darwin.c1
-rw-r--r--src/lib9/lock-FreeBSD.c1
-rw-r--r--src/lib9/lock-Linux.c5
-rw-r--r--src/lib9/lock-pthread.c54
-rw-r--r--src/lib9/lock-tas.c57
-rw-r--r--src/lib9/mkfile5
-rw-r--r--src/lib9/qlock.c22
-rw-r--r--src/lib9/rendez-signal.c1
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