Commit Diff


commit - a09e80f9c414ffc815641d49836be3a2a6a07800
commit + 6c7460701e7896446d0fb14bf9b24f258c61b6a6
blob - 26487babb0be41e3751f1d84f467cebcfe8e391a
blob + 9156f8912211a1859edce58fb9f64e3493310771
--- src/lib9/notify.c
+++ src/lib9/notify.c
@@ -35,6 +35,7 @@ static struct {
 	SIGVTALRM, 0,
 	SIGUSR1, 0,
 	SIGUSR2, 0,
+	SIGWINCH, 1,
 #ifdef SIGINFO
 	SIGINFO, 0,
 #endif
blob - 00bbcc7d7deb3b90b26204bcdc6aaab8bbb891f6
blob + d83a4b7f7bb583c18ad6f307ffab48c7d7c4f76b
--- src/lib9/qlock.c
+++ src/lib9/qlock.c
@@ -13,6 +13,7 @@ enum
 	QueuingR,
 	QueuingW,
 	Sleeping,
+	Waking,
 };
 
 static ulong	(*_rendezvousp)(ulong, ulong) = rendezvous;
@@ -74,6 +75,7 @@ qlock(QLock *q)
 	/* wait */
 	while((*_rendezvousp)((ulong)mp, 1) == ~0)
 		;
+	assert(mp->state == Waking);
 	mp->inuse = 0;
 }
 
@@ -90,6 +92,7 @@ qunlock(QLock *q)
 		if(q->head == nil)
 			q->tail = nil;
 		unlock(&q->lock);
+		p->state = Waking;
 		while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
 			;
 		return;
@@ -139,6 +142,7 @@ rlock(RWLock *q)
 	/* wait in kernel */
 	while((*_rendezvousp)((ulong)mp, 1) == ~0)
 		;
+	assert(mp->state == Waking);
 	mp->inuse = 0;
 }
 
@@ -180,6 +184,7 @@ runlock(RWLock *q)
 	unlock(&q->lock);
 
 	/* wakeup waiter */
+	p->state = Waking;
 	while((*_rendezvousp)((ulong)p, 0) == ~0)
 		;
 }
@@ -212,6 +217,7 @@ wlock(RWLock *q)
 	/* wait in kernel */
 	while((*_rendezvousp)((ulong)mp, 1) == ~0)
 		;
+	assert(mp->state == Waking);
 	mp->inuse = 0;
 }
 
@@ -251,6 +257,7 @@ wunlock(RWLock *q)
 		if(q->head == nil)
 			q->tail = nil;
 		unlock(&q->lock);
+		p->state = Waking;
 		while((*_rendezvousp)((ulong)p, 0) == ~0)
 			;
 		return;
@@ -266,6 +273,7 @@ wunlock(RWLock *q)
 		p = q->head;
 		q->head = p->next;
 		q->readers++;
+		p->state = Waking;
 		while((*_rendezvousp)((ulong)p, 0) == ~0)
 			;
 	}
@@ -308,6 +316,7 @@ rsleep(Rendez *r)
 		if(r->l->head == nil)
 			r->l->tail = nil;
 		unlock(&r->l->lock);
+		t->state = Waking;
 		while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
 			;
 	}else{
@@ -318,6 +327,7 @@ rsleep(Rendez *r)
 	/* wait for a wakeup */
 	while((*_rendezvousp)((ulong)me, 0x23456) == ~0)
 		;
+	assert(me->state == Waking);
 	me->inuse = 0;
 	if(!r->l->locked){
 		fprint(2, "rsleep: not locked after wakeup\n");
blob - 6c15e7ec755dffbf5e056b0d66d54b7151bd36fb
blob + 5709dd76e0478a8176f6f99e69ee407e14d0f5d4
--- src/lib9/rendez-signal.c
+++ src/lib9/rendez-signal.c
@@ -28,12 +28,15 @@
           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, pause, and SIGUSR1.
+ * This simulates rendezvous with shared memory, sigsuspend, and SIGUSR1.
  */
 
+#include <u.h>
 #include <signal.h>
-#include <lib9.h>
+#include <libc.h>
 
+#define DBG 0
+
 enum
 {
 	VOUSHASH = 257,
@@ -43,11 +46,11 @@ typedef struct Vous Vous;
 struct Vous
 {
 	Vous *link;
-	Lock lk;
 	int pid;
-	int wakeup;
-	ulong val;
+	int wokeup;
 	ulong tag;
+	ulong val1;		/* value for the sleeper */
+	ulong val2;		/* value for the waker */
 };
 
 static void
@@ -57,9 +60,17 @@ ign(int x)
 }
 
 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];
@@ -78,117 +89,112 @@ getvous(void)
 		vousfree = v->link;
 	}else if(nvousused < nelem(vouspool))
 		v = &vouspool[nvousused++];
-	else
+	else{
+		fprint(2, "rendezvous: out of vous!\n");
 		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 pid)
+findvous(ulong tag)
 {
 	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;
-			unlock(&vouslock);
+			v->link = nil;
 			return v;
 		}
 	}
+	return nil;
+}
+
+static Vous*
+mkvous(ulong tag)
+{
+	Vous *v;
+	int h;
+
+	h = tag%VOUSHASH;
 	v = getvous();
-	v->pid = pid;
 	v->link = voushash[h];
-	v->val = val;
 	v->tag = tag;
-	lock(&v->lk);
 	voushash[h] = v;
-	unlock(&vouslock);
 	return v;
 }
 
-#define DBG 0
 ulong
 rendezvous(ulong tag, ulong val)
 {
-	int me, vpid;
+	int vpid, pid;
 	ulong rval;
 	Vous *v;
 	sigset_t mask;
 
-	me = getpid();
-	v = findvous(tag, val, me);
-	if(v->pid == me){
-		if(DBG)fprint(2, "pid is %d tag %lux, sleeping\n", me, tag);
+	pid = getpid();
+	lock(&vouslock);
+	if((v = findvous(tag)) == nil){
 		/*
-		 * No rendezvous partner was found; the next guy
-		 * through will find v and wake us, so we must go
-		 * to sleep.
+		 * Go to sleep.
 		 *
-		 * To go to sleep:
-		 *	1. disable USR1 signals.
-		 *	2. unlock v->lk (tells waker okay to signal us).
-		 *	3. atomically suspend and enable USR1 signals.
-		 *
-		 * The call to ignusr1() could be done once at 
-		 * process creation instead of every time through rendezvous.
+		 * Block USR1, set the handler to interrupt system calls,
+		 * unlock the vouslock so our waker can wake us,
+		 * and then suspend.
 		 */
-		v->val = val;
-		ignusr1();
-		sigprocmask(SIG_SETMASK, NULL, &mask);
+		v = mkvous(tag);
+		v->pid = pid;
+		v->val2 = val;
+		v->wokeup = 0;
+		sigprocmask(SIG_SETMASK, nil, &mask);
 		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);
-		v->wakeup = 0;
-		unlock(&v->lk);
-		for(;;){
-			/*
-			 * There may well be random signals flying around,
-			 * so we can't be sure why we woke up.  If we weren't
-			 * properly awakened, we need to go back to sleep.
-			 */
-			sigsuspend(&mask);
-			lock(&v->lk);	/* do some memory synchronization */
-			unlock(&v->lk);
-			if(v->wakeup == 1)
-				break;
+		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, tag, val, rval);
+		}else{
+			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);
+		unlock(&vouslock);
 	}else{
 		/*
-		 * Found someone to meet.  Wake him:
-		 *
-		 *	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).
+		 * Wake up sleeper.
 		 */
+		rval = v->val2;
+		v->val1 = val;
 		vpid = v->pid;
-		lock(&v->lk);
-		rval = v->val;
-		v->val = val;
-		v->wakeup = 1;
-		unlock(&v->lk);
-		if(kill(vpid, SIGUSR1) < 0){
-			if(DBG)fprint(2, "pid is %d, kill %d failed: %r\n", me, vpid);
-			abort();
-		}
+		v->wokeup = 1;
+		if(DBG) fprint(2, "%d rv(%lux, %lux) -> g %lux, w %d\n", pid, tag, val, rval, vpid);
+		unlock(&vouslock);
+		kill(vpid, SIGUSR1);
 	}
 	return rval;
 }
-