code: plan9front

Download patch

ref: 6c8de2713c34622799504f9817afe6876c5621cf
parent: aea866a49300a5e31e737d8fe54763711e693f05
author: Jacob Moody <moody@posixcafe.org>
date: Sun Aug 21 18:24:45 EDT 2022

rio: kbdtap deadlocks are verboden

This should make kbdtap related deadlocks
impossible. The tap thread has been rewritten
to use one alt which always allows for the window
handling code to nofiy us regardless if we're send'ing or
recv'ing. We also move the start/stop messages to their
own channel and can the reset code for now.

--- a/sys/src/cmd/rio/dat.h
+++ b/sys/src/cmd/rio/dat.h
@@ -121,12 +121,6 @@
 	uchar	qfull;	/* filled the queue; no more recording until client comes back */	
 };
 
-enum{
-	Tapon = 'b',
-	Tapoff = 'e',
-	Tapreset = 'r',
-};
-
 struct Window
 {
 	Ref;
@@ -322,8 +316,15 @@
 int		snarffd;
 int		gotscreen;
 int		servekbd;
-Channel	*fromtap; 	/* input from kbd tap program to window */
-Channel *totap; 	/* our keyboard input to tap program */
+
+enum{
+	Tapon = 'b',
+	Tapoff = 'e',
+};
+Channel *ctltap;	/* on/off messages */
+Channel	*fromtap;	/* input from kbd tap program to window */
+Channel *totap;		/* our keyboard input to tap program */
+Channel *wintap;	/* tell the tapthread which Window to send to */
 Window	*input;
 QLock	all;			/* BUG */
 Filsys	*filsys;
--- a/sys/src/cmd/rio/rio.c
+++ b/sys/src/cmd/rio/rio.c
@@ -198,6 +198,8 @@
 		error("can't find keyboard");
 	totap = chancreate(sizeof(char*), 32);
 	fromtap = chancreate(sizeof(char*), 32);
+	wintap = chancreate(sizeof(Window*), 0);
+	ctltap = chancreate(sizeof(Window*), 0);
 	proccreate(keyboardtap, nil, STACK);
 
 	wscreen = allocscreen(screen, background, 0);
@@ -339,62 +341,93 @@
 void
 keyboardtap(void*)
 {
-	char *s;
-	Channel *out;
+	char *s, *ctl;
+	Window *w, *cur;
 	int mode;
-	enum { Kdev, Ktap, NALT};
+	enum { Awin, Actl, Afrom, Adev, Ato, Ainp, NALT };
 	enum { Mnorm, Mtap };
 
 	threadsetname("keyboardtap");	
 
 	static Alt alts[NALT+1];
-	alts[Kdev].c = kbdchan;
-	alts[Kdev].v = &s;
-	alts[Kdev].op = CHANRCV;
-	alts[Ktap].c = fromtap;
-	alts[Ktap].v = &s;
-	alts[Ktap].op = CHANRCV;
+	/* ctl */
+	alts[Awin].c = wintap;
+	alts[Awin].v = &w;
+	alts[Awin].op = CHANRCV;
+	alts[Actl].c = ctltap;
+	alts[Actl].v = &ctl;
+	alts[Actl].op = CHANRCV;
+	/* kbd input */
+	alts[Afrom].c = fromtap;
+	alts[Afrom].v = &s;
+	alts[Afrom].op = CHANRCV;
+	alts[Adev].c = kbdchan;
+	alts[Adev].v = &s;
+	alts[Adev].op = CHANRCV;
+	/* kbd output */
+	alts[Ato].c = totap;
+	alts[Ato].v = &s;
+	alts[Ato].op = CHANNOP;
+	alts[Ainp].c = nil;
+	alts[Ainp].v = &s;
+	alts[Ainp].op = CHANNOP;
 	alts[NALT].op = CHANEND;
 
-	out = nil;
+	cur = nil;
 	mode = Mnorm;
 	for(;;)
 		switch(alt(alts)){
-		case Ktap:
-			switch(*s){
-			case 'K': case 'k': case 'c':
+		case Awin:
+			cur = w;
+			if(cur != nil){
+				alts[Ainp].c = cur->ck;
 				break;
-			case Tapreset:
-				if(mode != Mtap)
-					goto Next;
-				goto Send;
-			case Tapoff:
-				mode = Mnorm;
-				goto Next;
+			}
+			if(alts[Ainp].op != CHANNOP || alts[Ato].op != CHANNOP)
+				free(s);
+			goto Reset;
+		case Actl:
+			switch(*ctl){
 			case Tapon:
 				mode = Mtap;
-				/* fallthrough */
-			default:
-			Next:
+				break;
+			case Tapoff:
+				mode = Mnorm;
+				break;
+			}
+			free(ctl);
+			break;
+		case Afrom:
+			if(cur == nil){
 				free(s);
-				continue;
+				break;
 			}
-			out = input == nil ? nil : input->ck;
-			goto Send;
-		case Kdev:
-			switch(mode){
-			case Mnorm:
-				out = input == nil ? nil : input->ck;
+			alts[Afrom].op = CHANNOP;
+			alts[Adev].op = CHANNOP;
+			alts[Ato].op = CHANNOP;
+			alts[Ainp].op = CHANSND;
+			break;
+		case Adev:
+			if(mode == Mnorm && cur == nil){
+				free(s);
 				break;
-			case Mtap:
-				out = totap;
-				break;
 			}
-		Send:
+			alts[Afrom].op = CHANNOP;
+			alts[Adev].op = CHANNOP;
+			if(mode == Mnorm)
+				alts[Ainp].op = CHANSND;
+			else
+				alts[Ato].op = CHANSND;
+			break;
+		case Ainp:
 			if(*s == 'k' || *s == 'K')
 				shiftdown = utfrune(s+1, Kshift) != nil;
-			if(out == nil || sendp(out, s) <= 0)
-				free(s);
+		case Ato:
+		Reset:
+			alts[Ainp].op = CHANNOP;
+			alts[Ato].op = CHANNOP;
+			alts[Afrom].op = CHANRCV;
+			alts[Adev].op = CHANRCV;
 			break;
 		}
 }
--- a/sys/src/cmd/rio/wind.c
+++ b/sys/src/cmd/rio/wind.c
@@ -83,13 +83,14 @@
 	Channel *c;
 
 	if(input == nil){
+		sendp(wintap, w);
 		input = w;
 		return;
 	}
 	if(w == input)
 		return;
-	chanprint(fromtap, "%c", Tapreset);
 	incref(input);
+	sendp(wintap, w);
 	c = chancreate(sizeof(Window*), 0);
 	wsendctlmesg(input, Repaint, ZR, c);
 	sendp(c, w);		/* send the new input */
@@ -1304,6 +1305,7 @@
 		return;
 	w->deleted = TRUE;
 	if(w == input){
+		sendp(wintap, nil);
 		input = nil;
 		riosetcursor(nil);
 	}
--- a/sys/src/cmd/rio/xfid.c
+++ b/sys/src/cmd/rio/xfid.c
@@ -308,7 +308,7 @@
 		}
 		break;
 	case Qtap:
-		chanprint(fromtap, "%c", Tapon);
+		chanprint(ctltap, "%c", Tapon);
 		break;
 	}
 	t.qid = x->f->qid;
@@ -365,7 +365,7 @@
 			w->wctlopen = FALSE;
 		break;
 	case Qtap:
-		chanprint(fromtap, "%c", Tapoff);
+		chanprint(ctltap, "%c", Tapoff);
 		break;
 	}
 	wclose(w);