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
This commit is contained in:
Russ Cox 2014-04-30 12:14:29 -04:00
parent 833216fef8
commit 4a3fb87264
12 changed files with 262 additions and 8 deletions

View file

@ -303,6 +303,7 @@ readfile(Column *c, char *s)
winresize(w, w->r, FALSE, TRUE);
textscrdraw(&w->body);
textsetselect(&w->tag, w->tag.file->b.nc, w->tag.file->b.nc);
xfidlog(w, "new");
}
char *ignotes[] = {
@ -866,6 +867,7 @@ newwindowthread(void *v)
recvp(cnewwindow);
w = makenewwindow(nil);
winsettag(w);
xfidlog(w, "new");
sendp(cnewwindow, w);
}
}

View file

@ -8,6 +8,7 @@ enum
Qeditout,
Qindex,
Qlabel,
Qlog,
Qnew,
QWaddr,
@ -391,6 +392,7 @@ struct Fid
Mntdir *mntdir;
int nrpart;
uchar rpart[UTFmax];
vlong logoff; // for putlog
};
@ -403,7 +405,6 @@ struct Xfid
Fid *f;
uchar *buf;
int flushed;
};
void xfidctl(void *);
@ -418,6 +419,10 @@ void xfideventwrite(Xfid*, Window*);
void xfidindexread(Xfid*);
void xfidutfread(Xfid*, Text*, uint, int);
int xfidruneread(Xfid*, Text*, uint, uint);
void xfidlogopen(Xfid*);
void xfidlogread(Xfid*);
void xfidlogflush(Xfid*);
void xfidlog(Window*, char*);
struct Reffont
{

View file

@ -347,6 +347,7 @@ void
newcol(Text *et, Text *_0, Text *_1, int _2, int _3, Rune *_4, int _5)
{
Column *c;
Window *w;
USED(_0);
USED(_1);
@ -356,8 +357,11 @@ newcol(Text *et, Text *_0, Text *_1, int _2, int _3, Rune *_4, int _5)
USED(_5);
c = rowadd(et->row, nil, -1);
if(c)
winsettag(coladd(c, nil, nil, -1));
if(c) {
w = coladd(c, nil, nil, -1);
winsettag(w);
xfidlog(w, "new");
}
}
void
@ -562,6 +566,7 @@ zeroxx(Text *et, Text *t, Text *_1, int _2, int _3, Rune *_4, int _5)
nw = coladd(t->w->col, nil, t->w, -1);
/* ugly: fix locks so w->unlock works */
winlock1(nw, t->w->owner);
xfidlog(nw, "zerox");
}
if(locked)
winunlock(t->w);
@ -627,6 +632,7 @@ get(Text *et, Text *t, Text *argt, int flag1, int _0, Rune *arg, int narg)
textsetselect(&u->w->tag, u->w->tag.file->b.nc, u->w->tag.file->b.nc);
textscrdraw(u);
}
xfidlog(w, "get");
}
void
@ -782,6 +788,7 @@ put(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
}
namer = bytetorune(name, &nname);
putfile(f, 0, f->b.nc, namer, nname);
xfidlog(w, "put");
free(name);
}

View file

@ -71,6 +71,7 @@ Dirtab dirtab[]=
{ "editout", QTFILE, Qeditout, 0200 },
{ "index", QTFILE, Qindex, 0400 },
{ "label", QTFILE, Qlabel, 0600 },
{ "log", QTFILE, Qlog, 0400 },
{ "new", QTDIR, Qnew, 0500|DMDIR },
{ nil, }
};

197
src/cmd/acme/logf.c Normal file
View file

@ -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);
}

View file

@ -298,6 +298,7 @@ plumbshow(Plumbmsg *m)
winsettag(w);
textscrdraw(&w->body);
textsetselect(&w->tag, w->tag.file->b.nc, w->tag.file->b.nc);
xfidlog(w, "new");
}
int
@ -770,6 +771,7 @@ openfile(Text *t, Expand *e)
w->autoindent = ow->autoindent;
}else
w->autoindent = globalautoindent;
xfidlog(w, "new");
}
if(e->a1 == e->a0)
eval = FALSE;
@ -803,6 +805,7 @@ new(Text *et, Text *t, Text *argt, int flag1, int flag2, Rune *arg, int narg)
int na, nf;
Expand e;
Runestr rs;
Window *w;
getarg(argt, FALSE, TRUE, &a, &na);
if(a){
@ -814,8 +817,11 @@ new(Text *et, Text *t, Text *argt, int flag1, int flag2, Rune *arg, int narg)
for(ndone=0; ; ndone++){
a = findbl(arg, narg, &na);
if(a == arg){
if(ndone==0 && et->col!=nil)
winsettag(coladd(et->col, nil, nil, -1));
if(ndone==0 && et->col!=nil) {
w = coladd(et->col, nil, nil, -1);
winsettag(w);
xfidlog(w, "new");
}
break;
}
nf = narg-na;

View file

@ -15,6 +15,7 @@ OFILES=\
exec.$O\
file.$O\
fsys.$O\
logf.$O\
look.$O\
regx.$O\
rows.$O\

View file

@ -776,6 +776,7 @@ rowload(Row *row, char *file, int initing)
q0 = q1 = 0;
textshow(&w->body, q0, q1, 1);
w->maxlines = min(w->body.fr.nlines, max(w->maxlines, w->body.fr.maxlines));
xfidlog(w, "new");
Nextline:
l = rdline(b, &line);
}

View file

@ -97,6 +97,7 @@ errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
w = coladd(row.col[row.ncol-1], nil, nil, -1);
w->filemenu = FALSE;
winsetname(w, r, n);
xfidlog(w, "new");
}
free(r);
for(i=nincl; --i>=0; ){

View file

@ -320,6 +320,7 @@ winclose(Window *w)
int i;
if(decref(&w->ref) == 0){
xfidlog(w, "del");
windirfree(w);
textclose(&w->tag);
textclose(&w->body);
@ -644,7 +645,7 @@ Rescue:
}
int
winclean(Window *w, int conservative) /* as it stands, conservative is always TRUE */
winclean(Window *w, int conservative)
{
if(w->isscratch || w->isdir) /* don't whine if it's a guide file, error window, etc. */
return TRUE;

View file

@ -63,6 +63,8 @@ xfidflush(Xfid *x)
Column *c;
Xfid *wx;
xfidlogflush(x);
/* search windows for matching tag */
qlock(&row.lk);
for(j=0; j<row.ncol; j++){
@ -186,6 +188,9 @@ xfidopen(Xfid *x)
}
else{
switch(q){
case Qlog:
xfidlogopen(x);
break;
case Qeditout:
if(!canqlock(&editoutlk)){
respond(x, &fc, Einuse);
@ -300,6 +305,9 @@ xfidread(Xfid *x)
case Qindex:
xfidindexread(x);
return;
case Qlog:
xfidlogread(x);
return;
default:
warning(nil, "unknown qid %d\n", q);
break;