ref: cbe4b116989c0bfec49b9ae7a1d9a85ead6648ae
dir: /sys/src/cmd/acme/logf.c/
#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 <libsec.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); 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->tag == x->oldtag) { rx->flushed = TRUE; rwakeupall(&eventlog.r); } } 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 * * op == "focus" for window focus change * - called from mousethread */ 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); }