From 3a0e0b8bb6e7fd9bcf510167980d9715e3faeb7b Mon Sep 17 00:00:00 2001 From: Peter Mikkelsen Date: Thu, 15 Feb 2024 20:39:09 +0000 Subject: Even more work :) --- main.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 141 insertions(+), 21 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index 8137fdb..4ef93f1 100644 --- a/main.c +++ b/main.c @@ -12,6 +12,7 @@ #define Eperm "permission denied" #define Eoffset "can't write to this file at non-zero offset" #define Ebadctl "bad ctl message" +#define Einuse "file in use" QLock guilock = 0; @@ -22,6 +23,7 @@ enum { Qclone, Qevent, Qtype, + Qwait, Qprops, Qprop, @@ -31,10 +33,34 @@ enum { Fclone, Fevent, Ftype, + Fwait, Fprops, Fmax, }; +void fsattach(Req *); +char *fswalk1(Fid *, char *, Qid *); +char *fsclone(Fid *, Fid *); +void fsopen(Req *); +void fsstat(Req *); +void fsread(Req *); +void fswrite(Req *); +void fsforker(void (*)(void*), void *, int); +void fsdestroyfid(Fid *); + +Srv fs = { + .attach = fsattach, + .walk1 = fswalk1, + .clone = fsclone, + .open = fsopen, + .stat = fsstat, + .read = fsread, + .write = fswrite, + + .destroyfid = fsdestroyfid, + .forker = fsforker, +}; + GuiElement *root; #define QID_TYPE(q) ((q.path) & 0xFF) @@ -75,6 +101,7 @@ mkqid(int type) case Qclone: case Qevent: case Qtype: + case Qwait: q.type = QTFILE; break; } @@ -132,6 +159,9 @@ newgui(GuiElement *parent) g->qevent = mkqid(Qevent); g->qtype = mkqid(Qtype); g->qprops = mkqid(Qprops); + g->qwait = mkqid(Qwait); + + g->events = chancreate(sizeof(char *), 0); if(parent){ g->id = parent->nchildren; @@ -170,6 +200,7 @@ fsattach(Req *r) GuiElement *g = newgui(nil); root = g; settype(g, Gcontainer); + updategui(1); } r->fid->aux = root; @@ -208,6 +239,8 @@ fswalk1(Fid *fid, char *name, Qid *qid) *qid = g->qtype; else if(strcmp(name, "props") == 0) *qid = g->qprops; + else if(strcmp(name, "wait") == 0) + *qid = g->qwait; else if(child = findchild(g, name)){ fid->aux = child; *qid = child->qid; @@ -250,15 +283,17 @@ void fsopen(Req *r) { GuiElement *g = r->fid->aux; + char *err = nil; switch(QID_TYPE(r->fid->qid)){ case Qdir: case Qevent: case Qclone: case Qprops: + case Qwait: if(r->ifcall.mode != OREAD){ - respond(r, Eperm); - return; + err = Eperm; + goto Lend; } break; } @@ -276,7 +311,18 @@ fsopen(Req *r) r->ofcall.qid = g->qclone; } - respond(r, nil); + if(QID_TYPE(r->fid->qid) == Qevent){ + wlock(&g->lock); + if(g->listening){ + err = Einuse; + r->fid->aux = nil; + }else + g->listening = 1; + wunlock(&g->lock); + } + +Lend: + respond(r, err); } void @@ -324,7 +370,7 @@ dirtreegen(int n, Dir *d, void *aux) d->qid = g->qclone; break; case Fevent: - d->mode = 0444; + d->mode = 0444|DMEXCL; d->name = estrdup9p("event"); d->qid = g->qevent; break; @@ -333,6 +379,11 @@ dirtreegen(int n, Dir *d, void *aux) d->name = estrdup9p("type"); d->qid = g->qtype; break; + case Fwait: + d->mode = 0444; + d->name = estrdup9p("wait"); + d->qid = g->qwait; + break; case Fprops: d->mode = 0555|DMDIR; d->name = estrdup9p("props"); @@ -401,10 +452,47 @@ fsread(Req *r) readstr(r, buf); break; case Qevent: - /* in another thread, wait for events on a channel - * and call readstr on each of them individually. - */ - readstr(r, "eveeent\n"); + { + /* get all the messages we can, and add them to g->currentevents */ + char *event; + int mustrecv = 0; + ulong currentsize; + ulong eventsize; +Lretry: + srvrelease(&fs); + if(mustrecv){ + recv(g->events, &event); + goto Lgotevent; + } + + while(nbrecv(g->events, &event)){ +Lgotevent: currentsize = g->currentevents ? strlen(g->currentevents) : 0; + eventsize = strlen(event); + + wlock(&g->lock); + g->currentevents = erealloc(g->currentevents, currentsize+eventsize+1); + memcpy(g->currentevents+currentsize, event, eventsize); + g->currentevents[currentsize+eventsize] = 0; + wunlock(&g->lock); + free(event); + } + + rlock(&g->lock); + if(g->currentevents == nil){ + runlock(&g->lock); + recv(g->events, &event); + goto Lgotevent; + }else{ + srvacquire(&fs); + readstr(r, g->currentevents); + if(r->ofcall.count == 0){ + runlock(&g->lock); + mustrecv = 1; + goto Lretry; + } + } + runlock(&g->lock); + } break; case Qtype: rlock(&g->lock); @@ -412,6 +500,9 @@ fsread(Req *r) runlock(&g->lock); readstr(r, buf); break; + case Qwait: + /* intentionally left blank */ + return; case Qprops: dirread9p(r, proptreegen, g); break; @@ -419,7 +510,7 @@ fsread(Req *r) { int tag = QID_PROP(r->fid->qid); PropSpec spec = propspecs[tag]; - PropVal val = getprop(g, tag); + PropVal val = getprop(g, tag, 1); char *str = spec.print(val); readstr(r, str); free(str); @@ -474,7 +565,7 @@ fswrite(Req *r) memcpy(buf, r->ifcall.data, r->ifcall.count); err = spec.parse(buf, &val); if(err == nil) - setprop(g, tag, val); + setprop(g, tag, val, 1); free(buf); } } @@ -482,20 +573,31 @@ fswrite(Req *r) respond(r, err); } -Srv fs = { - .attach = fsattach, - .walk1 = fswalk1, - .clone = fsclone, - .open = fsopen, - .stat = fsstat, - .read = fsread, - .write = fswrite, -}; +void +fsforker(void (*fn)(void*), void *arg, int rflag) +{ + /* same as threadsrvforker, but stay in the same note group */ + rflag &= ~RFNOTEG; + procrfork(fn, arg, 32*1024, rflag); +} + +void +fsdestroyfid(Fid *fid) +{ + GuiElement *g = fid->aux; + + if(g != nil && QID_TYPE(fid->qid) == Qevent){ + wlock(&g->lock); + g->listening = 0; + free(g->currentevents); + wunlock(&g->lock); + } +} void usage(void) { - fprint(2, "usage: %s [-D] [-m mountpoint] [-s srvname] \n", argv0); + fprint(2, "usage: %s [-D] [-m mountpoint] [-s srvname] command\n", argv0); exits("usage"); } @@ -518,11 +620,29 @@ threadmain(int argc, char **argv) usage(); }ARGEND; - if(argc > 1) + if(argc == 0) usage(); username = getuser(); initgraphics(); threadpostmountsrv(&fs, srvname, mtpt, MREPL); + + int pid = fork(); + switch(pid){ + case 0: /* child process */ + exec(argv[0], argv); + sysfatal("exec: %r"); + break; + case -1: /* error */ + sysfatal("fork: %r"); + break; + } + + /* parent process */ + int wpid; + do + wpid = waitpid(); + while(wpid != -1 && wpid != pid); + postnote(PNGROUP, getpid(), "interrupt"); exits(nil); } -- cgit v1.2.3