code: plan9front

Download patch

ref: a1d252ff9b58c9c9bf3bf8765e4cf2c988ed51d4
parent: 03f9392b3a4583f36b8c5d961733bae00bc9417e
author: Jacob Moody <moody@posixcafe.org>
date: Tue Sep 27 22:33:23 EDT 2022

rio: ensure single reader and single writer for kbdtap

Multiple readers eat each other's lunch, and it makes more
sense to limit use to one 'pipeline' then just one reader.

This also brings back the 'focus' message from kbdtap used
by ktrans to reset its line buffers when the user switches
windows. An event file was considered, but deemed harmful
to the artwork. To paraphrase an old excuse found in the code:
"rio just isn't structured for that. Apologies."

--- a/sys/src/cmd/ktrans/main.c
+++ b/sys/src/cmd/ktrans/main.c
@@ -497,7 +497,7 @@
 
 	threadsetname("keytrans");
 	while(recv(input, &m) != -1){
-		if(m.code == 'r'){
+		if(m.code == 'z'){
 			emitutf(dictch, "", 1);
 			resetstr(&line, nil);
 			continue;
@@ -609,7 +609,7 @@
 			p++;
 			switch(msg.code){
 			case 'c': case 'k': case 'K':
-			case 'r':
+			case 'z':
 				break;
 			default:
 				goto Drop;
--- a/sys/src/cmd/rio/dat.h
+++ b/sys/src/cmd/rio/dat.h
@@ -318,11 +318,14 @@
 enum{
 	Tapon = 'b',
 	Tapoff = 'e',
+	Tapfocus = 'z',
 };
-Channel *ctltap;	/* on/off messages */
+Channel *ctltap;	/* open/close */
+Channel *resptap;	/* open/close err */
 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
@@ -199,7 +199,8 @@
 	totap = chancreate(sizeof(char*), 32);
 	fromtap = chancreate(sizeof(char*), 32);
 	wintap = chancreate(sizeof(Window*), 0);
-	ctltap = chancreate(sizeof(Window*), 0);
+	ctltap = chancreate(sizeof(char*), 0);
+	resptap = chancreate(sizeof(char*), 0);
 	proccreate(keyboardtap, nil, STACK);
 
 	wscreen = allocscreen(screen, background, 0);
@@ -350,17 +351,48 @@
 			write(window[i]->notefd, "hangup", 6); 
 }
 
+static int tapseats[] = { [OREAD] Tapoff, [OWRITE] Tapoff };
+
+char*
+tapctlmsg(char *msg)
+{
+	int perm;
+
+	perm = msg[1];
+	switch(msg[0]){
+	case Tapoff:
+		if(perm == ORDWR)
+			tapseats[OREAD] = Tapoff, tapseats[OWRITE] = Tapoff;
+		else
+			tapseats[perm] = Tapoff;
+		break;
+	case Tapon:
+		switch(perm){
+		case ORDWR:
+			if(tapseats[OREAD] != Tapoff || tapseats[OWRITE] != Tapoff)
+				return "seat taken";
+			tapseats[OREAD] = Tapon, tapseats[OWRITE] = Tapon;
+			break;
+		case OREAD: case OWRITE:
+			if(tapseats[perm] != Tapoff)
+				return "seat taken";
+			tapseats[perm] = Tapon;
+			break;
+		}
+		break;
+	}
+	return nil;
+}
+
 void
 keyboardtap(void*)
 {
 	char *s, *ctl;
+	char *watched;
 	Window *w, *cur;
-	int mode;
-	enum { Awin, Actl, Afrom, Adev, Ato, Ainp, NALT };
-	enum { Mnorm, Mtap };
 
-	threadsetname("keyboardtap");	
-
+	threadsetname("keyboardtap");
+	enum { Awin, Actl, Afrom, Adev, Ato, Ainp, Awatch, NALT };
 	static Alt alts[NALT+1];
 	/* ctl */
 	alts[Awin].c = wintap;
@@ -383,10 +415,13 @@
 	alts[Ainp].c = nil;
 	alts[Ainp].v = &s;
 	alts[Ainp].op = CHANNOP;
+	alts[Awatch].c = totap;
+	alts[Awatch].v = &watched;
+	alts[Awatch].op = CHANNOP;
 	alts[NALT].op = CHANEND;
 
 	cur = nil;
-	mode = Mnorm;
+	watched = nil;
 	for(;;)
 		switch(alt(alts)){
 		case Awin:
@@ -393,20 +428,18 @@
 			cur = w;
 			if(cur != nil){
 				alts[Ainp].c = cur->ck;
-				break;
+				if(tapseats[OREAD] == Tapoff)	
+					break;
+				if(alts[Awatch].op == CHANSND)
+					free(watched);
+				watched = smprint("%c%d", Tapfocus, cur->id);
+				alts[Awatch].op = CHANSND;
 			}
 			if(alts[Ainp].op != CHANNOP || alts[Ato].op != CHANNOP)
 				free(s);
 			goto Reset;
 		case Actl:
-			switch(*ctl){
-			case Tapon:
-				mode = Mtap;
-				break;
-			case Tapoff:
-				mode = Mnorm;
-				break;
-			}
+			sendp(resptap, tapctlmsg(ctl));
 			free(ctl);
 			break;
 		case Afrom:
@@ -420,16 +453,19 @@
 			alts[Ainp].op = CHANSND;
 			break;
 		case Adev:
-			if(mode == Mnorm && cur == nil){
+			if(tapseats[OWRITE] == Tapoff && cur == nil){
 				free(s);
 				break;
 			}
 			alts[Afrom].op = CHANNOP;
 			alts[Adev].op = CHANNOP;
-			if(mode == Mnorm)
+			if(tapseats[OWRITE] == Tapoff)
 				alts[Ainp].op = CHANSND;
 			else
 				alts[Ato].op = CHANSND;
+			break;
+		case Awatch:
+			alts[Awatch].op = CHANNOP;
 			break;
 		case Ainp:
 			if(*s == 'k' || *s == 'K')
--- a/sys/src/cmd/rio/xfid.c
+++ b/sys/src/cmd/rio/xfid.c
@@ -247,6 +247,7 @@
 {
 	Fcall t;
 	Window *w;
+	char *s;
 
 	w = x->f->w;
 	if(w != nil && w->deleted){
@@ -312,8 +313,12 @@
 		}
 		break;
 	case Qtap:
-		chanprint(ctltap, "%c", Tapon);
-		break;
+		chanprint(ctltap, "%c%c", Tapon, x->mode);
+		s = recvp(resptap);
+		if(s == nil)
+			break;
+		filsysrespond(x->fs, x, &t, s);
+		return;
 	}
 	t.qid = x->f->qid;
 	t.iounit = messagesize-IOHDRSZ;
@@ -369,7 +374,8 @@
 			w->wctlopen = FALSE;
 		break;
 	case Qtap:
-		chanprint(ctltap, "%c", Tapoff);
+		chanprint(ctltap, "%c%c", Tapoff, x->f->mode);
+		recvp(resptap);
 		break;
 	}
 	if(w)
@@ -581,12 +587,18 @@
 		}
 		e = x->data + cnt;
 		for(p = x->data; p < e; p += strlen(p)+1){
-			if(*p == '\0'){
+			switch(*p){
+			case '\0':
 				fc.count = p - x->data;
 				filsysrespond(x->fs, x, &fc, "null message type");
 				return;
+			case Tapfocus:
+				/* cleanup our own pollution */
+				break;
+			default:
+				chanprint(fromtap, "%s", p);
+				break;	
 			}
-			chanprint(fromtap, "%s", p);
 		}
 		break;