various bug fixes and paranoia

This commit is contained in:
rsc 2004-05-23 00:59:33 +00:00
parent a09e80f9c4
commit 6c7460701e
3 changed files with 87 additions and 70 deletions

View file

@ -35,6 +35,7 @@ static struct {
SIGVTALRM, 0, SIGVTALRM, 0,
SIGUSR1, 0, SIGUSR1, 0,
SIGUSR2, 0, SIGUSR2, 0,
SIGWINCH, 1,
#ifdef SIGINFO #ifdef SIGINFO
SIGINFO, 0, SIGINFO, 0,
#endif #endif

View file

@ -13,6 +13,7 @@ enum
QueuingR, QueuingR,
QueuingW, QueuingW,
Sleeping, Sleeping,
Waking,
}; };
static ulong (*_rendezvousp)(ulong, ulong) = rendezvous; static ulong (*_rendezvousp)(ulong, ulong) = rendezvous;
@ -74,6 +75,7 @@ qlock(QLock *q)
/* wait */ /* wait */
while((*_rendezvousp)((ulong)mp, 1) == ~0) while((*_rendezvousp)((ulong)mp, 1) == ~0)
; ;
assert(mp->state == Waking);
mp->inuse = 0; mp->inuse = 0;
} }
@ -90,6 +92,7 @@ qunlock(QLock *q)
if(q->head == nil) if(q->head == nil)
q->tail = nil; q->tail = nil;
unlock(&q->lock); unlock(&q->lock);
p->state = Waking;
while((*_rendezvousp)((ulong)p, 0x12345) == ~0) while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
; ;
return; return;
@ -139,6 +142,7 @@ rlock(RWLock *q)
/* wait in kernel */ /* wait in kernel */
while((*_rendezvousp)((ulong)mp, 1) == ~0) while((*_rendezvousp)((ulong)mp, 1) == ~0)
; ;
assert(mp->state == Waking);
mp->inuse = 0; mp->inuse = 0;
} }
@ -180,6 +184,7 @@ runlock(RWLock *q)
unlock(&q->lock); unlock(&q->lock);
/* wakeup waiter */ /* wakeup waiter */
p->state = Waking;
while((*_rendezvousp)((ulong)p, 0) == ~0) while((*_rendezvousp)((ulong)p, 0) == ~0)
; ;
} }
@ -212,6 +217,7 @@ wlock(RWLock *q)
/* wait in kernel */ /* wait in kernel */
while((*_rendezvousp)((ulong)mp, 1) == ~0) while((*_rendezvousp)((ulong)mp, 1) == ~0)
; ;
assert(mp->state == Waking);
mp->inuse = 0; mp->inuse = 0;
} }
@ -251,6 +257,7 @@ wunlock(RWLock *q)
if(q->head == nil) if(q->head == nil)
q->tail = nil; q->tail = nil;
unlock(&q->lock); unlock(&q->lock);
p->state = Waking;
while((*_rendezvousp)((ulong)p, 0) == ~0) while((*_rendezvousp)((ulong)p, 0) == ~0)
; ;
return; return;
@ -266,6 +273,7 @@ wunlock(RWLock *q)
p = q->head; p = q->head;
q->head = p->next; q->head = p->next;
q->readers++; q->readers++;
p->state = Waking;
while((*_rendezvousp)((ulong)p, 0) == ~0) while((*_rendezvousp)((ulong)p, 0) == ~0)
; ;
} }
@ -308,6 +316,7 @@ rsleep(Rendez *r)
if(r->l->head == nil) if(r->l->head == nil)
r->l->tail = nil; r->l->tail = nil;
unlock(&r->l->lock); unlock(&r->l->lock);
t->state = Waking;
while((*_rendezvousp)((ulong)t, 0x12345) == ~0) while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
; ;
}else{ }else{
@ -318,6 +327,7 @@ rsleep(Rendez *r)
/* wait for a wakeup */ /* wait for a wakeup */
while((*_rendezvousp)((ulong)me, 0x23456) == ~0) while((*_rendezvousp)((ulong)me, 0x23456) == ~0)
; ;
assert(me->state == Waking);
me->inuse = 0; me->inuse = 0;
if(!r->l->locked){ if(!r->l->locked){
fprint(2, "rsleep: not locked after wakeup\n"); fprint(2, "rsleep: not locked after wakeup\n");

View file

@ -28,11 +28,14 @@
If a rendezvous is interrupted the return value is ~0, so If a rendezvous is interrupted the return value is ~0, so
that value should not be used in normal communication. that value should not be used in normal communication.
* This simulates rendezvous with shared memory, pause, and SIGUSR1. * This simulates rendezvous with shared memory, sigsuspend, and SIGUSR1.
*/ */
#include <u.h>
#include <signal.h> #include <signal.h>
#include <lib9.h> #include <libc.h>
#define DBG 0
enum enum
{ {
@ -43,11 +46,11 @@ typedef struct Vous Vous;
struct Vous struct Vous
{ {
Vous *link; Vous *link;
Lock lk;
int pid; int pid;
int wakeup; int wokeup;
ulong val;
ulong tag; ulong tag;
ulong val1; /* value for the sleeper */
ulong val2; /* value for the waker */
}; };
static void static void
@ -57,9 +60,17 @@ ign(int x)
} }
void /*__attribute__((constructor))*/ void /*__attribute__((constructor))*/
ignusr1(void) ignusr1(int restart)
{ {
signal(SIGUSR1, ign); struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = ign;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGUSR1);
if(restart)
sa.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &sa, nil);
} }
static Vous vouspool[2048]; static Vous vouspool[2048];
@ -78,117 +89,112 @@ getvous(void)
vousfree = v->link; vousfree = v->link;
}else if(nvousused < nelem(vouspool)) }else if(nvousused < nelem(vouspool))
v = &vouspool[nvousused++]; v = &vouspool[nvousused++];
else else{
fprint(2, "rendezvous: out of vous!\n");
abort(); abort();
}
return v; return v;
} }
static void static void
putvous(Vous *v) putvous(Vous *v)
{ {
lock(&vouslock);
v->link = vousfree; v->link = vousfree;
vousfree = v; vousfree = v;
unlock(&vouslock);
} }
static Vous* static Vous*
findvous(ulong tag, ulong val, int pid) findvous(ulong tag)
{ {
int h; int h;
Vous *v, **l; Vous *v, **l;
lock(&vouslock);
h = tag%VOUSHASH; h = tag%VOUSHASH;
for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){ for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){
if(v->tag == tag){ if(v->tag == tag){
*l = v->link; *l = v->link;
unlock(&vouslock); v->link = nil;
return v; return v;
} }
} }
return nil;
}
static Vous*
mkvous(ulong tag)
{
Vous *v;
int h;
h = tag%VOUSHASH;
v = getvous(); v = getvous();
v->pid = pid;
v->link = voushash[h]; v->link = voushash[h];
v->val = val;
v->tag = tag; v->tag = tag;
lock(&v->lk);
voushash[h] = v; voushash[h] = v;
unlock(&vouslock);
return v; return v;
} }
#define DBG 0
ulong ulong
rendezvous(ulong tag, ulong val) rendezvous(ulong tag, ulong val)
{ {
int me, vpid; int vpid, pid;
ulong rval; ulong rval;
Vous *v; Vous *v;
sigset_t mask; sigset_t mask;
me = getpid(); pid = getpid();
v = findvous(tag, val, me); lock(&vouslock);
if(v->pid == me){ if((v = findvous(tag)) == nil){
if(DBG)fprint(2, "pid is %d tag %lux, sleeping\n", me, tag);
/* /*
* No rendezvous partner was found; the next guy * Go to sleep.
* through will find v and wake us, so we must go
* to sleep.
* *
* To go to sleep: * Block USR1, set the handler to interrupt system calls,
* 1. disable USR1 signals. * unlock the vouslock so our waker can wake us,
* 2. unlock v->lk (tells waker okay to signal us). * and then suspend.
* 3. atomically suspend and enable USR1 signals.
*
* The call to ignusr1() could be done once at
* process creation instead of every time through rendezvous.
*/ */
v->val = val; v = mkvous(tag);
ignusr1(); v->pid = pid;
sigprocmask(SIG_SETMASK, NULL, &mask); v->val2 = val;
v->wokeup = 0;
sigprocmask(SIG_SETMASK, nil, &mask);
sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_SETMASK, &mask, NULL); 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); sigdelset(&mask, SIGUSR1);
v->wakeup = 0; sigsuspend(&mask);
unlock(&v->lk);
for(;;){ /*
/* * We're awake. Make USR1 not interrupt system calls.
* There may well be random signals flying around, * Were we awakened or interrupted?
* so we can't be sure why we woke up. If we weren't */
* properly awakened, we need to go back to sleep. ignusr1(1);
*/ lock(&vouslock);
sigsuspend(&mask); if(v->wokeup){
lock(&v->lk); /* do some memory synchronization */ rval = v->val1;
unlock(&v->lk); if(DBG) fprint(2, "%d rv(%lux, %lux) -> g %lux\n", pid, tag, val, rval);
if(v->wakeup == 1) }else{
break; if(findvous(tag) != v){
fprint(2, "rendezvous: interrupted but not found in hash table\n");
abort();
}
rval = ~(ulong)0;
if(DBG) fprint(2, "%d rv(%lux, %lux) -> g i\n", pid, tag, val);
} }
rval = v->val;
if(DBG)fprint(2, "pid is %d, awake\n", me);
putvous(v); putvous(v);
unlock(&vouslock);
}else{ }else{
/* /*
* Found someone to meet. Wake him: * Wake up sleeper.
*
* A. lock v->lk (waits for him to get to his step 2)
* B. send a USR1
*
* He won't get the USR1 until he suspends, which
* means it must wake him up (it can't get delivered
* before he sleeps).
*/ */
rval = v->val2;
v->val1 = val;
vpid = v->pid; vpid = v->pid;
lock(&v->lk); v->wokeup = 1;
rval = v->val; if(DBG) fprint(2, "%d rv(%lux, %lux) -> g %lux, w %d\n", pid, tag, val, rval, vpid);
v->val = val; unlock(&vouslock);
v->wakeup = 1; kill(vpid, SIGUSR1);
unlock(&v->lk);
if(kill(vpid, SIGUSR1) < 0){
if(DBG)fprint(2, "pid is %d, kill %d failed: %r\n", me, vpid);
abort();
}
} }
return rval; return rval;
} }