xref: /inferno-os/appl/lib/styxpersist.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement Styxpersist;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsyth#
4*37da2899SCharles.Forsyth# Copyright © 2004 Vita Nuova Holdings Limited
5*37da2899SCharles.Forsyth#
6*37da2899SCharles.Forsyth
7*37da2899SCharles.Forsythinclude "sys.m";
8*37da2899SCharles.Forsyth	sys: Sys;
9*37da2899SCharles.Forsythinclude "draw.m";
10*37da2899SCharles.Forsythinclude "styx.m";
11*37da2899SCharles.Forsyth	styx: Styx;
12*37da2899SCharles.Forsyth	Tmsg, Rmsg, NOFID, NOTAG: import styx;
13*37da2899SCharles.Forsythinclude "rand.m";
14*37da2899SCharles.Forsyth	rand: Rand;
15*37da2899SCharles.Forsythinclude "factotum.m";
16*37da2899SCharles.Forsyth	factotum: Factotum;
17*37da2899SCharles.Forsythinclude "styxpersist.m";
18*37da2899SCharles.Forsyth
19*37da2899SCharles.ForsythNOTOPEN, DEAD, AUTH, OPEN: con iota;
20*37da2899SCharles.ForsythNTAGHASH: con 32;
21*37da2899SCharles.ForsythMAXBACKOFF: con 30*1000;
22*37da2899SCharles.ForsythEstale: con "unable to reopen file";
23*37da2899SCharles.ForsythEbadtag: con "bad tag";
24*37da2899SCharles.ForsythEpartial: con "operation possibly not completed";
25*37da2899SCharles.ForsythEtypemismatch: con "tag type mismatch";
26*37da2899SCharles.ForsythDebug: con 0;
27*37da2899SCharles.Forsyth
28*37da2899SCharles.ForsythNoqid: con Sys->Qid(big 0, 0, 0);
29*37da2899SCharles.ForsythNprocs: con 1;
30*37da2899SCharles.ForsythErroronpartial: con 1;
31*37da2899SCharles.Forsyth
32*37da2899SCharles.ForsythTable: adt[T] {
33*37da2899SCharles.Forsyth	items:	array of list of (int, T);
34*37da2899SCharles.Forsyth	nilval:	T;
35*37da2899SCharles.Forsyth
36*37da2899SCharles.Forsyth	new: fn(nslots: int, nilval: T): ref Table[T];
37*37da2899SCharles.Forsyth	add:	fn(t: self ref Table, id: int, x: T): int;
38*37da2899SCharles.Forsyth	del:	fn(t: self ref Table, id: int): int;
39*37da2899SCharles.Forsyth	find:	fn(t: self ref Table, id: int): T;
40*37da2899SCharles.Forsyth};
41*37da2899SCharles.Forsyth
42*37da2899SCharles.ForsythFid: adt {
43*37da2899SCharles.Forsyth	fid:		int;
44*37da2899SCharles.Forsyth	state:	int;
45*37da2899SCharles.Forsyth	omode:	int;
46*37da2899SCharles.Forsyth	qid:		Sys->Qid;
47*37da2899SCharles.Forsyth	uname:	string;
48*37da2899SCharles.Forsyth	aname:	string;
49*37da2899SCharles.Forsyth	authed:	int;
50*37da2899SCharles.Forsyth	path:		list of string;	# in reverse order.
51*37da2899SCharles.Forsyth};
52*37da2899SCharles.Forsyth
53*37da2899SCharles.ForsythTag: adt {
54*37da2899SCharles.Forsyth	m: ref Tmsg;
55*37da2899SCharles.Forsyth	seq:		int;
56*37da2899SCharles.Forsyth	dead:	int;
57*37da2899SCharles.Forsyth	next: cyclic ref Tag;
58*37da2899SCharles.Forsyth};
59*37da2899SCharles.Forsyth
60*37da2899SCharles.ForsythRoot: adt {
61*37da2899SCharles.Forsyth	refcount: int;
62*37da2899SCharles.Forsyth	attached: chan of int;	# [1]; holds attached status: -1 (can't), 0 (haven't), 1 (attached)
63*37da2899SCharles.Forsyth	fid: int;
64*37da2899SCharles.Forsyth	qid: Sys->Qid;
65*37da2899SCharles.Forsyth	uname: string;
66*37da2899SCharles.Forsyth	aname: string;
67*37da2899SCharles.Forsyth};
68*37da2899SCharles.Forsyth
69*37da2899SCharles.Forsythkeyspec: string;
70*37da2899SCharles.Forsyth
71*37da2899SCharles.Forsythtags := array[NTAGHASH] of ref Tag;
72*37da2899SCharles.Forsythfids: ref Table[ref Fid];
73*37da2899SCharles.Forsythntags := 0;
74*37da2899SCharles.Forsythseqno := 0;
75*37da2899SCharles.Forsyth
76*37da2899SCharles.Forsythdoneversion := 0;
77*37da2899SCharles.Forsythmsize := 0;
78*37da2899SCharles.Forsythver: string;
79*37da2899SCharles.Forsyth
80*37da2899SCharles.Forsythcfd, sfd: ref Sys->FD;
81*37da2899SCharles.Forsythtmsg: chan of ref Tmsg;		# t-messages received from client
82*37da2899SCharles.Forsythrmsg: chan of ref Rmsg;		# r-messages received from server.
83*37da2899SCharles.Forsythrmsgpid := -1;
84*37da2899SCharles.Forsyth
85*37da2899SCharles.Forsythtoken: chan of (int, chan of (ref Fid, ref Root));		# [Nprocs] of (procid, workchan)
86*37da2899SCharles.Forsythprocrmsg: array of chan of ref Rmsg;
87*37da2899SCharles.Forsyth
88*37da2899SCharles.Forsythinit(clientfd: ref Sys->FD, usefac: int, kspec: string): (chan of chan of ref Sys->FD, string)
89*37da2899SCharles.Forsyth{
90*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
91*37da2899SCharles.Forsyth	styx = load Styx Styx->PATH;
92*37da2899SCharles.Forsyth	if(styx == nil)
93*37da2899SCharles.Forsyth		return (nil, sys->sprint("cannot load %q: %r", Styx->PATH));
94*37da2899SCharles.Forsyth	styx->init();
95*37da2899SCharles.Forsyth	rand = load Rand Rand->PATH;
96*37da2899SCharles.Forsyth	if (rand == nil)
97*37da2899SCharles.Forsyth		return (nil, sys->sprint("cannot load %q: %r", Rand->PATH));
98*37da2899SCharles.Forsyth	rand->init(sys->millisec());
99*37da2899SCharles.Forsyth	if(usefac){
100*37da2899SCharles.Forsyth		factotum = load Factotum Factotum->PATH;
101*37da2899SCharles.Forsyth		if(factotum == nil)
102*37da2899SCharles.Forsyth			return (nil, sys->sprint("cannot load %q: %r", Rand->PATH));
103*37da2899SCharles.Forsyth		factotum->init();
104*37da2899SCharles.Forsyth	}
105*37da2899SCharles.Forsyth
106*37da2899SCharles.Forsyth	keyspec = kspec;
107*37da2899SCharles.Forsyth	connectc := chan of chan of ref Sys->FD;
108*37da2899SCharles.Forsyth	spawn styxpersistproc(clientfd, connectc);
109*37da2899SCharles.Forsyth	return (connectc, nil);
110*37da2899SCharles.Forsyth}
111*37da2899SCharles.Forsyth
112*37da2899SCharles.Forsythstyxpersistproc(clientfd: ref Sys->FD, connectc: chan of chan of ref Sys->FD)
113*37da2899SCharles.Forsyth{
114*37da2899SCharles.Forsyth	fids = Table[ref Fid].new(11, nil);
115*37da2899SCharles.Forsyth	rmsg = chan of ref Rmsg;
116*37da2899SCharles.Forsyth	tmsg = chan of ref Tmsg;
117*37da2899SCharles.Forsyth	cfd = clientfd;
118*37da2899SCharles.Forsyth	spawn tmsgreader();
119*37da2899SCharles.Forsyth	connect(connectc);
120*37da2899SCharles.Forsyth	for(;;)alt{
121*37da2899SCharles.Forsyth	m := <-tmsg =>
122*37da2899SCharles.Forsyth		if(m == nil || tagof(m) == tagof(Tmsg.Readerror))
123*37da2899SCharles.Forsyth			quit();
124*37da2899SCharles.Forsyth		t := newtag(m);
125*37da2899SCharles.Forsyth		if(t == nil){
126*37da2899SCharles.Forsyth			sendrmsg(ref Rmsg.Error(m.tag, Ebadtag));
127*37da2899SCharles.Forsyth			continue;
128*37da2899SCharles.Forsyth		}
129*37da2899SCharles.Forsyth		if((rm := handletmsg(t)) != nil){
130*37da2899SCharles.Forsyth			sendrmsg(rm);
131*37da2899SCharles.Forsyth			gettag(m.tag, 1);
132*37da2899SCharles.Forsyth		}else{
133*37da2899SCharles.Forsyth			# XXX could be quicker about this as we don't rewrite messages
134*37da2899SCharles.Forsyth			sendtmsg(m);
135*37da2899SCharles.Forsyth		}
136*37da2899SCharles.Forsyth	m := <-rmsg =>
137*37da2899SCharles.Forsyth		if(m == nil || tagof(m) == tagof(Tmsg.Readerror)){
138*37da2899SCharles.Forsyth			if(Debug) sys->print("**************** reconnect {\n");
139*37da2899SCharles.Forsyth			do{
140*37da2899SCharles.Forsyth				connect(connectc);
141*37da2899SCharles.Forsyth			} while(resurrectfids() == 0);
142*37da2899SCharles.Forsyth			resurrecttags();
143*37da2899SCharles.Forsyth			if(Debug) sys->print("************** done reconnect }\n");
144*37da2899SCharles.Forsyth			continue;
145*37da2899SCharles.Forsyth		}
146*37da2899SCharles.Forsyth
147*37da2899SCharles.Forsyth		t := gettag(m.tag, 1);
148*37da2899SCharles.Forsyth		if(t == nil){
149*37da2899SCharles.Forsyth			log(sys->sprint("unexpected tag %d, %s", m.tag, m.text()));
150*37da2899SCharles.Forsyth			continue;
151*37da2899SCharles.Forsyth		}
152*37da2899SCharles.Forsyth		if((e := handlermsg(m, t.m)) != nil)
153*37da2899SCharles.Forsyth			log(e);
154*37da2899SCharles.Forsyth		else{
155*37da2899SCharles.Forsyth			# XXX could be quicker about this as we don't rewrite messages
156*37da2899SCharles.Forsyth			sendrmsg(m);
157*37da2899SCharles.Forsyth		}
158*37da2899SCharles.Forsyth	}
159*37da2899SCharles.Forsyth}
160*37da2899SCharles.Forsyth
161*37da2899SCharles.Forsythquit()
162*37da2899SCharles.Forsyth{
163*37da2899SCharles.Forsyth	log("quitting...\n");
164*37da2899SCharles.Forsyth	# XXX shutdown properly
165*37da2899SCharles.Forsyth	exit;
166*37da2899SCharles.Forsyth}
167*37da2899SCharles.Forsyth
168*37da2899SCharles.Forsythlog(s: string)
169*37da2899SCharles.Forsyth{
170*37da2899SCharles.Forsyth	sys->fprint(sys->fildes(2), "styxpersist: %s\n", s);
171*37da2899SCharles.Forsyth}
172*37da2899SCharles.Forsyth
173*37da2899SCharles.Forsythhandletmsg(t: ref Tag): ref Rmsg
174*37da2899SCharles.Forsyth{
175*37da2899SCharles.Forsyth	fid := NOFID;
176*37da2899SCharles.Forsyth	pick m := t.m {
177*37da2899SCharles.Forsyth	Flush =>
178*37da2899SCharles.Forsyth		if(gettag(m.oldtag, 0) == nil)
179*37da2899SCharles.Forsyth			return ref Rmsg.Flush(m.tag);
180*37da2899SCharles.Forsyth	 * =>
181*37da2899SCharles.Forsyth		fid = tmsgfid(m);
182*37da2899SCharles.Forsyth	}
183*37da2899SCharles.Forsyth	if(fid != NOFID){
184*37da2899SCharles.Forsyth		f := getfid(fid);
185*37da2899SCharles.Forsyth		if(f.state == DEAD){
186*37da2899SCharles.Forsyth			if(tagof(t.m) == tagof(Tmsg.Clunk)){
187*37da2899SCharles.Forsyth				fids.del(f.fid);
188*37da2899SCharles.Forsyth				return ref Rmsg.Clunk(t.m.tag);
189*37da2899SCharles.Forsyth			}
190*37da2899SCharles.Forsyth			return ref Rmsg.Error(t.m.tag, Estale);
191*37da2899SCharles.Forsyth		}
192*37da2899SCharles.Forsyth	}
193*37da2899SCharles.Forsyth	return nil;
194*37da2899SCharles.Forsyth}
195*37da2899SCharles.Forsyth
196*37da2899SCharles.Forsythhandlermsg(rm: ref Rmsg, tm: ref Tmsg): string
197*37da2899SCharles.Forsyth{
198*37da2899SCharles.Forsyth	if(tagof(rm) == tagof(Rmsg.Error) &&
199*37da2899SCharles.Forsyth			tagof(tm) != tagof(Tmsg.Remove) &&
200*37da2899SCharles.Forsyth			tagof(tm) != tagof(Tmsg.Clunk))
201*37da2899SCharles.Forsyth		return nil;
202*37da2899SCharles.Forsyth	if(tagof(rm) != tagof(Rmsg.Error) && rm.mtype() != tm.mtype()+1)
203*37da2899SCharles.Forsyth		return "type mismatch, got "+rm.text()+", reply to "+tm.text();
204*37da2899SCharles.Forsyth
205*37da2899SCharles.Forsyth	pick m := tm {
206*37da2899SCharles.Forsyth	Auth =>
207*37da2899SCharles.Forsyth		fid := newfid(m.afid);	# XXX should we be concerned about this failing?
208*37da2899SCharles.Forsyth		fid.state = AUTH;
209*37da2899SCharles.Forsyth	Attach =>
210*37da2899SCharles.Forsyth		fid := newfid(m.fid);
211*37da2899SCharles.Forsyth		fid.uname = m.uname;
212*37da2899SCharles.Forsyth		fid.aname = m.aname;
213*37da2899SCharles.Forsyth		if(m.afid != NOFID)
214*37da2899SCharles.Forsyth			fid.authed = 1;
215*37da2899SCharles.Forsyth	Walk =>
216*37da2899SCharles.Forsyth		fid := getfid(m.fid);
217*37da2899SCharles.Forsyth		qids: array of Sys->Qid;
218*37da2899SCharles.Forsyth		n := 0;
219*37da2899SCharles.Forsyth		pick r := rm {
220*37da2899SCharles.Forsyth		Walk =>
221*37da2899SCharles.Forsyth			qids = r.qids;
222*37da2899SCharles.Forsyth		}
223*37da2899SCharles.Forsyth		if(len qids != len m.names)
224*37da2899SCharles.Forsyth			return nil;
225*37da2899SCharles.Forsyth		if(m.fid != m.newfid){
226*37da2899SCharles.Forsyth			newfid := newfid(m.newfid);
227*37da2899SCharles.Forsyth			*newfid = *fid;
228*37da2899SCharles.Forsyth			newfid.fid = m.newfid;
229*37da2899SCharles.Forsyth			fid = newfid;
230*37da2899SCharles.Forsyth		}
231*37da2899SCharles.Forsyth		for(i := 0; i < len qids; i++){
232*37da2899SCharles.Forsyth			if(m.names[i] == ".."){
233*37da2899SCharles.Forsyth				if(fid.path != nil)
234*37da2899SCharles.Forsyth					fid.path = tl fid.path;
235*37da2899SCharles.Forsyth			}else{
236*37da2899SCharles.Forsyth				fid.path = m.names[i] :: fid.path;
237*37da2899SCharles.Forsyth			}
238*37da2899SCharles.Forsyth			fid.qid = qids[i];
239*37da2899SCharles.Forsyth		}
240*37da2899SCharles.Forsyth	Open =>
241*37da2899SCharles.Forsyth		fid := getfid(m.fid);
242*37da2899SCharles.Forsyth		fid.state = OPEN;
243*37da2899SCharles.Forsyth		fid.omode = m.mode;
244*37da2899SCharles.Forsyth		pick r := rm {
245*37da2899SCharles.Forsyth		Open =>
246*37da2899SCharles.Forsyth			fid.qid = r.qid;
247*37da2899SCharles.Forsyth		}
248*37da2899SCharles.Forsyth	Create =>
249*37da2899SCharles.Forsyth		fid := getfid(m.fid);
250*37da2899SCharles.Forsyth		fid.state = OPEN;
251*37da2899SCharles.Forsyth		fid.omode = m.mode;
252*37da2899SCharles.Forsyth		pick r := rm {
253*37da2899SCharles.Forsyth		Create =>
254*37da2899SCharles.Forsyth			fid.qid = r.qid;
255*37da2899SCharles.Forsyth		}
256*37da2899SCharles.Forsyth	Clunk or
257*37da2899SCharles.Forsyth	Remove =>
258*37da2899SCharles.Forsyth		fids.del(m.fid);
259*37da2899SCharles.Forsyth	Wstat =>
260*37da2899SCharles.Forsyth		if(m.stat.name != nil){
261*37da2899SCharles.Forsyth			fid := getfid(m.fid);
262*37da2899SCharles.Forsyth			fid.path = m.stat.name :: tl fid.path;
263*37da2899SCharles.Forsyth		}
264*37da2899SCharles.Forsyth	}
265*37da2899SCharles.Forsyth	return nil;
266*37da2899SCharles.Forsyth}
267*37da2899SCharles.Forsyth
268*37da2899SCharles.Forsyth# connect to destination with exponential backoff, setting sfd.
269*37da2899SCharles.Forsythconnect(connectc: chan of chan of ref Sys->FD)
270*37da2899SCharles.Forsyth{
271*37da2899SCharles.Forsyth	reply := chan of ref Sys->FD;
272*37da2899SCharles.Forsyth	sfd = nil;
273*37da2899SCharles.Forsyth	backoff := 0;
274*37da2899SCharles.Forsyth	for(;;){
275*37da2899SCharles.Forsyth		connectc <-= reply;
276*37da2899SCharles.Forsyth		fd := <-reply;
277*37da2899SCharles.Forsyth		if(fd != nil){
278*37da2899SCharles.Forsyth			kill(rmsgpid, "kill");
279*37da2899SCharles.Forsyth			sfd = fd;
280*37da2899SCharles.Forsyth			sync := chan of int;
281*37da2899SCharles.Forsyth			spawn rmsgreader(fd, sync);
282*37da2899SCharles.Forsyth			rmsgpid = <-sync;
283*37da2899SCharles.Forsyth			if(version() != -1)
284*37da2899SCharles.Forsyth				return;
285*37da2899SCharles.Forsyth			sfd = nil;
286*37da2899SCharles.Forsyth		}
287*37da2899SCharles.Forsyth		if(backoff == 0)
288*37da2899SCharles.Forsyth			backoff = 1000 + rand->rand(500) - 250;
289*37da2899SCharles.Forsyth		else if(backoff < MAXBACKOFF)
290*37da2899SCharles.Forsyth			backoff = backoff * 3 / 2;
291*37da2899SCharles.Forsyth		sys->sleep(backoff);
292*37da2899SCharles.Forsyth	}
293*37da2899SCharles.Forsyth}
294*37da2899SCharles.Forsyth
295*37da2899SCharles.Forsyth# first time we use the version offered by the client,
296*37da2899SCharles.Forsyth# and record it; subsequent times we offer the response
297*37da2899SCharles.Forsyth# recorded initially.
298*37da2899SCharles.Forsythversion(): int
299*37da2899SCharles.Forsyth{
300*37da2899SCharles.Forsyth	if(doneversion)
301*37da2899SCharles.Forsyth		sendtmsg(ref Tmsg.Version(NOTAG, msize, ver));
302*37da2899SCharles.Forsyth	else{
303*37da2899SCharles.Forsyth		m := <-tmsg;
304*37da2899SCharles.Forsyth		if(m == nil)
305*37da2899SCharles.Forsyth			quit();
306*37da2899SCharles.Forsyth		if(m == nil || tagof(m) != tagof(Tmsg.Version)){
307*37da2899SCharles.Forsyth			log("invalid initial version message: "+m.text());
308*37da2899SCharles.Forsyth			quit();
309*37da2899SCharles.Forsyth		}
310*37da2899SCharles.Forsyth		sendtmsg(m);
311*37da2899SCharles.Forsyth	}
312*37da2899SCharles.Forsyth	if((gm := <-rmsg) == nil)
313*37da2899SCharles.Forsyth		return -1;
314*37da2899SCharles.Forsyth	pick m := gm {
315*37da2899SCharles.Forsyth	Readerror =>
316*37da2899SCharles.Forsyth		return -1;
317*37da2899SCharles.Forsyth	Version =>
318*37da2899SCharles.Forsyth		if(doneversion && (m.msize != msize || m.version != ver)){
319*37da2899SCharles.Forsyth			log("wrong msize/version on reconnect");
320*37da2899SCharles.Forsyth			# XXX is there any hope here - we could quit.
321*37da2899SCharles.Forsyth			return -1;
322*37da2899SCharles.Forsyth		}
323*37da2899SCharles.Forsyth		if(!doneversion){
324*37da2899SCharles.Forsyth			msize = m.msize;
325*37da2899SCharles.Forsyth			ver = m.version;
326*37da2899SCharles.Forsyth			doneversion = 1;
327*37da2899SCharles.Forsyth			sendrmsg(m);
328*37da2899SCharles.Forsyth		}
329*37da2899SCharles.Forsyth		return 0;
330*37da2899SCharles.Forsyth	* =>
331*37da2899SCharles.Forsyth		log("invalid reply to Tversion: "+m.text());
332*37da2899SCharles.Forsyth		return -1;
333*37da2899SCharles.Forsyth	}
334*37da2899SCharles.Forsyth}
335*37da2899SCharles.Forsyth
336*37da2899SCharles.Forsythresurrecttags()
337*37da2899SCharles.Forsyth{
338*37da2899SCharles.Forsyth	# make sure that we send the tmsgs in the same order that
339*37da2899SCharles.Forsyth	# they were sent originally.
340*37da2899SCharles.Forsyth	all := array[ntags] of ref Tag;
341*37da2899SCharles.Forsyth	n := 0;
342*37da2899SCharles.Forsyth	for(i := 0; i < len tags; i++){
343*37da2899SCharles.Forsyth		for(t := tags[i]; t != nil; t = t.next){
344*37da2899SCharles.Forsyth			fid := tmsgfid(t.m);
345*37da2899SCharles.Forsyth			if(fid != NOFID && (f := getfid(fid)) != nil){
346*37da2899SCharles.Forsyth				if(f.state == DEAD){
347*37da2899SCharles.Forsyth					sendrmsg(ref Rmsg.Error(t.m.tag, Estale));
348*37da2899SCharles.Forsyth						t.dead = 1;
349*37da2899SCharles.Forsyth					continue;
350*37da2899SCharles.Forsyth				}
351*37da2899SCharles.Forsyth				if(Erroronpartial){
352*37da2899SCharles.Forsyth					partial := 0;
353*37da2899SCharles.Forsyth					pick m := t.m {
354*37da2899SCharles.Forsyth					Create =>
355*37da2899SCharles.Forsyth						partial = 1;
356*37da2899SCharles.Forsyth					Remove =>
357*37da2899SCharles.Forsyth						partial = 1;
358*37da2899SCharles.Forsyth					Wstat =>
359*37da2899SCharles.Forsyth						partial = (m.stat.name != nil && f.path != nil && hd f.path != m.stat.name);
360*37da2899SCharles.Forsyth					Write =>
361*37da2899SCharles.Forsyth						partial = (f.qid.qtype & Sys->QTAPPEND);
362*37da2899SCharles.Forsyth					}
363*37da2899SCharles.Forsyth					if(partial)
364*37da2899SCharles.Forsyth						sendrmsg(ref Rmsg.Error(t.m.tag, Epartial));
365*37da2899SCharles.Forsyth				}
366*37da2899SCharles.Forsyth			}
367*37da2899SCharles.Forsyth			all[n++] = t;
368*37da2899SCharles.Forsyth		}
369*37da2899SCharles.Forsyth	}
370*37da2899SCharles.Forsyth	all = all[0:n];
371*37da2899SCharles.Forsyth	sort(all);
372*37da2899SCharles.Forsyth	for(i = 0; i < len all; i++){
373*37da2899SCharles.Forsyth		t := all[i];
374*37da2899SCharles.Forsyth		pick m := t.m {
375*37da2899SCharles.Forsyth		Flush =>
376*37da2899SCharles.Forsyth			ot := gettag(m.oldtag, 0);
377*37da2899SCharles.Forsyth			if(ot == nil || ot.dead){
378*37da2899SCharles.Forsyth				sendrmsg(ref Rmsg.Flush(t.m.tag));
379*37da2899SCharles.Forsyth				t.dead = 1;
380*37da2899SCharles.Forsyth				continue;
381*37da2899SCharles.Forsyth			}
382*37da2899SCharles.Forsyth		}
383*37da2899SCharles.Forsyth		sendtmsg(t.m);
384*37da2899SCharles.Forsyth	}
385*37da2899SCharles.Forsyth	tags = array[len tags] of ref Tag;
386*37da2899SCharles.Forsyth	ntags = 0;
387*37da2899SCharles.Forsyth	for(i = 0; i < len all; i++)
388*37da2899SCharles.Forsyth		if(all[i].dead == 0)
389*37da2899SCharles.Forsyth			newtag(all[i].m);
390*37da2899SCharles.Forsyth}
391*37da2899SCharles.Forsyth
392*37da2899SCharles.Forsyth# re-open all the old fids, if possible.
393*37da2899SCharles.Forsyth# use up to Nprocs processes to keep latency down.
394*37da2899SCharles.Forsythresurrectfids(): int
395*37da2899SCharles.Forsyth{
396*37da2899SCharles.Forsyth	procrmsg = array[Nprocs] of {* => chan[1] of ref Rmsg};
397*37da2899SCharles.Forsyth	spawn rmsgmarshal(finish := chan of int);
398*37da2899SCharles.Forsyth	getroot := chan of (int, string, string, chan of ref Root);
399*37da2899SCharles.Forsyth	usedroot := chan of ref Root;
400*37da2899SCharles.Forsyth	spawn fidproc(getroot, usedroot);
401*37da2899SCharles.Forsyth	token = chan[Nprocs] of (int, chan of (ref Fid, ref Root));
402*37da2899SCharles.Forsyth	for(i := 0; i < Nprocs; i++)
403*37da2899SCharles.Forsyth		token <-= (i, nil);
404*37da2899SCharles.Forsyth
405*37da2899SCharles.Forsyth	for(i = 0; i < len fids.items; i++){
406*37da2899SCharles.Forsyth		for(fl := fids.items[i]; fl != nil; fl = tl fl){
407*37da2899SCharles.Forsyth			fid := (hd fl).t1;
408*37da2899SCharles.Forsyth			(procid, workc) := <-token;
409*37da2899SCharles.Forsyth			getroot <-= (1, fid.uname, fid.aname, reply := chan of ref Root);
410*37da2899SCharles.Forsyth			root := <-reply;
411*37da2899SCharles.Forsyth			if(workc == nil){
412*37da2899SCharles.Forsyth				workc = chan of (ref Fid, ref Root);
413*37da2899SCharles.Forsyth				spawn workproc(procid, workc, usedroot);
414*37da2899SCharles.Forsyth			}
415*37da2899SCharles.Forsyth			workc <-= (fid, root);
416*37da2899SCharles.Forsyth		}
417*37da2899SCharles.Forsyth	}
418*37da2899SCharles.Forsyth
419*37da2899SCharles.Forsyth	for(i = 0; i < Nprocs; i++){
420*37da2899SCharles.Forsyth		(nil, workc) := <-token;
421*37da2899SCharles.Forsyth		if(workc != nil)
422*37da2899SCharles.Forsyth			workc <-= (nil, nil);
423*37da2899SCharles.Forsyth	}
424*37da2899SCharles.Forsyth	for(i = 0; i < Nprocs; i++){
425*37da2899SCharles.Forsyth		getroot <-= (0, nil, nil, reply := chan of ref Root);
426*37da2899SCharles.Forsyth		root := <-reply;
427*37da2899SCharles.Forsyth		if(<-root.attached > 0)
428*37da2899SCharles.Forsyth			clunk(0, root.fid);
429*37da2899SCharles.Forsyth	}
430*37da2899SCharles.Forsyth	usedroot <-= nil;
431*37da2899SCharles.Forsyth	return <-finish;
432*37da2899SCharles.Forsyth}
433*37da2899SCharles.Forsyth
434*37da2899SCharles.Forsythworkproc(procid: int, workc: chan of (ref Fid, ref Root), usedroot: chan of ref Root)
435*37da2899SCharles.Forsyth{
436*37da2899SCharles.Forsyth	while(((fid, root) := <-workc).t0 != nil){
437*37da2899SCharles.Forsyth		# mark fid as dead only if it's a genuine server error, not if
438*37da2899SCharles.Forsyth		# the server has just hung up.
439*37da2899SCharles.Forsyth		if((err := resurrectfid(procid, fid, root)) != nil && sfd != nil){
440*37da2899SCharles.Forsyth			log(err);
441*37da2899SCharles.Forsyth			fid.state = DEAD;
442*37da2899SCharles.Forsyth		}
443*37da2899SCharles.Forsyth		usedroot <-= root;
444*37da2899SCharles.Forsyth		token <-= (procid, workc);
445*37da2899SCharles.Forsyth	}
446*37da2899SCharles.Forsyth}
447*37da2899SCharles.Forsyth
448*37da2899SCharles.Forsythresurrectfid(procid: int, fid: ref Fid, root: ref Root): string
449*37da2899SCharles.Forsyth{
450*37da2899SCharles.Forsyth	if(fid.state == AUTH)
451*37da2899SCharles.Forsyth		return "auth fid discarded";
452*37da2899SCharles.Forsyth	attached := <-root.attached;
453*37da2899SCharles.Forsyth	if(attached == -1){
454*37da2899SCharles.Forsyth		root.attached <-= -1;
455*37da2899SCharles.Forsyth		return "root attach failed";
456*37da2899SCharles.Forsyth	}
457*37da2899SCharles.Forsyth	if(!attached || root.uname != fid.uname || root.aname != fid.aname){
458*37da2899SCharles.Forsyth		if(attached)
459*37da2899SCharles.Forsyth			clunk(procid, root.fid);
460*37da2899SCharles.Forsyth		afid := NOFID;
461*37da2899SCharles.Forsyth		if(fid.authed){
462*37da2899SCharles.Forsyth			afid = fid.fid - 1;		# see unusedfid()
463*37da2899SCharles.Forsyth			if((err := auth(procid, afid, root.uname, root.aname)) != nil){
464*37da2899SCharles.Forsyth				log(err);
465*37da2899SCharles.Forsyth				afid = -1;
466*37da2899SCharles.Forsyth			}
467*37da2899SCharles.Forsyth		}
468*37da2899SCharles.Forsyth		(err, qid) := attach(procid, root.fid, afid, fid.uname, fid.aname);
469*37da2899SCharles.Forsyth		if(afid != NOFID)
470*37da2899SCharles.Forsyth			clunk(procid, afid);
471*37da2899SCharles.Forsyth		if(err != nil){
472*37da2899SCharles.Forsyth			root.attached <-= -1;
473*37da2899SCharles.Forsyth			return "attach failed: "+err;
474*37da2899SCharles.Forsyth		}
475*37da2899SCharles.Forsyth		root.uname = fid.uname;
476*37da2899SCharles.Forsyth		root.aname = fid.aname;
477*37da2899SCharles.Forsyth		root.qid = qid;
478*37da2899SCharles.Forsyth	}
479*37da2899SCharles.Forsyth	root.attached <-= 1;
480*37da2899SCharles.Forsyth	(err, qid) := walk(procid, root.fid, fid.fid, fid.path, root.qid);
481*37da2899SCharles.Forsyth	if(err != nil)
482*37da2899SCharles.Forsyth		return err;
483*37da2899SCharles.Forsyth	if(fid.state == OPEN && (err = openfid(procid, fid)) != nil){
484*37da2899SCharles.Forsyth		clunk(procid, fid.fid);
485*37da2899SCharles.Forsyth		return err;
486*37da2899SCharles.Forsyth	}
487*37da2899SCharles.Forsyth	return nil;
488*37da2899SCharles.Forsyth}
489*37da2899SCharles.Forsyth
490*37da2899SCharles.Forsythopenfid(procid: int, fid: ref Fid): string
491*37da2899SCharles.Forsyth{
492*37da2899SCharles.Forsyth	(err, qid) := open(procid, fid.fid, fid.omode);
493*37da2899SCharles.Forsyth	if(err != nil)
494*37da2899SCharles.Forsyth		return err;
495*37da2899SCharles.Forsyth	if(qid.path != fid.qid.path || qid.qtype != fid.qid.qtype)
496*37da2899SCharles.Forsyth		return "qid mismatch on reopen";
497*37da2899SCharles.Forsyth	return nil;
498*37da2899SCharles.Forsyth}
499*37da2899SCharles.Forsyth
500*37da2899SCharles.Forsyth# store up to Nprocs separate root fids and dole them out to those that want them.
501*37da2899SCharles.Forsythfidproc(getroot: chan of (int, string, string, chan of ref Root), usedroot: chan of ref Root)
502*37da2899SCharles.Forsyth{
503*37da2899SCharles.Forsyth	roots := array[Nprocs] of ref Root;
504*37da2899SCharles.Forsyth	n := 0;
505*37da2899SCharles.Forsyth	maxfid := -1;
506*37da2899SCharles.Forsyth	for(;;)alt{
507*37da2899SCharles.Forsyth	(match, uname, aname, reply) := <-getroot =>
508*37da2899SCharles.Forsyth		for(i := 0; i < n; i++)
509*37da2899SCharles.Forsyth			if(match && roots[i].uname == uname && roots[i].aname == aname)
510*37da2899SCharles.Forsyth				break;
511*37da2899SCharles.Forsyth		if(i == n)
512*37da2899SCharles.Forsyth			for(i = 0; i < n; i++)
513*37da2899SCharles.Forsyth				if(roots[i].refcount == 0)
514*37da2899SCharles.Forsyth					break;
515*37da2899SCharles.Forsyth		if(i == n){
516*37da2899SCharles.Forsyth			maxfid = unusedfid(maxfid);
517*37da2899SCharles.Forsyth			roots[n] = ref Root(0, chan[1] of int, maxfid, Noqid, uname, aname);
518*37da2899SCharles.Forsyth			roots[n++].attached <-= 0;
519*37da2899SCharles.Forsyth		}
520*37da2899SCharles.Forsyth		roots[i].refcount++;
521*37da2899SCharles.Forsyth		reply <-= roots[i];
522*37da2899SCharles.Forsyth	r := <-usedroot =>
523*37da2899SCharles.Forsyth		if(r == nil)
524*37da2899SCharles.Forsyth			exit;
525*37da2899SCharles.Forsyth		r.refcount--;
526*37da2899SCharles.Forsyth	}
527*37da2899SCharles.Forsyth}
528*37da2899SCharles.Forsyth
529*37da2899SCharles.Forsythclunk(procid: int, fid: int)
530*37da2899SCharles.Forsyth{
531*37da2899SCharles.Forsyth	pick m := fcall(ref Tmsg.Clunk(procid, fid)) {
532*37da2899SCharles.Forsyth	Error =>
533*37da2899SCharles.Forsyth		if(sfd != nil)
534*37da2899SCharles.Forsyth			log("error on clunk: " + m.ename);
535*37da2899SCharles.Forsyth	}
536*37da2899SCharles.Forsyth}
537*37da2899SCharles.Forsyth
538*37da2899SCharles.Forsythattach(procid, fid, afid: int, uname, aname: string): (string, Sys->Qid)
539*37da2899SCharles.Forsyth{
540*37da2899SCharles.Forsyth	pick m := fcall(ref Tmsg.Attach(procid, fid, afid, uname, aname)) {
541*37da2899SCharles.Forsyth	Attach =>
542*37da2899SCharles.Forsyth		return (nil, m.qid);
543*37da2899SCharles.Forsyth	Error =>
544*37da2899SCharles.Forsyth		return (m.ename, Noqid);
545*37da2899SCharles.Forsyth	}
546*37da2899SCharles.Forsyth	return (nil, Noqid);	# not reached
547*37da2899SCharles.Forsyth}
548*37da2899SCharles.Forsyth
549*37da2899SCharles.Forsythread(procid, fid: int, buf: array of byte): (int, string)
550*37da2899SCharles.Forsyth{
551*37da2899SCharles.Forsyth	# XXX assume that offsets are ignored of auth fid reads/writes
552*37da2899SCharles.Forsyth	pick m := fcall(ref Tmsg.Read(procid, fid, big 0, len buf)) {
553*37da2899SCharles.Forsyth	Error =>
554*37da2899SCharles.Forsyth		return (-1, m.ename);
555*37da2899SCharles.Forsyth	Read =>
556*37da2899SCharles.Forsyth		buf[0:] = m.data;
557*37da2899SCharles.Forsyth		return (len m.data, nil);
558*37da2899SCharles.Forsyth	}
559*37da2899SCharles.Forsyth	return (-1, nil);			# not reached
560*37da2899SCharles.Forsyth}
561*37da2899SCharles.Forsyth
562*37da2899SCharles.Forsythwrite(procid, fid: int, buf: array of byte): (int, string)
563*37da2899SCharles.Forsyth{
564*37da2899SCharles.Forsyth	# XXX assume that offsets are ignored of auth fid reads/writes
565*37da2899SCharles.Forsyth	pick m := fcall(ref Tmsg.Write(procid, fid, big 0, buf)) {
566*37da2899SCharles.Forsyth	Error =>
567*37da2899SCharles.Forsyth		sys->werrstr(m.ename);
568*37da2899SCharles.Forsyth		return (-1, sys->sprint("%r"));
569*37da2899SCharles.Forsyth	Write =>
570*37da2899SCharles.Forsyth		return (m.count, nil);
571*37da2899SCharles.Forsyth	}
572*37da2899SCharles.Forsyth	return (-1, nil);		# not reached
573*37da2899SCharles.Forsyth}
574*37da2899SCharles.Forsyth
575*37da2899SCharles.Forsythauth(procid, fid: int, uname, aname: string): string
576*37da2899SCharles.Forsyth{
577*37da2899SCharles.Forsyth	if(factotum == nil)
578*37da2899SCharles.Forsyth		return "no factotum available";
579*37da2899SCharles.Forsyth
580*37da2899SCharles.Forsyth	pick m := fcall(ref Tmsg.Auth(procid, fid, uname, aname)) {
581*37da2899SCharles.Forsyth	Error =>
582*37da2899SCharles.Forsyth		return m.ename;
583*37da2899SCharles.Forsyth	}
584*37da2899SCharles.Forsyth
585*37da2899SCharles.Forsyth	readc := chan of (array of byte, chan of (int, string));
586*37da2899SCharles.Forsyth	writec := chan of (array of byte, chan of (int, string));
587*37da2899SCharles.Forsyth	done := chan of (ref Factotum->Authinfo, string);
588*37da2899SCharles.Forsyth	spawn factotum->genproxy(readc, writec, done,
589*37da2899SCharles.Forsyth			sys->open("/mnt/factotum/rpc", Sys->ORDWR),
590*37da2899SCharles.Forsyth			"proto=p9any role=client "+keyspec);
591*37da2899SCharles.Forsyth	for(;;)alt{
592*37da2899SCharles.Forsyth	(buf, reply) := <-readc =>
593*37da2899SCharles.Forsyth		reply <-= read(procid, fid, buf);
594*37da2899SCharles.Forsyth	(buf, reply) := <-writec =>
595*37da2899SCharles.Forsyth		reply <-= write(procid, fid, buf);
596*37da2899SCharles.Forsyth	(authinfo, err) := <-done =>
597*37da2899SCharles.Forsyth		if(authinfo == nil){
598*37da2899SCharles.Forsyth			clunk(procid, fid);
599*37da2899SCharles.Forsyth			return err;
600*37da2899SCharles.Forsyth		}
601*37da2899SCharles.Forsyth		# XXX check that authinfo.cuid == uname?
602*37da2899SCharles.Forsyth		return nil;
603*37da2899SCharles.Forsyth	}
604*37da2899SCharles.Forsyth}
605*37da2899SCharles.Forsyth
606*37da2899SCharles.Forsyth# path is in reverse order; assume fid != newfid on entry.
607*37da2899SCharles.Forsythwalk(procid: int, fid, newfid: int, path: list of string, qid: Sys->Qid): (string, Sys->Qid)
608*37da2899SCharles.Forsyth{
609*37da2899SCharles.Forsyth	names := array[len path] of string;
610*37da2899SCharles.Forsyth	for(i := len names - 1; i >= 0; i--)
611*37da2899SCharles.Forsyth		(names[i], path) = (hd path, tl path);
612*37da2899SCharles.Forsyth	do{
613*37da2899SCharles.Forsyth		w := names;
614*37da2899SCharles.Forsyth		if(len w > Styx->MAXWELEM)
615*37da2899SCharles.Forsyth			w = w[0:Styx->MAXWELEM];
616*37da2899SCharles.Forsyth		names = names[len w:];
617*37da2899SCharles.Forsyth		pick m := fcall(ref Tmsg.Walk(procid, fid, newfid, w)) {
618*37da2899SCharles.Forsyth		Error =>
619*37da2899SCharles.Forsyth			if(newfid == fid)
620*37da2899SCharles.Forsyth				clunk(procid, newfid);
621*37da2899SCharles.Forsyth			return ("walk error: "+m.ename, Noqid);
622*37da2899SCharles.Forsyth		Walk =>
623*37da2899SCharles.Forsyth			if(len m.qids != len w){
624*37da2899SCharles.Forsyth				if(newfid == fid)
625*37da2899SCharles.Forsyth					clunk(procid, newfid);
626*37da2899SCharles.Forsyth				return ("walk: file not found", Noqid);
627*37da2899SCharles.Forsyth			}
628*37da2899SCharles.Forsyth			if(len m.qids > 0)
629*37da2899SCharles.Forsyth				qid = m.qids[len m.qids - 1];
630*37da2899SCharles.Forsyth			fid = newfid;
631*37da2899SCharles.Forsyth		}
632*37da2899SCharles.Forsyth	}while(len names > 0);
633*37da2899SCharles.Forsyth	return (nil, qid);
634*37da2899SCharles.Forsyth}
635*37da2899SCharles.Forsyth
636*37da2899SCharles.Forsythopen(procid: int, fid: int, mode: int): (string, Sys->Qid)
637*37da2899SCharles.Forsyth{
638*37da2899SCharles.Forsyth	pick m := fcall(ref Tmsg.Open(procid, fid, mode)) {
639*37da2899SCharles.Forsyth	Error =>
640*37da2899SCharles.Forsyth		return ("open: "+m.ename, Noqid);
641*37da2899SCharles.Forsyth	Open =>
642*37da2899SCharles.Forsyth		return (nil, m.qid);		# XXX what if iounit doesn't match the original?
643*37da2899SCharles.Forsyth	}
644*37da2899SCharles.Forsyth	return (nil, Noqid);		# not reached
645*37da2899SCharles.Forsyth}
646*37da2899SCharles.Forsyth
647*37da2899SCharles.Forsythfcall(m: ref Tmsg): ref Rmsg
648*37da2899SCharles.Forsyth{
649*37da2899SCharles.Forsyth	sendtmsg(m);
650*37da2899SCharles.Forsyth	pick rm := <-procrmsg[m.tag] {
651*37da2899SCharles.Forsyth	Readerror =>
652*37da2899SCharles.Forsyth		procrmsg[m.tag] <-= rm;
653*37da2899SCharles.Forsyth		return ref Rmsg.Error(rm.tag, rm.error);
654*37da2899SCharles.Forsyth	Error =>
655*37da2899SCharles.Forsyth		return rm;
656*37da2899SCharles.Forsyth	* =>
657*37da2899SCharles.Forsyth		if(rm.mtype() != m.mtype()+1)
658*37da2899SCharles.Forsyth			return ref Rmsg.Error(m.tag, Etypemismatch);
659*37da2899SCharles.Forsyth		return rm;
660*37da2899SCharles.Forsyth	}
661*37da2899SCharles.Forsyth}
662*37da2899SCharles.Forsyth
663*37da2899SCharles.Forsyth# find an unused fid (and make sure that the one before it is unused
664*37da2899SCharles.Forsyth# too, in case we want to use it for an auth fid);
665*37da2899SCharles.Forsythunusedfid(maxfid: int): int
666*37da2899SCharles.Forsyth{
667*37da2899SCharles.Forsyth	for(f := maxfid + 1; ; f++)
668*37da2899SCharles.Forsyth		if(fids.find(f) == nil && fids.find(f+1) == nil)
669*37da2899SCharles.Forsyth			return f + 1;
670*37da2899SCharles.Forsyth	abort("no unused fids - i don't believe it");
671*37da2899SCharles.Forsyth	return 0;
672*37da2899SCharles.Forsyth}
673*37da2899SCharles.Forsyth
674*37da2899SCharles.Forsyth# XXX what about message length limitations?
675*37da2899SCharles.Forsythsendtmsg(m: ref Tmsg)
676*37da2899SCharles.Forsyth{
677*37da2899SCharles.Forsyth	if(Debug) sys->print("%s\n", m.text());
678*37da2899SCharles.Forsyth	d := m.pack();
679*37da2899SCharles.Forsyth	if(sys->write(sfd, d, len d) != len d)
680*37da2899SCharles.Forsyth		log(sys->sprint("tmsg write failed: %r"));	# XXX could signal to redial
681*37da2899SCharles.Forsyth}
682*37da2899SCharles.Forsyth
683*37da2899SCharles.Forsythsendrmsg(m: ref Rmsg)
684*37da2899SCharles.Forsyth{
685*37da2899SCharles.Forsyth	d := m.pack();
686*37da2899SCharles.Forsyth	if(sys->write(cfd, d, len d) != len d){
687*37da2899SCharles.Forsyth		log(sys->sprint("rmsg write failed: %r"));
688*37da2899SCharles.Forsyth		quit();
689*37da2899SCharles.Forsyth	}
690*37da2899SCharles.Forsyth}
691*37da2899SCharles.Forsyth
692*37da2899SCharles.Forsythrmsgmarshal(finish: chan of int)
693*37da2899SCharles.Forsyth{
694*37da2899SCharles.Forsyth	for(;;)alt{
695*37da2899SCharles.Forsyth	finish <-= 1 =>
696*37da2899SCharles.Forsyth		exit;
697*37da2899SCharles.Forsyth	m := <-rmsg =>
698*37da2899SCharles.Forsyth		if(m == nil || tagof(m) == tagof(Rmsg.Readerror)){
699*37da2899SCharles.Forsyth			sfd = nil;
700*37da2899SCharles.Forsyth			for(i := 0; i < Nprocs; i++)
701*37da2899SCharles.Forsyth				procrmsg[i] <-= ref Rmsg.Readerror(NOTAG, "hung up");
702*37da2899SCharles.Forsyth			finish <-= 0;
703*37da2899SCharles.Forsyth			exit;
704*37da2899SCharles.Forsyth		}
705*37da2899SCharles.Forsyth		if(m.tag >= Nprocs){
706*37da2899SCharles.Forsyth			log("invalid reply message");
707*37da2899SCharles.Forsyth			break;
708*37da2899SCharles.Forsyth		}
709*37da2899SCharles.Forsyth		# XXX if the server replies with a tag that no-one's waiting for. we'll lock up.
710*37da2899SCharles.Forsyth		# (but is it much of a concern, given no flushes, etc?)
711*37da2899SCharles.Forsyth		procrmsg[m.tag] <-= m;
712*37da2899SCharles.Forsyth	}
713*37da2899SCharles.Forsyth}
714*37da2899SCharles.Forsyth
715*37da2899SCharles.Forsythrmsgreader(fd: ref Sys->FD, sync: chan of int)
716*37da2899SCharles.Forsyth{
717*37da2899SCharles.Forsyth	sync <-= sys->pctl(0, nil);
718*37da2899SCharles.Forsyth	m: ref Rmsg;
719*37da2899SCharles.Forsyth	do {
720*37da2899SCharles.Forsyth		m = Rmsg.read(fd, msize);
721*37da2899SCharles.Forsyth		if(Debug) sys->print("%s\n", m.text());
722*37da2899SCharles.Forsyth		rmsg <-= m;
723*37da2899SCharles.Forsyth	} while(m != nil && tagof(m) != tagof(Tmsg.Readerror));
724*37da2899SCharles.Forsyth}
725*37da2899SCharles.Forsyth
726*37da2899SCharles.Forsythtmsgreader()
727*37da2899SCharles.Forsyth{
728*37da2899SCharles.Forsyth	m: ref Tmsg;
729*37da2899SCharles.Forsyth	do{
730*37da2899SCharles.Forsyth		m = Tmsg.read(cfd, msize);
731*37da2899SCharles.Forsyth		tmsg <-= m;
732*37da2899SCharles.Forsyth	} while(m != nil && tagof(m) != tagof(Tmsg.Readerror));
733*37da2899SCharles.Forsyth}
734*37da2899SCharles.Forsyth
735*37da2899SCharles.Forsythabort(s: string)
736*37da2899SCharles.Forsyth{
737*37da2899SCharles.Forsyth	log(s);
738*37da2899SCharles.Forsyth	raise "abort";
739*37da2899SCharles.Forsyth}
740*37da2899SCharles.Forsyth
741*37da2899SCharles.Forsythtmsgfid(t: ref Tmsg): int
742*37da2899SCharles.Forsyth{
743*37da2899SCharles.Forsyth	fid := NOFID;
744*37da2899SCharles.Forsyth	pick m := t {
745*37da2899SCharles.Forsyth	Attach =>
746*37da2899SCharles.Forsyth		fid = m.afid;
747*37da2899SCharles.Forsyth	Walk =>
748*37da2899SCharles.Forsyth		fid = m.fid;
749*37da2899SCharles.Forsyth	Open =>
750*37da2899SCharles.Forsyth		fid = m.fid;
751*37da2899SCharles.Forsyth	Create =>
752*37da2899SCharles.Forsyth		fid = m.fid;
753*37da2899SCharles.Forsyth	Read =>
754*37da2899SCharles.Forsyth		fid = m.fid;
755*37da2899SCharles.Forsyth	Write =>
756*37da2899SCharles.Forsyth		fid = m.fid;
757*37da2899SCharles.Forsyth	Clunk or
758*37da2899SCharles.Forsyth	Stat or
759*37da2899SCharles.Forsyth	Remove =>
760*37da2899SCharles.Forsyth		fid = m.fid;
761*37da2899SCharles.Forsyth	Wstat =>
762*37da2899SCharles.Forsyth		fid = m.fid;
763*37da2899SCharles.Forsyth	}
764*37da2899SCharles.Forsyth	return fid;
765*37da2899SCharles.Forsyth}
766*37da2899SCharles.Forsyth
767*37da2899SCharles.Forsythblankfid: Fid;
768*37da2899SCharles.Forsythnewfid(fid: int): ref Fid
769*37da2899SCharles.Forsyth{
770*37da2899SCharles.Forsyth	f := ref blankfid;
771*37da2899SCharles.Forsyth	f.fid = fid;
772*37da2899SCharles.Forsyth	if(fids.add(fid, f) == 0){
773*37da2899SCharles.Forsyth		abort("duplicate fid "+string fid);
774*37da2899SCharles.Forsyth	}
775*37da2899SCharles.Forsyth	return f;
776*37da2899SCharles.Forsyth}
777*37da2899SCharles.Forsyth
778*37da2899SCharles.Forsythgetfid(fid: int): ref Fid
779*37da2899SCharles.Forsyth{
780*37da2899SCharles.Forsyth	return fids.find(fid);
781*37da2899SCharles.Forsyth}
782*37da2899SCharles.Forsyth
783*37da2899SCharles.Forsythnewtag(m: ref Tmsg): ref Tag
784*37da2899SCharles.Forsyth{
785*37da2899SCharles.Forsyth	# XXX what happens if the client sends a duplicate tag?
786*37da2899SCharles.Forsyth	t := ref Tag(m, seqno++, 0, nil);
787*37da2899SCharles.Forsyth	slot := t.m.tag & (NTAGHASH - 1);
788*37da2899SCharles.Forsyth	t.next = tags[slot];
789*37da2899SCharles.Forsyth	tags[slot] = t;
790*37da2899SCharles.Forsyth	ntags++;
791*37da2899SCharles.Forsyth	return t;
792*37da2899SCharles.Forsyth}
793*37da2899SCharles.Forsyth
794*37da2899SCharles.Forsythgettag(tag: int, destroy: int): ref Tag
795*37da2899SCharles.Forsyth{
796*37da2899SCharles.Forsyth	slot := tag & (NTAGHASH - 1);
797*37da2899SCharles.Forsyth	prev: ref Tag;
798*37da2899SCharles.Forsyth	for(t := tags[slot]; t != nil; t = t.next){
799*37da2899SCharles.Forsyth		if(t.m.tag == tag)
800*37da2899SCharles.Forsyth			break;
801*37da2899SCharles.Forsyth		prev = t;
802*37da2899SCharles.Forsyth	}
803*37da2899SCharles.Forsyth	if(t == nil || !destroy)
804*37da2899SCharles.Forsyth		return t;
805*37da2899SCharles.Forsyth	if(prev == nil)
806*37da2899SCharles.Forsyth		tags[slot] = t.next;
807*37da2899SCharles.Forsyth	else
808*37da2899SCharles.Forsyth		prev.next = t.next;
809*37da2899SCharles.Forsyth	ntags--;
810*37da2899SCharles.Forsyth	return t;
811*37da2899SCharles.Forsyth}
812*37da2899SCharles.Forsyth
813*37da2899SCharles.ForsythTable[T].new(nslots: int, nilval: T): ref Table[T]
814*37da2899SCharles.Forsyth{
815*37da2899SCharles.Forsyth	if(nslots == 0)
816*37da2899SCharles.Forsyth		nslots = 13;
817*37da2899SCharles.Forsyth	return ref Table[T](array[nslots] of list of (int, T), nilval);
818*37da2899SCharles.Forsyth}
819*37da2899SCharles.Forsyth
820*37da2899SCharles.ForsythTable[T].add(t: self ref Table[T], id: int, x: T): int
821*37da2899SCharles.Forsyth{
822*37da2899SCharles.Forsyth	slot := id % len t.items;
823*37da2899SCharles.Forsyth	for(q := t.items[slot]; q != nil; q = tl q)
824*37da2899SCharles.Forsyth		if((hd q).t0 == id)
825*37da2899SCharles.Forsyth			return 0;
826*37da2899SCharles.Forsyth	t.items[slot] = (id, x) :: t.items[slot];
827*37da2899SCharles.Forsyth	return 1;
828*37da2899SCharles.Forsyth}
829*37da2899SCharles.Forsyth
830*37da2899SCharles.ForsythTable[T].del(t: self ref Table[T], id: int): int
831*37da2899SCharles.Forsyth{
832*37da2899SCharles.Forsyth	slot := id % len t.items;
833*37da2899SCharles.Forsyth
834*37da2899SCharles.Forsyth	p: list of (int, T);
835*37da2899SCharles.Forsyth	r := 0;
836*37da2899SCharles.Forsyth	for(q := t.items[slot]; q != nil; q = tl q){
837*37da2899SCharles.Forsyth		if((hd q).t0 == id){
838*37da2899SCharles.Forsyth			p = joinip(p, tl q);
839*37da2899SCharles.Forsyth			r = 1;
840*37da2899SCharles.Forsyth			break;
841*37da2899SCharles.Forsyth		}
842*37da2899SCharles.Forsyth		p = hd q :: p;
843*37da2899SCharles.Forsyth	}
844*37da2899SCharles.Forsyth	t.items[slot] = p;
845*37da2899SCharles.Forsyth	return r;
846*37da2899SCharles.Forsyth}
847*37da2899SCharles.Forsyth
848*37da2899SCharles.ForsythTable[T].find(t: self ref Table[T], id: int): T
849*37da2899SCharles.Forsyth{
850*37da2899SCharles.Forsyth	for(p := t.items[id % len t.items]; p != nil; p = tl p)
851*37da2899SCharles.Forsyth		if((hd p).t0 == id)
852*37da2899SCharles.Forsyth			return (hd p).t1;
853*37da2899SCharles.Forsyth	return t.nilval;
854*37da2899SCharles.Forsyth}
855*37da2899SCharles.Forsyth
856*37da2899SCharles.Forsythsort(a: array of ref Tag)
857*37da2899SCharles.Forsyth{
858*37da2899SCharles.Forsyth	mergesort(a, array[len a] of ref Tag);
859*37da2899SCharles.Forsyth}
860*37da2899SCharles.Forsyth
861*37da2899SCharles.Forsythmergesort(a, b: array of ref Tag)
862*37da2899SCharles.Forsyth{
863*37da2899SCharles.Forsyth	r := len a;
864*37da2899SCharles.Forsyth	if (r > 1) {
865*37da2899SCharles.Forsyth		m := (r-1)/2 + 1;
866*37da2899SCharles.Forsyth		mergesort(a[0:m], b[0:m]);
867*37da2899SCharles.Forsyth		mergesort(a[m:], b[m:]);
868*37da2899SCharles.Forsyth		b[0:] = a;
869*37da2899SCharles.Forsyth		for ((i, j, k) := (0, m, 0); i < m && j < r; k++) {
870*37da2899SCharles.Forsyth			if (b[i].seq > b[j].seq)
871*37da2899SCharles.Forsyth				a[k] = b[j++];
872*37da2899SCharles.Forsyth			else
873*37da2899SCharles.Forsyth				a[k] = b[i++];
874*37da2899SCharles.Forsyth		}
875*37da2899SCharles.Forsyth		if (i < m)
876*37da2899SCharles.Forsyth			a[k:] = b[i:m];
877*37da2899SCharles.Forsyth		else if (j < r)
878*37da2899SCharles.Forsyth			a[k:] = b[j:r];
879*37da2899SCharles.Forsyth	}
880*37da2899SCharles.Forsyth}
881*37da2899SCharles.Forsyth
882*37da2899SCharles.Forsythkill(pid: int, note: string): int
883*37da2899SCharles.Forsyth{
884*37da2899SCharles.Forsyth	fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE);
885*37da2899SCharles.Forsyth	if(fd == nil || sys->fprint(fd, "%s", note) < 0)
886*37da2899SCharles.Forsyth		return -1;
887*37da2899SCharles.Forsyth	return 0;
888*37da2899SCharles.Forsyth}
889*37da2899SCharles.Forsyth
890*37da2899SCharles.Forsyth# join x to y, leaving result in arbitrary order.
891*37da2899SCharles.Forsythjoinip[T](x, y: list of (int, T)): list of (int, T)
892*37da2899SCharles.Forsyth{
893*37da2899SCharles.Forsyth	if(len x > len y)
894*37da2899SCharles.Forsyth		(x, y) = (y, x);
895*37da2899SCharles.Forsyth	for(; x != nil; x = tl x)
896*37da2899SCharles.Forsyth		y = hd x :: y;
897*37da2899SCharles.Forsyth	return y;
898*37da2899SCharles.Forsyth}
899