15e96a66cSDavid du Colombier #include "stdinc.h" 25e96a66cSDavid du Colombier 35e96a66cSDavid du Colombier #include "9.h" 45e96a66cSDavid du Colombier #include "dat.h" 55e96a66cSDavid du Colombier #include "fns.h" 65e96a66cSDavid du Colombier 75e96a66cSDavid du Colombier enum { 85e96a66cSDavid du Colombier NConInit = 128, 95e96a66cSDavid du Colombier NMsgInit = 20, 105e96a66cSDavid du Colombier NMsgProcInit = 4, 115e96a66cSDavid du Colombier NMsizeInit = 8192+IOHDRSZ, 125e96a66cSDavid du Colombier }; 135e96a66cSDavid du Colombier 145e96a66cSDavid du Colombier static struct { 1534e04225SDavid du Colombier VtLock* alock; /* alloc */ 1634e04225SDavid du Colombier Msg* ahead; 1734e04225SDavid du Colombier VtRendez* arendez; 185e96a66cSDavid du Colombier 195e96a66cSDavid du Colombier int maxmsg; 205e96a66cSDavid du Colombier int nmsg; 2134e04225SDavid du Colombier int nmsgstarve; 2234e04225SDavid du Colombier 2334e04225SDavid du Colombier VtLock* rlock; /* read */ 2434e04225SDavid du Colombier Msg* rhead; 2534e04225SDavid du Colombier Msg* rtail; 2634e04225SDavid du Colombier VtRendez* rrendez; 2734e04225SDavid du Colombier 285e96a66cSDavid du Colombier int maxproc; 295e96a66cSDavid du Colombier int nproc; 3034e04225SDavid du Colombier int nprocstarve; 315e96a66cSDavid du Colombier 325e96a66cSDavid du Colombier u32int msize; /* immutable */ 335e96a66cSDavid du Colombier } mbox; 345e96a66cSDavid du Colombier 3534e04225SDavid du Colombier static struct { 3634e04225SDavid du Colombier VtLock* alock; /* alloc */ 3734e04225SDavid du Colombier Con* ahead; 3834e04225SDavid du Colombier VtRendez* arendez; 3934e04225SDavid du Colombier 4034e04225SDavid du Colombier VtLock* clock; 4134e04225SDavid du Colombier Con* chead; 4234e04225SDavid du Colombier Con* ctail; 4334e04225SDavid du Colombier 4434e04225SDavid du Colombier int maxcon; 4534e04225SDavid du Colombier int ncon; 4634e04225SDavid du Colombier int nconstarve; 4734e04225SDavid du Colombier 4834e04225SDavid du Colombier u32int msize; 4934e04225SDavid du Colombier } cbox; 505e96a66cSDavid du Colombier 515e96a66cSDavid du Colombier static void 525e96a66cSDavid du Colombier conFree(Con* con) 535e96a66cSDavid du Colombier { 5434e04225SDavid du Colombier assert(con->version == nil); 5534e04225SDavid du Colombier assert(con->mhead == nil); 5634e04225SDavid du Colombier assert(con->whead == nil); 5734e04225SDavid du Colombier assert(con->nfid == 0); 5834e04225SDavid du Colombier assert(con->state == ConMoribund); 5934e04225SDavid du Colombier 605e96a66cSDavid du Colombier if(con->fd >= 0){ 615e96a66cSDavid du Colombier close(con->fd); 625e96a66cSDavid du Colombier con->fd = -1; 635e96a66cSDavid du Colombier } 6434e04225SDavid du Colombier con->state = ConDead; 655e96a66cSDavid du Colombier 6634e04225SDavid du Colombier vtLock(cbox.alock); 6734e04225SDavid du Colombier if(con->cprev != nil) 6834e04225SDavid du Colombier con->cprev->cnext = con->cnext; 6934e04225SDavid du Colombier else 7034e04225SDavid du Colombier cbox.chead = con->cnext; 7134e04225SDavid du Colombier if(con->cnext != nil) 7234e04225SDavid du Colombier con->cnext->cprev = con->cprev; 7334e04225SDavid du Colombier else 7434e04225SDavid du Colombier cbox.ctail = con->cprev; 7534e04225SDavid du Colombier con->cprev = con->cnext = nil; 765e96a66cSDavid du Colombier 7734e04225SDavid du Colombier if(cbox.ncon > cbox.maxcon){ 7834e04225SDavid du Colombier if(con->name != nil) 7934e04225SDavid du Colombier vtMemFree(con->name); 8034e04225SDavid du Colombier vtLockFree(con->fidlock); 8134e04225SDavid du Colombier vtMemFree(con->data); 82c366c7d4SDavid du Colombier vtRendezFree(con->wrendez); 8334e04225SDavid du Colombier vtLockFree(con->wlock); 84c366c7d4SDavid du Colombier vtRendezFree(con->mrendez); 8534e04225SDavid du Colombier vtLockFree(con->mlock); 86c366c7d4SDavid du Colombier vtRendezFree(con->rendez); 8734e04225SDavid du Colombier vtLockFree(con->lock); 8834e04225SDavid du Colombier vtMemFree(con); 8934e04225SDavid du Colombier cbox.ncon--; 9034e04225SDavid du Colombier vtUnlock(cbox.alock); 9134e04225SDavid du Colombier return; 9234e04225SDavid du Colombier } 9334e04225SDavid du Colombier con->anext = cbox.ahead; 9434e04225SDavid du Colombier cbox.ahead = con; 9534e04225SDavid du Colombier if(con->anext == nil) 9634e04225SDavid du Colombier vtWakeup(cbox.arendez); 9734e04225SDavid du Colombier vtUnlock(cbox.alock); 9834e04225SDavid du Colombier } 9934e04225SDavid du Colombier 10034e04225SDavid du Colombier static void 10134e04225SDavid du Colombier msgFree(Msg* m) 10234e04225SDavid du Colombier { 10334e04225SDavid du Colombier assert(m->rwnext == nil); 10434e04225SDavid du Colombier assert(m->fnext == nil && m->fprev == nil); 10534e04225SDavid du Colombier 10634e04225SDavid du Colombier vtLock(mbox.alock); 10734e04225SDavid du Colombier if(mbox.nmsg > mbox.maxmsg){ 10834e04225SDavid du Colombier vtMemFree(m->data); 10934e04225SDavid du Colombier vtMemFree(m); 11034e04225SDavid du Colombier mbox.nmsg--; 11134e04225SDavid du Colombier vtUnlock(mbox.alock); 11234e04225SDavid du Colombier return; 11334e04225SDavid du Colombier } 11434e04225SDavid du Colombier m->anext = mbox.ahead; 11534e04225SDavid du Colombier mbox.ahead = m; 11634e04225SDavid du Colombier if(m->anext == nil) 11734e04225SDavid du Colombier vtWakeup(mbox.arendez); 11834e04225SDavid du Colombier vtUnlock(mbox.alock); 11934e04225SDavid du Colombier } 12034e04225SDavid du Colombier 12134e04225SDavid du Colombier static Msg* 12234e04225SDavid du Colombier msgAlloc(Con* con) 12334e04225SDavid du Colombier { 12434e04225SDavid du Colombier Msg *m; 12534e04225SDavid du Colombier 12634e04225SDavid du Colombier vtLock(mbox.alock); 12734e04225SDavid du Colombier while(mbox.ahead == nil){ 12834e04225SDavid du Colombier if(mbox.nmsg >= mbox.maxmsg){ 12934e04225SDavid du Colombier mbox.nmsgstarve++; 13034e04225SDavid du Colombier vtSleep(mbox.arendez); 13134e04225SDavid du Colombier continue; 13234e04225SDavid du Colombier } 13334e04225SDavid du Colombier m = vtMemAllocZ(sizeof(Msg)); 13434e04225SDavid du Colombier m->data = vtMemAlloc(mbox.msize); 13534e04225SDavid du Colombier m->msize = mbox.msize; 13634e04225SDavid du Colombier mbox.nmsg++; 13734e04225SDavid du Colombier mbox.ahead = m; 13834e04225SDavid du Colombier break; 13934e04225SDavid du Colombier } 14034e04225SDavid du Colombier m = mbox.ahead; 14134e04225SDavid du Colombier mbox.ahead = m->anext; 14234e04225SDavid du Colombier m->anext = nil; 14334e04225SDavid du Colombier vtUnlock(mbox.alock); 14434e04225SDavid du Colombier 14534e04225SDavid du Colombier m->con = con; 14634e04225SDavid du Colombier m->state = MsgR; 14734e04225SDavid du Colombier 14834e04225SDavid du Colombier return m; 14934e04225SDavid du Colombier } 15034e04225SDavid du Colombier 15134e04225SDavid du Colombier static void 15234e04225SDavid du Colombier msgMunlink(Msg* m) 15334e04225SDavid du Colombier { 15434e04225SDavid du Colombier Con *con; 15534e04225SDavid du Colombier 15634e04225SDavid du Colombier con = m->con; 15734e04225SDavid du Colombier 15834e04225SDavid du Colombier if(m->mprev != nil) 15934e04225SDavid du Colombier m->mprev->mnext = m->mnext; 16034e04225SDavid du Colombier else 16134e04225SDavid du Colombier con->mhead = m->mnext; 16234e04225SDavid du Colombier if(m->mnext != nil) 16334e04225SDavid du Colombier m->mnext->mprev = m->mprev; 16434e04225SDavid du Colombier else 16534e04225SDavid du Colombier con->mtail = m->mprev; 16634e04225SDavid du Colombier m->mprev = m->mnext = nil; 16734e04225SDavid du Colombier } 16834e04225SDavid du Colombier 16934e04225SDavid du Colombier static void 17034e04225SDavid du Colombier msgUnlinkUnlockAndFree(Msg* m) 17134e04225SDavid du Colombier { 17234e04225SDavid du Colombier /* 17334e04225SDavid du Colombier * Unlink the message from the flush and message queues, 17434e04225SDavid du Colombier * unlock the connection message lock and free the message. 17534e04225SDavid du Colombier * Called with con->mlock locked. 17634e04225SDavid du Colombier */ 17734e04225SDavid du Colombier if(m->fprev != nil) 17834e04225SDavid du Colombier m->fprev->fnext = m->fnext; 17934e04225SDavid du Colombier if(m->fnext != nil) 18034e04225SDavid du Colombier m->fnext->fprev = m->fprev; 18134e04225SDavid du Colombier m->fprev = m->fnext = nil; 18234e04225SDavid du Colombier 18334e04225SDavid du Colombier msgMunlink(m); 18434e04225SDavid du Colombier vtUnlock(m->con->mlock); 18534e04225SDavid du Colombier msgFree(m); 18634e04225SDavid du Colombier } 18734e04225SDavid du Colombier 18834e04225SDavid du Colombier void 18934e04225SDavid du Colombier msgFlush(Msg* m) 19034e04225SDavid du Colombier { 19134e04225SDavid du Colombier Msg *old; 19234e04225SDavid du Colombier Con *con; 19334e04225SDavid du Colombier 19434e04225SDavid du Colombier con = m->con; 19534e04225SDavid du Colombier 196*39734e7eSDavid du Colombier fprint(2, "msgFlush %F\n", &m->t); 197*39734e7eSDavid du Colombier 19834e04225SDavid du Colombier /* 19934e04225SDavid du Colombier * Look for the message to be flushed in the 20034e04225SDavid du Colombier * queue of all messages still on this connection. 20134e04225SDavid du Colombier */ 20234e04225SDavid du Colombier vtLock(con->mlock); 20334e04225SDavid du Colombier for(old = con->mhead; old != nil; old = old->mnext) 20434e04225SDavid du Colombier if(old->t.tag == m->t.oldtag) 20534e04225SDavid du Colombier break; 20634e04225SDavid du Colombier if(old == nil){ 20734e04225SDavid du Colombier if(Dflag) 20834e04225SDavid du Colombier fprint(2, "msgFlush: cannot find %d\n", m->t.oldtag); 20934e04225SDavid du Colombier vtUnlock(con->mlock); 21034e04225SDavid du Colombier return; 21134e04225SDavid du Colombier } 21234e04225SDavid du Colombier 213*39734e7eSDavid du Colombier fprint(2, "\tmsgFlush found %F\n", &old->t); 214*39734e7eSDavid du Colombier 21534e04225SDavid du Colombier /* 21634e04225SDavid du Colombier * Found it. 21734e04225SDavid du Colombier * 21834e04225SDavid du Colombier * Easy case is no 9P processing done yet, 21934e04225SDavid du Colombier * message is on the read queue. 22034e04225SDavid du Colombier * Mark the message as flushed and let the read 22134e04225SDavid du Colombier * process throw it away after after pulling 22234e04225SDavid du Colombier * it off the read queue. 22334e04225SDavid du Colombier */ 22434e04225SDavid du Colombier if(old->state == MsgR){ 22534e04225SDavid du Colombier old->state = MsgF; 22634e04225SDavid du Colombier if(Dflag) 22734e04225SDavid du Colombier fprint(2, "msgFlush: change %d from MsgR to MsgF\n", m->t.oldtag); 22834e04225SDavid du Colombier vtUnlock(con->mlock); 22934e04225SDavid du Colombier return; 23034e04225SDavid du Colombier } 23134e04225SDavid du Colombier 23234e04225SDavid du Colombier /* 23334e04225SDavid du Colombier * Flushing flushes. 23434e04225SDavid du Colombier * Since they don't affect the server state, flushes 23534e04225SDavid du Colombier * can be deleted when in Msg9 or MsgW state. 23634e04225SDavid du Colombier */ 23734e04225SDavid du Colombier if(old->t.type == Tflush){ 23834e04225SDavid du Colombier /* 23934e04225SDavid du Colombier * For Msg9 state, the old message may 24034e04225SDavid du Colombier * or may not be on the write queue. 24134e04225SDavid du Colombier * Mark the message as flushed and let 24234e04225SDavid du Colombier * the write process throw it away after 24334e04225SDavid du Colombier * after pulling it off the write queue. 24434e04225SDavid du Colombier */ 24534e04225SDavid du Colombier if(old->state == Msg9){ 24634e04225SDavid du Colombier old->state = MsgF; 24734e04225SDavid du Colombier if(Dflag) 24834e04225SDavid du Colombier fprint(2, "msgFlush: change %d from Msg9 to MsgF\n", m->t.oldtag); 24934e04225SDavid du Colombier vtUnlock(con->mlock); 25034e04225SDavid du Colombier return; 25134e04225SDavid du Colombier } 25234e04225SDavid du Colombier assert(old->state == MsgW); 25334e04225SDavid du Colombier 25434e04225SDavid du Colombier /* 25534e04225SDavid du Colombier * A flush in MsgW state implies it is waiting 25634e04225SDavid du Colombier * for its corresponding old message to be written, 25734e04225SDavid du Colombier * so it can be deleted right here, right now... 25834e04225SDavid du Colombier * right here, right now... right here, right now... 25934e04225SDavid du Colombier * right about now... the funk soul brother. 26034e04225SDavid du Colombier */ 26134e04225SDavid du Colombier if(Dflag) 26234e04225SDavid du Colombier fprint(2, "msgFlush: delete pending flush %F\n", &old->t); 26334e04225SDavid du Colombier msgUnlinkUnlockAndFree(old); 26434e04225SDavid du Colombier return; 26534e04225SDavid du Colombier } 26634e04225SDavid du Colombier 26734e04225SDavid du Colombier /* 26834e04225SDavid du Colombier * Must wait for the old message to be written. 26934e04225SDavid du Colombier * Add m to old's flush queue. 27034e04225SDavid du Colombier * Old is the head of its own flush queue. 27134e04225SDavid du Colombier */ 27234e04225SDavid du Colombier m->fprev = old; 27334e04225SDavid du Colombier m->fnext = old->fnext; 27434e04225SDavid du Colombier if(m->fnext) 27534e04225SDavid du Colombier m->fnext->fprev = m; 27634e04225SDavid du Colombier old->fnext = m; 27734e04225SDavid du Colombier if(Dflag) 27834e04225SDavid du Colombier fprint(2, "msgFlush: add %d to %d queue\n", m->t.tag, old->t.tag); 27934e04225SDavid du Colombier vtUnlock(con->mlock); 2805e96a66cSDavid du Colombier } 2815e96a66cSDavid du Colombier 2825e96a66cSDavid du Colombier static void 2835e96a66cSDavid du Colombier msgProc(void*) 2845e96a66cSDavid du Colombier { 2855e96a66cSDavid du Colombier Msg *m; 2865e96a66cSDavid du Colombier char *e; 2875e96a66cSDavid du Colombier Con *con; 2885e96a66cSDavid du Colombier 28934e04225SDavid du Colombier vtThreadSetName("msgProc"); 2905e96a66cSDavid du Colombier 29134e04225SDavid du Colombier for(;;){ 29234e04225SDavid du Colombier /* 29334e04225SDavid du Colombier * If surplus to requirements, exit. 29434e04225SDavid du Colombier * If not, wait for and pull a message off 29534e04225SDavid du Colombier * the read queue. 29634e04225SDavid du Colombier */ 29734e04225SDavid du Colombier vtLock(mbox.rlock); 29834e04225SDavid du Colombier if(mbox.nproc > mbox.maxproc){ 29934e04225SDavid du Colombier mbox.nproc--; 30034e04225SDavid du Colombier vtUnlock(mbox.rlock); 30134e04225SDavid du Colombier break; 30234e04225SDavid du Colombier } 30334e04225SDavid du Colombier while(mbox.rhead == nil) 30434e04225SDavid du Colombier vtSleep(mbox.rrendez); 30534e04225SDavid du Colombier m = mbox.rhead; 30634e04225SDavid du Colombier mbox.rhead = m->rwnext; 30734e04225SDavid du Colombier m->rwnext = nil; 30834e04225SDavid du Colombier vtUnlock(mbox.rlock); 3095e96a66cSDavid du Colombier 3105e96a66cSDavid du Colombier con = m->con; 31134e04225SDavid du Colombier e = nil; 3125e96a66cSDavid du Colombier 31334e04225SDavid du Colombier /* 31434e04225SDavid du Colombier * If the message has been flushed before any 31534e04225SDavid du Colombier * 9P processing has started, just throw it away. 31634e04225SDavid du Colombier */ 31734e04225SDavid du Colombier vtLock(con->mlock); 31834e04225SDavid du Colombier if(m->state == MsgF){ 31934e04225SDavid du Colombier msgUnlinkUnlockAndFree(m); 32034e04225SDavid du Colombier continue; 32134e04225SDavid du Colombier } 32234e04225SDavid du Colombier m->state = Msg9; 32334e04225SDavid du Colombier vtUnlock(con->mlock); 32434e04225SDavid du Colombier 32534e04225SDavid du Colombier /* 32634e04225SDavid du Colombier * explain this 32734e04225SDavid du Colombier */ 32834e04225SDavid du Colombier vtLock(con->lock); 3295e96a66cSDavid du Colombier if(m->t.type == Tversion){ 3305e96a66cSDavid du Colombier con->version = m; 33134e04225SDavid du Colombier con->state = ConDown; 33234e04225SDavid du Colombier while(con->mhead != m) 33334e04225SDavid du Colombier vtSleep(con->rendez); 33434e04225SDavid du Colombier assert(con->state == ConDown); 3355e96a66cSDavid du Colombier if(con->version == m){ 3365e96a66cSDavid du Colombier con->version = nil; 33734e04225SDavid du Colombier con->state = ConInit; 3385e96a66cSDavid du Colombier } 3395e96a66cSDavid du Colombier else 3405e96a66cSDavid du Colombier e = "Tversion aborted"; 3415e96a66cSDavid du Colombier } 34234e04225SDavid du Colombier else if(con->state != ConUp) 3435e96a66cSDavid du Colombier e = "connection not ready"; 3445e96a66cSDavid du Colombier vtUnlock(con->lock); 3455e96a66cSDavid du Colombier 3465e96a66cSDavid du Colombier /* 3475e96a66cSDavid du Colombier * Dispatch if not error already. 3485e96a66cSDavid du Colombier */ 3495e96a66cSDavid du Colombier m->r.tag = m->t.tag; 3505e96a66cSDavid du Colombier if(e == nil && !(*rFcall[m->t.type])(m)) 3515e96a66cSDavid du Colombier e = vtGetError(); 3525e96a66cSDavid du Colombier if(e != nil){ 3535e96a66cSDavid du Colombier m->r.type = Rerror; 3545e96a66cSDavid du Colombier m->r.ename = e; 3555e96a66cSDavid du Colombier } 3565e96a66cSDavid du Colombier else 3575e96a66cSDavid du Colombier m->r.type = m->t.type+1; 3585e96a66cSDavid du Colombier 35934e04225SDavid du Colombier 3605e96a66cSDavid du Colombier /* 36134e04225SDavid du Colombier * Put the message (with reply) on the 36234e04225SDavid du Colombier * write queue and wakeup the write process. 3635e96a66cSDavid du Colombier */ 36434e04225SDavid du Colombier vtLock(con->wlock); 36534e04225SDavid du Colombier if(con->whead == nil) 36634e04225SDavid du Colombier con->whead = m; 3675e96a66cSDavid du Colombier else 36834e04225SDavid du Colombier con->wtail->rwnext = m; 36934e04225SDavid du Colombier con->wtail = m; 37034e04225SDavid du Colombier vtWakeup(con->wrendez); 37134e04225SDavid du Colombier vtUnlock(con->wlock); 3725e96a66cSDavid du Colombier } 3735e96a66cSDavid du Colombier } 3745e96a66cSDavid du Colombier 3755e96a66cSDavid du Colombier static void 37634e04225SDavid du Colombier msgRead(void* v) 3775e96a66cSDavid du Colombier { 3785e96a66cSDavid du Colombier Msg *m; 3795e96a66cSDavid du Colombier Con *con; 3805e96a66cSDavid du Colombier int eof, fd, n; 3815e96a66cSDavid du Colombier 38234e04225SDavid du Colombier vtThreadSetName("msgRead"); 3835e96a66cSDavid du Colombier 3845e96a66cSDavid du Colombier con = v; 3855e96a66cSDavid du Colombier fd = con->fd; 3865e96a66cSDavid du Colombier eof = 0; 3875e96a66cSDavid du Colombier 3885e96a66cSDavid du Colombier while(!eof){ 38934e04225SDavid du Colombier m = msgAlloc(con); 3905e96a66cSDavid du Colombier 3915e96a66cSDavid du Colombier while((n = read9pmsg(fd, m->data, con->msize)) == 0) 3925e96a66cSDavid du Colombier ; 3935e96a66cSDavid du Colombier if(n < 0){ 3945e96a66cSDavid du Colombier m->t.type = Tversion; 3955e96a66cSDavid du Colombier m->t.fid = NOFID; 3965e96a66cSDavid du Colombier m->t.tag = NOTAG; 3975e96a66cSDavid du Colombier m->t.msize = con->msize; 3985e96a66cSDavid du Colombier m->t.version = "9PEoF"; 3995e96a66cSDavid du Colombier eof = 1; 4005e96a66cSDavid du Colombier } 4015e96a66cSDavid du Colombier else if(convM2S(m->data, n, &m->t) != n){ 4025e96a66cSDavid du Colombier if(Dflag) 40334e04225SDavid du Colombier fprint(2, "msgRead: convM2S error: %s\n", 4045e96a66cSDavid du Colombier con->name); 4055e96a66cSDavid du Colombier msgFree(m); 4065e96a66cSDavid du Colombier continue; 4075e96a66cSDavid du Colombier } 4085e96a66cSDavid du Colombier if(Dflag) 409*39734e7eSDavid du Colombier fprint(2, "msgRead %p: t %F\n", con, &m->t); 4105e96a66cSDavid du Colombier 41134e04225SDavid du Colombier vtLock(con->mlock); 41234e04225SDavid du Colombier if(con->mtail != nil){ 41334e04225SDavid du Colombier m->mprev = con->mtail; 41434e04225SDavid du Colombier con->mtail->mnext = m; 41534e04225SDavid du Colombier } 41634e04225SDavid du Colombier else{ 41734e04225SDavid du Colombier con->mhead = m; 41834e04225SDavid du Colombier m->mprev = nil; 41934e04225SDavid du Colombier } 42034e04225SDavid du Colombier con->mtail = m; 42134e04225SDavid du Colombier vtUnlock(con->mlock); 42234e04225SDavid du Colombier 42334e04225SDavid du Colombier vtLock(mbox.rlock); 42434e04225SDavid du Colombier if(mbox.rhead == nil){ 42534e04225SDavid du Colombier mbox.rhead = m; 42634e04225SDavid du Colombier if(!vtWakeup(mbox.rrendez)){ 42734e04225SDavid du Colombier if(mbox.nproc < mbox.maxproc){ 4285e96a66cSDavid du Colombier if(vtThread(msgProc, nil) > 0) 4295e96a66cSDavid du Colombier mbox.nproc++; 4305e96a66cSDavid du Colombier } 43134e04225SDavid du Colombier else 43234e04225SDavid du Colombier mbox.nprocstarve++; 43334e04225SDavid du Colombier } 43434e04225SDavid du Colombier /* 43534e04225SDavid du Colombier * don't need this surely? 43634e04225SDavid du Colombier vtWakeup(mbox.rrendez); 43734e04225SDavid du Colombier */ 4385e96a66cSDavid du Colombier } 4395e96a66cSDavid du Colombier else 44034e04225SDavid du Colombier mbox.rtail->rwnext = m; 44134e04225SDavid du Colombier mbox.rtail = m; 44234e04225SDavid du Colombier vtUnlock(mbox.rlock); 4435e96a66cSDavid du Colombier } 44434e04225SDavid du Colombier } 44534e04225SDavid du Colombier 44634e04225SDavid du Colombier static int 44734e04225SDavid du Colombier _msgWrite(Msg* m) 44834e04225SDavid du Colombier { 44934e04225SDavid du Colombier Con *con; 45034e04225SDavid du Colombier int eof, n; 45134e04225SDavid du Colombier 45234e04225SDavid du Colombier con = m->con; 45334e04225SDavid du Colombier 45434e04225SDavid du Colombier /* 45534e04225SDavid du Colombier * An Rflush with a .fprev implies it is on a flush queue waiting for 45634e04225SDavid du Colombier * its corresponding 'oldtag' message to go out first, so punt 45734e04225SDavid du Colombier * until the 'oldtag' message goes out (see below). 45834e04225SDavid du Colombier */ 45934e04225SDavid du Colombier if(m->r.type == Rflush && m->fprev != nil){ 460*39734e7eSDavid du Colombier fprint(2, "msgWrite %p: delay r %F\n", con, &m->r); 46134e04225SDavid du Colombier return 0; 46234e04225SDavid du Colombier } 46334e04225SDavid du Colombier 46434e04225SDavid du Colombier msgMunlink(m); 46534e04225SDavid du Colombier vtUnlock(con->mlock); 46634e04225SDavid du Colombier 46734e04225SDavid du Colombier /* 46834e04225SDavid du Colombier * TODO: optimise this copy away somehow for 46934e04225SDavid du Colombier * read, stat, etc. 47034e04225SDavid du Colombier */ 47134e04225SDavid du Colombier assert(n = convS2M(&m->r, con->data, con->msize)); 47234e04225SDavid du Colombier if(write(con->fd, con->data, n) != n) 47334e04225SDavid du Colombier eof = 1; 47434e04225SDavid du Colombier else 47534e04225SDavid du Colombier eof = 0; 47634e04225SDavid du Colombier 47734e04225SDavid du Colombier if(Dflag) 478*39734e7eSDavid du Colombier fprint(2, "msgWrite %p: r %F\n", con, &m->r); 47934e04225SDavid du Colombier 48034e04225SDavid du Colombier /* 48134e04225SDavid du Colombier * Just wrote a reply. If it has any flushes waiting 48234e04225SDavid du Colombier * for it to have gone out, recurse down the list writing 48334e04225SDavid du Colombier * them out too. 48434e04225SDavid du Colombier */ 48534e04225SDavid du Colombier vtLock(con->mlock); 48634e04225SDavid du Colombier if(m->fnext != nil){ 48734e04225SDavid du Colombier m->fnext->fprev = nil; 48834e04225SDavid du Colombier eof += _msgWrite(m->fnext); 48934e04225SDavid du Colombier m->fnext = nil; 49034e04225SDavid du Colombier } 49134e04225SDavid du Colombier msgFree(m); 49234e04225SDavid du Colombier 49334e04225SDavid du Colombier return eof; 49434e04225SDavid du Colombier } 49534e04225SDavid du Colombier 49634e04225SDavid du Colombier static void 49734e04225SDavid du Colombier msgWrite(void* v) 49834e04225SDavid du Colombier { 49934e04225SDavid du Colombier Msg *m; 50034e04225SDavid du Colombier int eof; 50134e04225SDavid du Colombier Con *con; 50234e04225SDavid du Colombier 50334e04225SDavid du Colombier vtThreadSetName("msgWrite"); 50434e04225SDavid du Colombier 50534e04225SDavid du Colombier con = v; 50634e04225SDavid du Colombier if(vtThread(msgRead, con) < 0){ 50734e04225SDavid du Colombier conFree(con); 50834e04225SDavid du Colombier return; 50934e04225SDavid du Colombier } 51034e04225SDavid du Colombier 51134e04225SDavid du Colombier for(;;){ 51234e04225SDavid du Colombier /* 51334e04225SDavid du Colombier * Wait for and pull a message off the write queue. 51434e04225SDavid du Colombier */ 51534e04225SDavid du Colombier vtLock(con->wlock); 51634e04225SDavid du Colombier while(con->whead == nil) 51734e04225SDavid du Colombier vtSleep(con->wrendez); 51834e04225SDavid du Colombier m = con->whead; 51934e04225SDavid du Colombier con->whead = m->rwnext; 52034e04225SDavid du Colombier m->rwnext = nil; 52134e04225SDavid du Colombier vtUnlock(con->wlock); 52234e04225SDavid du Colombier 52334e04225SDavid du Colombier /* 52434e04225SDavid du Colombier * Throw the message away if it's a flushed flush, 52534e04225SDavid du Colombier * otherwise change its state and try to write it out. 52634e04225SDavid du Colombier */ 52734e04225SDavid du Colombier vtLock(con->mlock); 52834e04225SDavid du Colombier if(m->state == MsgF){ 52934e04225SDavid du Colombier assert(m->t.type == Tflush); 53034e04225SDavid du Colombier msgUnlinkUnlockAndFree(m); 53134e04225SDavid du Colombier continue; 53234e04225SDavid du Colombier } 53334e04225SDavid du Colombier m->state = MsgW; 53434e04225SDavid du Colombier eof = _msgWrite(m); 53534e04225SDavid du Colombier vtUnlock(con->mlock); 53634e04225SDavid du Colombier 53734e04225SDavid du Colombier vtLock(con->lock); 53834e04225SDavid du Colombier if(eof && con->fd >= 0){ 53934e04225SDavid du Colombier close(con->fd); 54034e04225SDavid du Colombier con->fd = -1; 54134e04225SDavid du Colombier } 54234e04225SDavid du Colombier if(con->state == ConDown) 54334e04225SDavid du Colombier vtWakeup(con->rendez); 54434e04225SDavid du Colombier if(con->state == ConMoribund && con->mhead == nil){ 54534e04225SDavid du Colombier vtUnlock(con->lock); 54634e04225SDavid du Colombier conFree(con); 54734e04225SDavid du Colombier break; 54834e04225SDavid du Colombier } 54934e04225SDavid du Colombier vtUnlock(con->lock); 55034e04225SDavid du Colombier } 5515e96a66cSDavid du Colombier } 5525e96a66cSDavid du Colombier 5535e96a66cSDavid du Colombier Con* 5545e96a66cSDavid du Colombier conAlloc(int fd, char* name) 5555e96a66cSDavid du Colombier { 5565e96a66cSDavid du Colombier Con *con; 5575e96a66cSDavid du Colombier 55834e04225SDavid du Colombier vtLock(cbox.alock); 55934e04225SDavid du Colombier while(cbox.ahead == nil){ 56034e04225SDavid du Colombier if(cbox.ncon >= cbox.maxcon){ 56134e04225SDavid du Colombier cbox.nconstarve++; 56234e04225SDavid du Colombier vtSleep(cbox.arendez); 56334e04225SDavid du Colombier continue; 5645e96a66cSDavid du Colombier } 5655e96a66cSDavid du Colombier con = vtMemAllocZ(sizeof(Con)); 5665e96a66cSDavid du Colombier con->lock = vtLockAlloc(); 56734e04225SDavid du Colombier con->rendez = vtRendezAlloc(con->lock); 5685e96a66cSDavid du Colombier con->data = vtMemAlloc(cbox.msize); 5695e96a66cSDavid du Colombier con->msize = cbox.msize; 57034e04225SDavid du Colombier con->alock = vtLockAlloc(); 57134e04225SDavid du Colombier con->mlock = vtLockAlloc(); 57234e04225SDavid du Colombier con->mrendez = vtRendezAlloc(con->mlock); 57334e04225SDavid du Colombier con->wlock = vtLockAlloc(); 57434e04225SDavid du Colombier con->wrendez = vtRendezAlloc(con->wlock); 5755e96a66cSDavid du Colombier con->fidlock = vtLockAlloc(); 57634e04225SDavid du Colombier 57734e04225SDavid du Colombier cbox.ncon++; 57834e04225SDavid du Colombier cbox.ahead = con; 57934e04225SDavid du Colombier break; 5805e96a66cSDavid du Colombier } 58134e04225SDavid du Colombier con = cbox.ahead; 58234e04225SDavid du Colombier cbox.ahead = con->anext; 58334e04225SDavid du Colombier con->anext = nil; 58434e04225SDavid du Colombier 58534e04225SDavid du Colombier if(cbox.ctail != nil){ 58634e04225SDavid du Colombier con->cprev = cbox.ctail; 58734e04225SDavid du Colombier cbox.ctail->cnext = con; 58834e04225SDavid du Colombier } 58934e04225SDavid du Colombier else{ 59034e04225SDavid du Colombier cbox.chead = con; 59134e04225SDavid du Colombier con->cprev = nil; 59234e04225SDavid du Colombier } 59334e04225SDavid du Colombier cbox.ctail = con; 59434e04225SDavid du Colombier 5955e96a66cSDavid du Colombier assert(con->mhead == nil); 59634e04225SDavid du Colombier assert(con->whead == nil); 5975e96a66cSDavid du Colombier assert(con->fhead == nil); 5985e96a66cSDavid du Colombier assert(con->nfid == 0); 5995e96a66cSDavid du Colombier 60034e04225SDavid du Colombier con->state = ConNew; 6015e96a66cSDavid du Colombier con->fd = fd; 6025e96a66cSDavid du Colombier if(con->name != nil){ 6035e96a66cSDavid du Colombier vtMemFree(con->name); 6045e96a66cSDavid du Colombier con->name = nil; 6055e96a66cSDavid du Colombier } 6065e96a66cSDavid du Colombier if(name != nil) 6075e96a66cSDavid du Colombier con->name = vtStrDup(name); 60834e04225SDavid du Colombier else 60934e04225SDavid du Colombier con->name = vtStrDup("unknown"); 6105e96a66cSDavid du Colombier con->aok = 0; 61134e04225SDavid du Colombier vtUnlock(cbox.alock); 6125e96a66cSDavid du Colombier 61334e04225SDavid du Colombier if(vtThread(msgWrite, con) < 0){ 6145e96a66cSDavid du Colombier conFree(con); 6155e96a66cSDavid du Colombier return nil; 6165e96a66cSDavid du Colombier } 6175e96a66cSDavid du Colombier 6185e96a66cSDavid du Colombier return con; 6195e96a66cSDavid du Colombier } 6205e96a66cSDavid du Colombier 6215e96a66cSDavid du Colombier static int 6225e96a66cSDavid du Colombier cmdMsg(int argc, char* argv[]) 6235e96a66cSDavid du Colombier { 6245e96a66cSDavid du Colombier char *p; 6255e96a66cSDavid du Colombier char *usage = "usage: msg [-m nmsg] [-p nproc]"; 62634e04225SDavid du Colombier int maxmsg, nmsg, nmsgstarve, maxproc, nproc, nprocstarve; 6275e96a66cSDavid du Colombier 6285e96a66cSDavid du Colombier maxmsg = maxproc = 0; 6295e96a66cSDavid du Colombier 6305e96a66cSDavid du Colombier ARGBEGIN{ 6315e96a66cSDavid du Colombier default: 6325e96a66cSDavid du Colombier return cliError(usage); 6335e96a66cSDavid du Colombier case 'm': 6345e96a66cSDavid du Colombier p = ARGF(); 6355e96a66cSDavid du Colombier if(p == nil) 6365e96a66cSDavid du Colombier return cliError(usage); 6375e96a66cSDavid du Colombier maxmsg = strtol(argv[0], &p, 0); 6385e96a66cSDavid du Colombier if(maxmsg <= 0 || p == argv[0] || *p != '\0') 6395e96a66cSDavid du Colombier return cliError(usage); 6405e96a66cSDavid du Colombier break; 6415e96a66cSDavid du Colombier case 'p': 6425e96a66cSDavid du Colombier p = ARGF(); 6435e96a66cSDavid du Colombier if(p == nil) 6445e96a66cSDavid du Colombier return cliError(usage); 6455e96a66cSDavid du Colombier maxproc = strtol(argv[0], &p, 0); 6465e96a66cSDavid du Colombier if(maxproc <= 0 || p == argv[0] || *p != '\0') 6475e96a66cSDavid du Colombier return cliError(usage); 6485e96a66cSDavid du Colombier break; 6495e96a66cSDavid du Colombier }ARGEND 6505e96a66cSDavid du Colombier if(argc) 6515e96a66cSDavid du Colombier return cliError(usage); 6525e96a66cSDavid du Colombier 65334e04225SDavid du Colombier vtLock(mbox.alock); 6545e96a66cSDavid du Colombier if(maxmsg) 6555e96a66cSDavid du Colombier mbox.maxmsg = maxmsg; 6565e96a66cSDavid du Colombier maxmsg = mbox.maxmsg; 65734e04225SDavid du Colombier nmsg = mbox.nmsg; 65834e04225SDavid du Colombier nmsgstarve = mbox.nmsgstarve; 65934e04225SDavid du Colombier vtUnlock(mbox.alock); 66034e04225SDavid du Colombier 66134e04225SDavid du Colombier vtLock(mbox.rlock); 6625e96a66cSDavid du Colombier if(maxproc) 6635e96a66cSDavid du Colombier mbox.maxproc = maxproc; 6645e96a66cSDavid du Colombier maxproc = mbox.maxproc; 66534e04225SDavid du Colombier nproc = mbox.nproc; 66634e04225SDavid du Colombier nprocstarve = mbox.nprocstarve; 66734e04225SDavid du Colombier vtUnlock(mbox.rlock); 6685e96a66cSDavid du Colombier 6695e96a66cSDavid du Colombier consPrint("\tmsg -m %d -p %d\n", maxmsg, maxproc); 67034e04225SDavid du Colombier consPrint("\tnmsg %d nmsgstarve %d nproc %d nprocstarve %d\n", 67134e04225SDavid du Colombier nmsg, nmsgstarve, nproc, nprocstarve); 6725e96a66cSDavid du Colombier 6735e96a66cSDavid du Colombier return 1; 6745e96a66cSDavid du Colombier } 6755e96a66cSDavid du Colombier 67681cf8742SDavid du Colombier static int 67781cf8742SDavid du Colombier scmp(Fid *a, Fid *b) 67881cf8742SDavid du Colombier { 67981cf8742SDavid du Colombier if(a == 0) 68081cf8742SDavid du Colombier return 1; 68181cf8742SDavid du Colombier if(b == 0) 68281cf8742SDavid du Colombier return -1; 68381cf8742SDavid du Colombier return strcmp(a->uname, b->uname); 68481cf8742SDavid du Colombier } 68581cf8742SDavid du Colombier 68681cf8742SDavid du Colombier static Fid* 68781cf8742SDavid du Colombier fidMerge(Fid *a, Fid *b) 68881cf8742SDavid du Colombier { 68981cf8742SDavid du Colombier Fid *s, **l; 69081cf8742SDavid du Colombier 69181cf8742SDavid du Colombier l = &s; 69281cf8742SDavid du Colombier while(a || b){ 69381cf8742SDavid du Colombier if(scmp(a, b) < 0){ 69481cf8742SDavid du Colombier *l = a; 69581cf8742SDavid du Colombier l = &a->sort; 69681cf8742SDavid du Colombier a = a->sort; 69781cf8742SDavid du Colombier }else{ 69881cf8742SDavid du Colombier *l = b; 69981cf8742SDavid du Colombier l = &b->sort; 70081cf8742SDavid du Colombier b = b->sort; 70181cf8742SDavid du Colombier } 70281cf8742SDavid du Colombier } 70381cf8742SDavid du Colombier *l = 0; 70481cf8742SDavid du Colombier return s; 70581cf8742SDavid du Colombier } 70681cf8742SDavid du Colombier 70781cf8742SDavid du Colombier static Fid* 70881cf8742SDavid du Colombier fidMergeSort(Fid *f) 70981cf8742SDavid du Colombier { 71081cf8742SDavid du Colombier int delay; 71181cf8742SDavid du Colombier Fid *a, *b; 71281cf8742SDavid du Colombier 71381cf8742SDavid du Colombier if(f == nil) 71481cf8742SDavid du Colombier return nil; 71581cf8742SDavid du Colombier if(f->sort == nil) 71681cf8742SDavid du Colombier return f; 71781cf8742SDavid du Colombier 71881cf8742SDavid du Colombier a = b = f; 71981cf8742SDavid du Colombier delay = 1; 72081cf8742SDavid du Colombier while(a && b){ 72181cf8742SDavid du Colombier if(delay) /* easy way to handle 2-element list */ 72281cf8742SDavid du Colombier delay = 0; 72381cf8742SDavid du Colombier else 72481cf8742SDavid du Colombier a = a->sort; 72581cf8742SDavid du Colombier if(b = b->sort) 72681cf8742SDavid du Colombier b = b->sort; 72781cf8742SDavid du Colombier } 72881cf8742SDavid du Colombier 72981cf8742SDavid du Colombier b = a->sort; 73081cf8742SDavid du Colombier a->sort = nil; 73181cf8742SDavid du Colombier 73281cf8742SDavid du Colombier a = fidMergeSort(f); 73381cf8742SDavid du Colombier b = fidMergeSort(b); 73481cf8742SDavid du Colombier 73581cf8742SDavid du Colombier return fidMerge(a, b); 73681cf8742SDavid du Colombier } 73781cf8742SDavid du Colombier 73881cf8742SDavid du Colombier static int 73981cf8742SDavid du Colombier cmdWho(int argc, char* argv[]) 74081cf8742SDavid du Colombier { 74181cf8742SDavid du Colombier char *usage = "usage: who"; 74281cf8742SDavid du Colombier int i; 74381cf8742SDavid du Colombier Con *con; 74481cf8742SDavid du Colombier Fid *fid, *last; 74581cf8742SDavid du Colombier 74681cf8742SDavid du Colombier ARGBEGIN{ 74781cf8742SDavid du Colombier default: 74881cf8742SDavid du Colombier return cliError(usage); 74981cf8742SDavid du Colombier }ARGEND 75081cf8742SDavid du Colombier 75181cf8742SDavid du Colombier if(argc > 0) 75281cf8742SDavid du Colombier return cliError(usage); 75381cf8742SDavid du Colombier 75481cf8742SDavid du Colombier vtRLock(cbox.clock); 75581cf8742SDavid du Colombier for(con=cbox.chead; con; con=con->cnext){ 75681cf8742SDavid du Colombier consPrint("\t%q:", con->name); 75781cf8742SDavid du Colombier vtLock(con->fidlock); 75881cf8742SDavid du Colombier last = nil; 75981cf8742SDavid du Colombier for(i=0; i<NFidHash; i++) 76081cf8742SDavid du Colombier for(fid=con->fidhash[i]; fid; fid=fid->hash) 76181cf8742SDavid du Colombier if(fid->fidno != NOFID && fid->uname){ 76281cf8742SDavid du Colombier fid->sort = last; 76381cf8742SDavid du Colombier last = fid; 76481cf8742SDavid du Colombier } 76581cf8742SDavid du Colombier fid = fidMergeSort(last); 76681cf8742SDavid du Colombier last = nil; 76781cf8742SDavid du Colombier for(; fid; last=fid, fid=fid->sort) 76881cf8742SDavid du Colombier if(last==nil || strcmp(fid->uname, last->uname) != 0) 76981cf8742SDavid du Colombier consPrint(" %q", fid->uname); 77081cf8742SDavid du Colombier vtUnlock(con->fidlock); 77181cf8742SDavid du Colombier consPrint("\n"); 77281cf8742SDavid du Colombier } 77381cf8742SDavid du Colombier vtRUnlock(cbox.clock); 77481cf8742SDavid du Colombier return 1; 77581cf8742SDavid du Colombier } 77681cf8742SDavid du Colombier 7775e96a66cSDavid du Colombier void 77834e04225SDavid du Colombier msgInit(void) 7795e96a66cSDavid du Colombier { 78034e04225SDavid du Colombier mbox.alock = vtLockAlloc(); 78134e04225SDavid du Colombier mbox.arendez = vtRendezAlloc(mbox.alock); 78234e04225SDavid du Colombier 78334e04225SDavid du Colombier mbox.rlock = vtLockAlloc(); 78434e04225SDavid du Colombier mbox.rrendez = vtRendezAlloc(mbox.rlock); 7855e96a66cSDavid du Colombier 7865e96a66cSDavid du Colombier mbox.maxmsg = NMsgInit; 7875e96a66cSDavid du Colombier mbox.maxproc = NMsgProcInit; 7885e96a66cSDavid du Colombier mbox.msize = NMsizeInit; 7895e96a66cSDavid du Colombier 7905e96a66cSDavid du Colombier cliAddCmd("msg", cmdMsg); 79134e04225SDavid du Colombier } 7925e96a66cSDavid du Colombier 79334e04225SDavid du Colombier static int 79434e04225SDavid du Colombier cmdCon(int argc, char* argv[]) 79534e04225SDavid du Colombier { 79634e04225SDavid du Colombier char *p; 79734e04225SDavid du Colombier Con *con; 79834e04225SDavid du Colombier char *usage = "usage: con [-m ncon]"; 79934e04225SDavid du Colombier int maxcon, ncon, nconstarve; 80034e04225SDavid du Colombier 80134e04225SDavid du Colombier maxcon = 0; 80234e04225SDavid du Colombier 80334e04225SDavid du Colombier ARGBEGIN{ 80434e04225SDavid du Colombier default: 80534e04225SDavid du Colombier return cliError(usage); 80634e04225SDavid du Colombier case 'm': 80734e04225SDavid du Colombier p = ARGF(); 80834e04225SDavid du Colombier if(p == nil) 80934e04225SDavid du Colombier return cliError(usage); 81034e04225SDavid du Colombier maxcon = strtol(argv[0], &p, 0); 81134e04225SDavid du Colombier if(maxcon <= 0 || p == argv[0] || *p != '\0') 81234e04225SDavid du Colombier return cliError(usage); 81334e04225SDavid du Colombier break; 81434e04225SDavid du Colombier }ARGEND 81534e04225SDavid du Colombier if(argc) 81634e04225SDavid du Colombier return cliError(usage); 81734e04225SDavid du Colombier 81834e04225SDavid du Colombier vtLock(cbox.clock); 81934e04225SDavid du Colombier if(maxcon) 82034e04225SDavid du Colombier cbox.maxcon = maxcon; 82134e04225SDavid du Colombier maxcon = cbox.maxcon; 82234e04225SDavid du Colombier ncon = cbox.ncon; 82334e04225SDavid du Colombier nconstarve = cbox.nconstarve; 82434e04225SDavid du Colombier vtUnlock(cbox.clock); 82534e04225SDavid du Colombier 82634e04225SDavid du Colombier consPrint("\tcon -m %d\n", maxcon); 82734e04225SDavid du Colombier consPrint("\tncon %d nconstarve %d\n", ncon, nconstarve); 82834e04225SDavid du Colombier 82934e04225SDavid du Colombier vtRLock(cbox.clock); 83034e04225SDavid du Colombier for(con = cbox.chead; con != nil; con = con->cnext){ 83134e04225SDavid du Colombier consPrint("\t%s\n", con->name); 83234e04225SDavid du Colombier } 83334e04225SDavid du Colombier vtRUnlock(cbox.clock); 83434e04225SDavid du Colombier 83534e04225SDavid du Colombier return 1; 83634e04225SDavid du Colombier } 83734e04225SDavid du Colombier 83834e04225SDavid du Colombier void 83934e04225SDavid du Colombier conInit(void) 84034e04225SDavid du Colombier { 84134e04225SDavid du Colombier cbox.alock = vtLockAlloc(); 84234e04225SDavid du Colombier cbox.arendez = vtRendezAlloc(cbox.alock); 84334e04225SDavid du Colombier 84434e04225SDavid du Colombier cbox.clock = vtLockAlloc(); 84534e04225SDavid du Colombier 84634e04225SDavid du Colombier cbox.maxcon = NConInit; 8475e96a66cSDavid du Colombier cbox.msize = NMsizeInit; 84834e04225SDavid du Colombier 84934e04225SDavid du Colombier cliAddCmd("con", cmdCon); 85081cf8742SDavid du Colombier cliAddCmd("who", cmdWho); 8515e96a66cSDavid du Colombier } 852