#include #include #include #include #include #include #include #include "libframe/frame.h" #include #include #include #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->fcall.tag == x->fcall.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 */ 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); }