git: 9front

Download patch

ref: f96bae7a1d09fede6a6c884c166c93ec37f4a60d
parent: dd454a23cfd5bf956f4d1be7b35ae6e5fd94be0a
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);
--