master logf.c
ohmu  ·  2026-09-13
  1#include <u.h>
  2#include <libc.h>
  3#include <draw.h>
  4#include <thread.h>
  5#include <cursor.h>
  6#include <mouse.h>
  7#include <keyboard.h>
  8#include <frame.h>
  9#include <fcall.h>
 10#include <plumb.h>
 11#include <libsec.h>
 12#include "dat.h"
 13#include "fns.h"
 14
 15// State for global log file.
 16typedef struct Log Log;
 17struct Log
 18{
 19	QLock lk;
 20	Rendez r;
 21
 22	vlong start; // msg[0] corresponds to 'start' in the global sequence of events
 23	
 24	// queued events (nev=entries in ev, mev=capacity of p)
 25	char **ev;
 26	int nev;
 27	int mev;
 28
 29	// open acme/put files that need to read events
 30	Fid **f;
 31	int nf;
 32	int mf;
 33	
 34	// active (blocked) reads waiting for events
 35	Xfid **read;
 36	int nread;
 37	int mread;
 38};
 39
 40static Log eventlog;
 41
 42void
 43xfidlogopen(Xfid *x)
 44{
 45	qlock(&eventlog.lk);
 46	if(eventlog.nf >= eventlog.mf) {	
 47		eventlog.mf = eventlog.mf*2;
 48		if(eventlog.mf == 0)
 49			eventlog.mf = 8;
 50		eventlog.f = erealloc(eventlog.f, eventlog.mf*sizeof eventlog.f[0]);
 51	}
 52	eventlog.f[eventlog.nf++] = x->f;
 53	x->f->logoff = eventlog.start + eventlog.nev;
 54
 55	qunlock(&eventlog.lk);
 56}
 57
 58void
 59xfidlogclose(Xfid *x)
 60{
 61	int i;
 62
 63	qlock(&eventlog.lk);
 64	for(i=0; i<eventlog.nf; i++) {
 65		if(eventlog.f[i] == x->f) {
 66			eventlog.f[i] = eventlog.f[--eventlog.nf];
 67			break;
 68		}
 69	}
 70	qunlock(&eventlog.lk);
 71}
 72
 73void
 74xfidlogread(Xfid *x)
 75{
 76	char *p;
 77	int i;
 78	Fcall fc;
 79
 80	qlock(&eventlog.lk);
 81	if(eventlog.nread >= eventlog.mread) {	
 82		eventlog.mread = eventlog.mread*2;
 83		if(eventlog.mread == 0)
 84			eventlog.mread = 8;
 85		eventlog.read = erealloc(eventlog.read, eventlog.mread*sizeof eventlog.read[0]);
 86	}
 87	eventlog.read[eventlog.nread++] = x;
 88	
 89	if(eventlog.r.l == nil)
 90		eventlog.r.l = &eventlog.lk;
 91	x->flushed = FALSE;
 92	while(x->f->logoff >= eventlog.start+eventlog.nev && !x->flushed)
 93		rsleep(&eventlog.r);
 94		
 95	for(i=0; i<eventlog.nread; i++) {
 96		if(eventlog.read[i] == x) {
 97			eventlog.read[i] = eventlog.read[--eventlog.nread];
 98			break;
 99		}
100	}
101
102	if(x->flushed) {
103		qunlock(&eventlog.lk);
104		return;
105	}
106
107	i = x->f->logoff - eventlog.start;
108	p = estrdup(eventlog.ev[i]);
109	x->f->logoff++;
110	qunlock(&eventlog.lk);
111
112	fc.data = p;
113	fc.count = strlen(p);
114	respond(x, &fc, nil);
115	free(p);	
116}
117
118void
119xfidlogflush(Xfid *x)
120{
121	int i;
122	Xfid *rx;
123
124	qlock(&eventlog.lk);
125	for(i=0; i<eventlog.nread; i++) {
126		rx = eventlog.read[i];
127		if(rx->fcall.tag == x->fcall.oldtag) {
128			rx->flushed = TRUE;
129			rwakeupall(&eventlog.r);
130		}
131	}
132	qunlock(&eventlog.lk);
133}
134
135/*
136 * add a log entry for op on w.
137 * expected calls:
138 *
139 * op == "new" for each new window
140 *	- caller of coladd or makenewwindow responsible for calling
141 *		xfidlog after setting window name
142 *	- exception: zerox
143 *
144 * op == "zerox" for new window created via zerox
145 *	- called from zeroxx
146 *
147 * op == "get" for Get executed on window
148 *	- called from get
149 *
150 * op == "put" for Put executed on window
151 *	- called from put
152 *
153 * op == "del" for deleted window
154 *	- called from winclose
155 */
156void
157xfidlog(Window *w, char *op)
158{
159	int i, n;
160	vlong min;
161	File *f;
162	char *name;
163
164	qlock(&eventlog.lk);
165	if(eventlog.nev >= eventlog.mev) {
166		// Remove and free any entries that all readers have read.
167		min = eventlog.start + eventlog.nev;
168		for(i=0; i<eventlog.nf; i++) {
169			if(min > eventlog.f[i]->logoff)
170				min = eventlog.f[i]->logoff;
171		}
172		if(min > eventlog.start) {
173			n = min - eventlog.start;
174			for(i=0; i<n; i++)
175				free(eventlog.ev[i]);
176			eventlog.nev -= n;
177			eventlog.start += n;
178			memmove(eventlog.ev, eventlog.ev+n, eventlog.nev*sizeof eventlog.ev[0]);
179		}
180		
181		// Otherwise grow.
182		if(eventlog.nev >= eventlog.mev) {
183			eventlog.mev = eventlog.mev*2;
184			if(eventlog.mev == 0)
185				eventlog.mev = 8;
186			eventlog.ev = erealloc(eventlog.ev, eventlog.mev*sizeof eventlog.ev[0]);
187		}
188	}
189	f = w->body.file;
190	name = runetobyte(f->name, f->nname);
191	if(name == nil)
192		name = estrdup("");
193	eventlog.ev[eventlog.nev++] = smprint("%d %s %s\n", w->id, op, name);
194	free(name);
195	if(eventlog.r.l == nil)
196		eventlog.r.l = &eventlog.lk;
197	rwakeupall(&eventlog.r);
198	qunlock(&eventlog.lk);
199}