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