diff options
author | Russ Cox <rsc@swtch.com> | 2014-04-30 12:14:29 -0400 |
---|---|---|
committer | Russ Cox <rsc@swtch.com> | 2014-04-30 12:14:29 -0400 |
commit | 4a3fb87264f8bc03fc62f00ef335056f30d18023 (patch) | |
tree | 77d52013a1fbb6fd967c1e146d5ddbf5ca0c065d /src/cmd/acme/logf.c | |
parent | 833216fef8b946895956737d205bcad7031bf06f (diff) | |
download | plan9port-4a3fb87264f8bc03fc62f00ef335056f30d18023.tar.gz plan9port-4a3fb87264f8bc03fc62f00ef335056f30d18023.tar.bz2 plan9port-4a3fb87264f8bc03fc62f00ef335056f30d18023.zip |
acme: add log file in acme root directory
Reading /mnt/acme/log reports a log of window create,
put, and delete events, as they happen. It blocks until the
next event is available.
Example log output:
8 new /Users/rsc/foo.go
8 put /Users/rsc/foo.go
8 del /Users/rsc/foo.go
This lets acme-aware programs react to file writes, for example
compiling code, running a test, or updating an import block.
TBR=r
R=r
https://codereview.appspot.com/89560044
Diffstat (limited to 'src/cmd/acme/logf.c')
-rw-r--r-- | src/cmd/acme/logf.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/cmd/acme/logf.c b/src/cmd/acme/logf.c new file mode 100644 index 00000000..ebcd4bfd --- /dev/null +++ b/src/cmd/acme/logf.c @@ -0,0 +1,197 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <thread.h> +#include <cursor.h> +#include <mouse.h> +#include <keyboard.h> +#include <frame.h> +#include <fcall.h> +#include <plumb.h> +#include "dat.h" +#include "fns.h" + +// State for global log file. +typedef struct Log Log; +struct Log +{ + QLock lk; + Rendez r; + + vlong start; // msg[0] corresponds to 'start' in the global sequence of events + + // queued events (nev=entries in ev, mev=capacity of p) + char **ev; + int nev; + int mev; + + // open acme/put files that need to read events + Fid **f; + int nf; + int mf; + + // active (blocked) reads waiting for events + Xfid **read; + int nread; + int mread; +}; + +static Log eventlog; + +void +xfidlogopen(Xfid *x) +{ + qlock(&eventlog.lk); + if(eventlog.nf >= eventlog.mf) { + eventlog.mf = eventlog.mf*2; + if(eventlog.mf == 0) + eventlog.mf = 8; + eventlog.f = erealloc(eventlog.f, eventlog.mf*sizeof eventlog.f[0]); + } + eventlog.f[eventlog.nf++] = x->f; + x->f->logoff = eventlog.start + eventlog.nev; + + qunlock(&eventlog.lk); +} + +void +xfidlogclose(Xfid *x) +{ + int i; + + qlock(&eventlog.lk); + for(i=0; i<eventlog.nf; i++) { + if(eventlog.f[i] == x->f) { + eventlog.f[i] = eventlog.f[--eventlog.nf]; + break; + } + } + qunlock(&eventlog.lk); +} + +void +xfidlogread(Xfid *x) +{ + char *p; + int i; + Fcall fc; + + qlock(&eventlog.lk); + if(eventlog.nread >= eventlog.mread) { + eventlog.mread = eventlog.mread*2; + if(eventlog.mread == 0) + eventlog.mread = 8; + eventlog.read = erealloc(eventlog.read, eventlog.mread*sizeof eventlog.read[0]); + } + eventlog.read[eventlog.nread++] = x; + + if(eventlog.r.l == nil) + eventlog.r.l = &eventlog.lk; + x->flushed = FALSE; + while(x->f->logoff >= eventlog.start+eventlog.nev && !x->flushed) + rsleep(&eventlog.r); + + for(i=0; i<eventlog.nread; i++) { + if(eventlog.read[i] == x) { + eventlog.read[i] = eventlog.read[--eventlog.nread]; + break; + } + } + + if(x->flushed) { + qunlock(&eventlog.lk); + respond(x, &fc, "read cancelled"); + return; + } + + i = x->f->logoff - eventlog.start; + p = estrdup(eventlog.ev[i]); + x->f->logoff++; + qunlock(&eventlog.lk); + + fc.data = p; + fc.count = strlen(p); + respond(x, &fc, nil); + free(p); +} + +void +xfidlogflush(Xfid *x) +{ + int i; + Xfid *rx; + + qlock(&eventlog.lk); + for(i=0; i<eventlog.nread; i++) { + rx = eventlog.read[i]; + if(rx->fcall.tag == x->fcall.oldtag) + rx->flushed = TRUE; + } + qunlock(&eventlog.lk); +} + +/* + * add a log entry for op on w. + * expected calls: + * + * op == "new" for each new window + * - caller of coladd or makenewwindow responsible for calling + * xfidlog after setting window name + * - exception: zerox + * + * op == "zerox" for new window created via zerox + * - called from zeroxx + * + * op == "get" for Get executed on window + * - called from get + * + * op == "put" for Put executed on window + * - called from put + * + * op == "del" for deleted window + * - called from winclose + */ +void +xfidlog(Window *w, char *op) +{ + int i, n; + vlong min; + File *f; + char *name; + + qlock(&eventlog.lk); + if(eventlog.nev >= eventlog.mev) { + // Remove and free any entries that all readers have read. + min = eventlog.start + eventlog.nev; + for(i=0; i<eventlog.nf; i++) { + if(min > eventlog.f[i]->logoff) + min = eventlog.f[i]->logoff; + } + if(min > eventlog.start) { + n = min - eventlog.start; + for(i=0; i<n; i++) + free(eventlog.ev[i]); + eventlog.nev -= n; + eventlog.start += n; + memmove(eventlog.ev, eventlog.ev+n, eventlog.nev*sizeof eventlog.ev[0]); + } + + // Otherwise grow. + if(eventlog.nev >= eventlog.mev) { + eventlog.mev = eventlog.mev*2; + if(eventlog.mev == 0) + eventlog.mev = 8; + eventlog.ev = erealloc(eventlog.ev, eventlog.mev*sizeof eventlog.ev[0]); + } + } + f = w->body.file; + name = runetobyte(f->name, f->nname); + if(name == nil) + name = estrdup(""); + eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name); + free(name); + if(eventlog.r.l == nil) + eventlog.r.l = &eventlog.lk; + rwakeupall(&eventlog.r); + qunlock(&eventlog.lk); +} |