git: 9front

Download patch

ref: bc4515d8003031b9b3b4a7d34b8fbd9bdfe1a439
parent: e056624897daf8446708a73bf7eecb136fb441eb
author: cinap_lenrek <cinap_lenrek@centraldogma>
date: Tue Jun 7 00:14:35 EDT 2011

kbdfs: simplify ctlproc by putting 9p handling in its own coroutine

--- a/sys/src/cmd/aux/kbdfs/kbdfs.c
+++ b/sys/src/cmd/aux/kbdfs/kbdfs.c
@@ -19,7 +19,6 @@
 
 	Rawon=	0,
 	Rawoff,
-	Kbdflush,
 
 	STACK = 8*1024,
 };
@@ -83,7 +82,8 @@
 char Enonexist[] = "file does not exist";
 char Ebadspec[] = "bad attach specifier";
 char Ewalk[] = "walk in non directory";
-char Efront[] = "the front fell off";
+char Ephase[] = "the front fell off";
+char Eintr[] = "interrupted";
 
 int scanfd;
 int ledsfd;
@@ -90,21 +90,23 @@
 int consfd;
 
 int kbdopen;
-int consopen;
 int consctlopen;
 
 int debug;
 
-Channel *keychan;	/* Key */
+Channel *keychan;	/* chan(Key) */
 
-Channel *reqchan;	/* Req* */
-Channel *ctlchan;	/* int */
+Channel *kbdreqchan;	/* chan(Req*) */
+Channel *consreqchan;	/* chan(Req*) */
 
-Channel *rawchan;	/* Rune */
-Channel *runechan;	/* Rune */
-Channel *linechan;	/* char * */
-Channel *kbdchan;	/* char* */
+Channel *ctlchan;	/* chan(int) */
 
+Channel *rawchan;	/* chan(Rune) */
+Channel *runechan;	/* chan(Rune) */
+
+Channel *conschan;	/* chan(char*) */
+Channel *kbdchan;	/* chan(char*) */
+
 /*
  * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
  * A 'standard' keyboard doesn't produce anything above 0x58.
@@ -366,7 +368,7 @@
 	nb = 0;
 	while(recv(keychan, &key) > 0){
 		if(key.down && key.r)
-			nbsend(rawchan, &key.r);
+			send(rawchan, &key.r);
 
 		rb[0] = 0;
 		for(i=0; i<nb && cb[i] != key.c; i++)
@@ -389,7 +391,7 @@
 			}
 			rb[0] = 'k';
 		}
-		if(rb[0]){
+		if(rb[0] && kbdopen){
 			s = utfconv(rb, nb+1);
 			if(nbsendp(kbdchan, s) <= 0)
 				free(s);
@@ -551,7 +553,8 @@
 	Rune rb[256], r;
 	Channel *cook;
 	int nr, done;
-	
+	char *s;
+
 	cook = aux;
 
 	threadsetname("lineproc");
@@ -585,34 +588,115 @@
 				fprint(1, "%C", r);
 			}
 		} while(!done && nr < nelem(rb));
-		sendp(linechan, utfconv(rb, nr));
+		s = utfconv(rb, nr);
+		if(nbsendp(conschan, s) <= 0)
+			free(s);
 	}
 }
 
 /*
- * Queue reads to cons and kbd, flushing and
- * relay data between 9p and rawchan / kbdchan.
+ * Reads Tread and Tflush requests from reqchan and responds
+ * to them with data received on the string channel.
  */
 void
+reqproc(void *aux)
+{
+	enum { AREQ, ASTR, AEND };
+	Alt a[AEND+1];
+	Channel **ac;
+	Req *r, *q, **qq;
+	char *s, *p, *e;
+	int n;
+
+	threadsetname("reqproc");
+
+	s = nil;
+	p = nil;
+
+	q = nil;
+	qq = &q;
+
+	ac = aux;
+	a[AREQ].c = ac[0];	/* chan(Req*) */
+	a[AREQ].v = &r;
+	a[ASTR].c = ac[1];	/* chan(char*) */
+	a[ASTR].v = &s;
+	a[AEND].op = CHANEND;
+
+	for(;;){
+		a[AREQ].op = CHANRCV;
+		a[ASTR].op = (q != nil && s == nil) ? CHANRCV : CHANNOP;
+		switch(alt(a)){
+		case AREQ:
+			if(r->ifcall.type == Tflush){
+				Req **rr, **xx;
+
+				for(rr = &q; *rr; rr=xx){
+					xx = &((*rr)->aux);
+					if(*rr == r->oldreq){
+						if((*rr = *xx) == nil)
+							qq = rr;
+						respond(r->oldreq, Eintr);
+						break;
+					}
+				}
+				respond(r, nil);
+				continue;
+			} else if(r->ifcall.type != Tread){
+				respond(r, Ephase);
+				continue;
+			}
+			r->aux = nil;
+			*qq = r;
+			qq = &r->aux;
+
+			if(0){
+		case ASTR:
+				p = s;
+			} else if(s == nil)
+				continue;
+			if((r = q) == nil)
+				continue;
+			if((q = q->aux) == nil)
+				qq = &q;
+
+			e = s + strlen(s);
+			if(p == s && r->fid->qid.path == Qkbd)
+				e++; /* send terminating \0 if its kbd file */
+
+			n = e - p;
+			if(n > r->ifcall.count)
+				n = r->ifcall.count;
+
+			r->ofcall.count = n;
+			memmove(r->ofcall.data, p, n);
+			respond(r, nil);
+
+			p += n;
+			if(p >= e){
+				free(s);
+				s = nil;
+			}
+		}
+	}
+}
+
+/*
+ * Keep track of rawing state and distribute the runes from
+ * runechan to the right channels depending on the state.
+ */
+void
 ctlproc(void *)
 {
-	struct {
-		Req *h;
-		Req **t;
-	} qcons, qkbd, *q;
-	enum { Areq, Actl, Arune, Aline, Akbd, Aend };
-	Alt a[Aend+1];
-	Req *req;
-	Fid *fid;
+	Channel *cook, *aconsr[2], *akbdr[2];
+	enum { ACTL, ARUNE, AEND };
+	Alt a[AEND+1];
 	Rune r;
-	char *s, *b, *p, *e;
-	int c, n, raw;
-	Channel *cook;
+	int c, raw;
+	char *s;
 
 	threadsetname("ctlproc");
 
-	cook = chancreate(sizeof(Rune), 0);
-
 	if(scanfd >= 0)
 		proccreate(scanproc, nil, STACK);	/* scanfd -> keychan */
 	if(consfd >= 0)
@@ -620,157 +704,60 @@
 
 	threadcreate(keyproc, nil, STACK);		/* keychan -> rawchan, kbdchan */
 	threadcreate(runeproc, nil, STACK);		/* rawchan -> runechan */
-	threadcreate(lineproc, cook, STACK);		/* cook -> linechan */
 
-	raw = 0;
+	aconsr[0] = consreqchan;
+	aconsr[1] = conschan;
+	threadcreate(reqproc, aconsr, STACK);		/* consreqchan,conschan -> respond */
 
-	b = p = e = nil;
+	akbdr[0] = kbdreqchan;
+	akbdr[1] = kbdchan;
+	threadcreate(reqproc, akbdr, STACK);		/* kbdreqchan,kbdchan -> respond */
 
-	qcons.h = nil;
-	qcons.t = &qcons.h;
-	qkbd.h = nil;
-	qkbd.t = &qkbd.h;
+	cook = chancreate(sizeof(Rune), 0);
+	threadcreate(lineproc, cook, STACK);		/* cook -> conschan */
 
-	memset(a, 0, sizeof a);
+	raw = 0;
 
-	a[Areq].c = reqchan;
-	a[Areq].v = &req;
-	a[Areq].op = CHANRCV;
+	a[ACTL].c = ctlchan;
+	a[ACTL].v = &c;
+	a[ACTL].op = CHANRCV;
 
-	a[Actl].c = ctlchan;
-	a[Actl].v = &c;
-	a[Actl].op = CHANRCV;
+	a[ARUNE].c = runechan;
+	a[ARUNE].v = &r;
+	a[ARUNE].op = CHANRCV;
 
-	a[Arune].c = runechan;
-	a[Arune].v = &r;
-	a[Arune].op = CHANRCV;
+	a[AEND].op = CHANEND;
 
-	a[Aline].c = linechan;
-	a[Aline].v = &s;
-	a[Aline].op = CHANRCV;
-
-	a[Akbd].c = kbdchan;
-	a[Akbd].v = &s;
-	a[Akbd].op = CHANRCV;
-
-	a[Aend].op = CHANEND;
-
 	for(;;){
-		s = nil;
-
-		if(kbdopen){
-			a[Arune].op = qkbd.h ? CHANRCV : CHANNOP;
-			a[Akbd].op = qkbd.h ? CHANRCV : CHANNOP;
-			a[Aline].op = CHANNOP;
-		}else{
-			a[Arune].op = (b == nil) ? CHANRCV : CHANNOP;
-			a[Akbd].op = CHANRCV;
-			a[Aline].op = (b == nil) ? CHANRCV : CHANNOP;
-		}
-
 		switch(alt(a)){
-		case Areq:
-			fid = req->fid;
-			if(req->ifcall.type == Tflush){
-				Req **rr;
-
-				fid = req->oldreq->fid;
-				q = fid->qid.path == Qcons ? &qcons : &qkbd;
-				for(rr = &q->h; *rr && *rr != req->oldreq; rr = &((*rr)->aux))
-					;
-				if(*rr == req->oldreq){
-					if((*rr = req->oldreq->aux) == nil)
-						q->t = rr;
-					req->oldreq->aux = nil;
-					respond(req->oldreq, "interrupted");
-				}
-				respond(req, nil);
-			} else if(req->ifcall.type == Tread){
-				q = fid->qid.path == Qcons ? &qcons : &qkbd;
-				req->aux = nil;
-				*q->t = req;
-				q->t = &req->aux;
-				goto Havereq;
-			} else
-				respond(req, Efront);
-			break;
-
-		case Actl:
+		case ACTL:
 			switch(c){
 			case Rawoff:
 			case Rawon:
 				if(raw = (c == Rawon)){
-					while(s = nbrecvp(linechan))
-						free(s);
-					r = '\0';
-					send(cook, &r);
-					free(b);
-					b = nil;
+					r = 0;
+					nbsend(cook, &r);
 				}
-				break;
-			case Kbdflush:
-				while(s = nbrecvp(kbdchan))
-					free(s);
-				break;
 			}
 			break;
-
-		case Arune:
+		case ARUNE:
 			if(kbdopen){
 				s = emalloc9p(UTFmax+2);
 				s[0] = 'c';
 				s[1+runetochar(s+1, &r)] = 0;
-				goto Havekbd;
+				if(nbsendp(kbdchan, s) <= 0)
+					free(s);
+				break;
 			}
-
 			if(raw){
 				s = emalloc9p(UTFmax+1);
 				s[runetochar(s, &r)] = 0;
-			} else {
-				nbsend(cook, &r);
+				if(nbsendp(conschan, s) <= 0)
+					free(s);
 				break;
 			}
-			/* no break */
-
-		case Aline:
-			b = s;
-			p = s;
-			e = s + strlen(s);
-
-		Havereq:
-			while(b && (req = qcons.h)){
-				if((qcons.h = req->aux) == nil)
-					qcons.t = &qcons.h;
-				n = e - p;
-				if(req->ifcall.count < n)
-					n = req->ifcall.count;
-				req->ofcall.count = n;
-				memmove(req->ofcall.data, p, n);
-				respond(req, nil);
-				p += n;
-				if(p >= e){
-					free(b);
-					b = nil;
-				}
-			}
+			nbsend(cook, &r);
 			break;
-
-		case Akbd:
-		Havekbd:
-			if(req = qkbd.h){
-				if((qkbd.h = req->aux) == nil)
-					qkbd.t = &qkbd.h;
-				n = strlen(s) + 1;
-				if(n > req->ifcall.count)
-					respond(req, Eshort);
-				else {
-					req->ofcall.count = n;
-					memmove(req->ofcall.data, s, n);
-					respond(req, nil);
-				}
-			}
-			free(s);
-			break;
 		}
 	}
 }
@@ -1011,11 +998,7 @@
 				return;
 			}
 			kbdopen++;
-			sendul(ctlchan, Kbdflush);
 			break;
-		case Qcons:
-			consopen++;
-			break;
 		case Qconsctl:
 			consctlopen++;
 			break;
@@ -1055,19 +1038,18 @@
 	f = r->fid;
 	switch((ulong)f->qid.path){
 	default:
-		respond(r, Efront);
+		respond(r, Ephase);
 		return;
-
 	case Qroot:
 		r->ofcall.count = readtopdir(f, (void*)r->ofcall.data, r->ifcall.offset,
 			r->ifcall.count, r->ifcall.count);
 		break;
-
 	case Qkbd:
+		sendp(kbdreqchan, r);
+		return;
 	case Qcons:
-		sendp(reqchan, r);
+		sendp(consreqchan, r);
 		return;
-
 	case Qkbmap:
 		kbmapread(r);
 		return;
@@ -1085,7 +1067,7 @@
 	f = r->fid;
 	switch((ulong)f->qid.path){
 	default:
-		respond(r, Efront);
+		respond(r, Ephase);
 		return;
 
 	case Qcons:
@@ -1134,8 +1116,10 @@
 {
 	switch((ulong)r->oldreq->fid->qid.path) {
 	case Qkbd:
+		sendp(kbdreqchan, r);
+		return;
 	case Qcons:
-		sendp(reqchan, r);
+		sendp(consreqchan, r);
 		return;
 	}
 	respond(r, nil);
@@ -1156,12 +1140,8 @@
 			}
 			break;
 		case Qkbd:
-			if(--kbdopen == 0)
-				sendul(ctlchan, Kbdflush);
+			kbdopen--;
 			break;
-		case Qcons:
-			consopen--;
-			break;
 		case Qconsctl:
 			if(--consctlopen == 0)
 				sendul(ctlchan, Rawoff);
@@ -1278,16 +1258,15 @@
 		if((consfd = open(*argv, OREAD)) < 0)
 			fprint(2, "%s: warning: can't open %s: %r\n", argv0, *argv);
 
+	consreqchan = chancreate(sizeof(Req*), 0);
+	kbdreqchan = chancreate(sizeof(Req*), 0);
+
 	keychan = chancreate(sizeof(Key), 8);
-	reqchan = chancreate(sizeof(Req*), 0);
 	ctlchan = chancreate(sizeof(int), 0);
-	rawchan = chancreate(sizeof(Rune), 16);
+	rawchan = chancreate(sizeof(Rune), 0);
 	runechan = chancreate(sizeof(Rune), 32);
-	linechan = chancreate(sizeof(char*), 16);
+	conschan = chancreate(sizeof(char*), 16);
 	kbdchan = chancreate(sizeof(char*), 16);
-
-	if(!(keychan && reqchan && ctlchan && rawchan && runechan && linechan && kbdchan))
-		sysfatal("allocating chans");
 
 	elevate();
 	procrfork(ctlproc, nil, STACK, RFNAMEG|RFNOTEG);
--