]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/aux/kbdfs/kbdfs.c
kbdfs: simplify ctlproc by putting 9p handling in its own coroutine
[plan9front.git] / sys / src / cmd / aux / kbdfs / kbdfs.c
index 9932f8daef3c0b3754c4ea4aae44c5f3c2be0b66..fce22aa2a984379ed137ca0933154ffe9d2af3ac 100644 (file)
@@ -19,7 +19,6 @@ enum {
 
        Rawon=  0,
        Rawoff,
-       Kbdflush,
 
        STACK = 8*1024,
 };
@@ -83,27 +82,30 @@ char Einuse[] = "file in use";
 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;
 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.
@@ -366,7 +368,7 @@ keyproc(void *)
        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 @@ keyproc(void *)
                        }
                        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 @@ lineproc(void *aux)
        Rune rb[256], r;
        Channel *cook;
        int nr, done;
-       
+       char *s;
+
        cook = aux;
 
        threadsetname("lineproc");
@@ -585,34 +588,115 @@ lineproc(void *aux)
                                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,156 +704,59 @@ ctlproc(void *)
 
        threadcreate(keyproc, nil, STACK);              /* keychan -> rawchan, kbdchan */
        threadcreate(runeproc, nil, STACK);             /* rawchan -> runechan */
-       threadcreate(lineproc, cook, STACK);            /* cook -> linechan */
-
-       raw = 0;
-
-       b = p = e = nil;
-
-       qcons.h = nil;
-       qcons.t = &qcons.h;
-       qkbd.h = nil;
-       qkbd.t = &qkbd.h;
 
-       memset(a, 0, sizeof a);
+       aconsr[0] = consreqchan;
+       aconsr[1] = conschan;
+       threadcreate(reqproc, aconsr, STACK);           /* consreqchan,conschan -> respond */
 
-       a[Areq].c = reqchan;
-       a[Areq].v = &req;
-       a[Areq].op = CHANRCV;
+       akbdr[0] = kbdreqchan;
+       akbdr[1] = kbdchan;
+       threadcreate(reqproc, akbdr, STACK);            /* kbdreqchan,kbdchan -> respond */
 
-       a[Actl].c = ctlchan;
-       a[Actl].v = &c;
-       a[Actl].op = CHANRCV;
+       cook = chancreate(sizeof(Rune), 0);
+       threadcreate(lineproc, cook, STACK);            /* cook -> conschan */
 
-       a[Arune].c = runechan;
-       a[Arune].v = &r;
-       a[Arune].op = CHANRCV;
+       raw = 0;
 
-       a[Aline].c = linechan;
-       a[Aline].v = &s;
-       a[Aline].op = CHANRCV;
+       a[ACTL].c = ctlchan;
+       a[ACTL].v = &c;
+       a[ACTL].op = CHANRCV;
 
-       a[Akbd].c = kbdchan;
-       a[Akbd].v = &s;
-       a[Akbd].op = CHANRCV;
+       a[ARUNE].c = runechan;
+       a[ARUNE].v = &r;
+       a[ARUNE].op = CHANRCV;
 
-       a[Aend].op = CHANEND;
+       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;
-                               }
-                       }
-                       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);
+                       nbsend(cook, &r);
                        break;
                }
        }
@@ -1011,10 +998,6 @@ fsopen(Req *r)
                                return;
                        }
                        kbdopen++;
-                       sendul(ctlchan, Kbdflush);
-                       break;
-               case Qcons:
-                       consopen++;
                        break;
                case Qconsctl:
                        consctlopen++;
@@ -1055,19 +1038,18 @@ fsread(Req *r)
        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 @@ fswrite(Req *r)
        f = r->fid;
        switch((ulong)f->qid.path){
        default:
-               respond(r, Efront);
+               respond(r, Ephase);
                return;
 
        case Qcons:
@@ -1134,8 +1116,10 @@ fsflush(Req *r)
 {
        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);
@@ -1158,9 +1142,6 @@ fsdestroyfid(Fid *f)
                case Qkbd:
                        kbdopen--;
                        break;
-               case Qcons:
-                       consopen--;
-                       break;
                case Qconsctl:
                        if(--consctlopen == 0)
                                sendul(ctlchan, Rawoff);
@@ -1277,17 +1258,16 @@ threadmain(int argc, char** argv)
                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);
        threadpostmountsrv(&fs, srv, mtpt, MBEFORE);