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