mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
various bug fixes and paranoia
This commit is contained in:
parent
a09e80f9c4
commit
6c7460701e
3 changed files with 87 additions and 70 deletions
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue