summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c162
1 files changed, 141 insertions, 21 deletions
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);
}