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, 9*fe853e23SDavid du Colombier NMsgInit = 384, 10*fe853e23SDavid du Colombier NMsgProcInit = 64, 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); 1047f1bc48aSDavid du Colombier assert(m->flush == 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; 1477f1bc48aSDavid du Colombier m->nowq = 0; 14834e04225SDavid du Colombier 14934e04225SDavid du Colombier return m; 15034e04225SDavid du Colombier } 15134e04225SDavid du Colombier 15234e04225SDavid du Colombier static void 15334e04225SDavid du Colombier msgMunlink(Msg* m) 15434e04225SDavid du Colombier { 15534e04225SDavid du Colombier Con *con; 15634e04225SDavid du Colombier 15734e04225SDavid du Colombier con = m->con; 15834e04225SDavid du Colombier 15934e04225SDavid du Colombier if(m->mprev != nil) 16034e04225SDavid du Colombier m->mprev->mnext = m->mnext; 16134e04225SDavid du Colombier else 16234e04225SDavid du Colombier con->mhead = m->mnext; 16334e04225SDavid du Colombier if(m->mnext != nil) 16434e04225SDavid du Colombier m->mnext->mprev = m->mprev; 16534e04225SDavid du Colombier else 16634e04225SDavid du Colombier con->mtail = m->mprev; 16734e04225SDavid du Colombier m->mprev = m->mnext = nil; 16834e04225SDavid du Colombier } 16934e04225SDavid du Colombier 17034e04225SDavid du Colombier void 17134e04225SDavid du Colombier msgFlush(Msg* m) 17234e04225SDavid du Colombier { 17334e04225SDavid du Colombier Con *con; 1747f1bc48aSDavid du Colombier Msg *flush, *old; 17534e04225SDavid du Colombier 17634e04225SDavid du Colombier con = m->con; 17734e04225SDavid du Colombier 17828495efeSDavid du Colombier if(Dflag) 17939734e7eSDavid du Colombier fprint(2, "msgFlush %F\n", &m->t); 18039734e7eSDavid du Colombier 18134e04225SDavid du Colombier /* 18228495efeSDavid du Colombier * If this Tflush has been flushed, nothing to do. 18334e04225SDavid du Colombier * Look for the message to be flushed in the 18434e04225SDavid du Colombier * queue of all messages still on this connection. 18528495efeSDavid du Colombier * If it's not found must assume Elvis has already 18628495efeSDavid du Colombier * left the building and reply normally. 18734e04225SDavid du Colombier */ 18834e04225SDavid du Colombier vtLock(con->mlock); 18928495efeSDavid du Colombier if(m->state == MsgF){ 19028495efeSDavid du Colombier vtUnlock(con->mlock); 19128495efeSDavid du Colombier return; 19228495efeSDavid du Colombier } 19334e04225SDavid du Colombier for(old = con->mhead; old != nil; old = old->mnext) 19434e04225SDavid du Colombier if(old->t.tag == m->t.oldtag) 19534e04225SDavid du Colombier break; 19634e04225SDavid du Colombier if(old == nil){ 19734e04225SDavid du Colombier if(Dflag) 19834e04225SDavid du Colombier fprint(2, "msgFlush: cannot find %d\n", m->t.oldtag); 19934e04225SDavid du Colombier vtUnlock(con->mlock); 20034e04225SDavid du Colombier return; 20134e04225SDavid du Colombier } 20234e04225SDavid du Colombier 20328495efeSDavid du Colombier if(Dflag) 20439734e7eSDavid du Colombier fprint(2, "\tmsgFlush found %F\n", &old->t); 20539734e7eSDavid du Colombier 20634e04225SDavid du Colombier /* 20734e04225SDavid du Colombier * Found it. 20828495efeSDavid du Colombier * There are two cases where the old message can be 20928495efeSDavid du Colombier * truly flushed and no reply to the original message given. 21028495efeSDavid du Colombier * The first is when the old message is in MsgR state; no 21128495efeSDavid du Colombier * processing has been done yet and it is still on the read 21228495efeSDavid du Colombier * queue. The second is if old is a Tflush, which doesn't 21328495efeSDavid du Colombier * affect the server state. In both cases, put the old 2147f1bc48aSDavid du Colombier * message into MsgF state and let MsgWrite toss it after 2157f1bc48aSDavid du Colombier * pulling it off the queue. 21634e04225SDavid du Colombier */ 21728495efeSDavid du Colombier if(old->state == MsgR || old->t.type == Tflush){ 21834e04225SDavid du Colombier old->state = MsgF; 21934e04225SDavid du Colombier if(Dflag) 22028495efeSDavid du Colombier fprint(2, "msgFlush: change %d from MsgR to MsgF\n", 22128495efeSDavid du Colombier m->t.oldtag); 22234e04225SDavid du Colombier } 22334e04225SDavid du Colombier 22434e04225SDavid du Colombier /* 22528495efeSDavid du Colombier * Link this flush message and the old message 2267f1bc48aSDavid du Colombier * so multiple flushes can be coalesced (if there are 22728495efeSDavid du Colombier * multiple Tflush messages for a particular pending 22828495efeSDavid du Colombier * request, it is only necessary to respond to the last 22928495efeSDavid du Colombier * one, so any previous can be removed) and to be 23028495efeSDavid du Colombier * sure flushes wait for their corresponding old 23128495efeSDavid du Colombier * message to go out first. 2327f1bc48aSDavid du Colombier * Waiting flush messages do not go on the write queue, 2337f1bc48aSDavid du Colombier * they are processed after the old message is dealt 2347f1bc48aSDavid du Colombier * with. There's no real need to protect the setting of 2357f1bc48aSDavid du Colombier * Msg.nowq, the only code to check it runs in this 2367f1bc48aSDavid du Colombier * process after this routine returns. 23734e04225SDavid du Colombier */ 2387f1bc48aSDavid du Colombier if((flush = old->flush) != nil){ 23934e04225SDavid du Colombier if(Dflag) 24028495efeSDavid du Colombier fprint(2, "msgFlush: remove %d from %d list\n", 2417f1bc48aSDavid du Colombier old->flush->t.tag, old->t.tag); 2427f1bc48aSDavid du Colombier m->flush = flush->flush; 2437f1bc48aSDavid du Colombier flush->flush = nil; 2447f1bc48aSDavid du Colombier msgMunlink(flush); 2457f1bc48aSDavid du Colombier msgFree(flush); 24634e04225SDavid du Colombier } 2477f1bc48aSDavid du Colombier old->flush = m; 2487f1bc48aSDavid du Colombier m->nowq = 1; 24934e04225SDavid du Colombier 25034e04225SDavid du Colombier if(Dflag) 25128495efeSDavid du Colombier fprint(2, "msgFlush: add %d to %d queue\n", 25228495efeSDavid du Colombier m->t.tag, old->t.tag); 25334e04225SDavid du Colombier vtUnlock(con->mlock); 2545e96a66cSDavid du Colombier } 2555e96a66cSDavid du Colombier 2565e96a66cSDavid du Colombier static void 2575e96a66cSDavid du Colombier msgProc(void*) 2585e96a66cSDavid du Colombier { 2595e96a66cSDavid du Colombier Msg *m; 2605e96a66cSDavid du Colombier char *e; 2615e96a66cSDavid du Colombier Con *con; 2625e96a66cSDavid du Colombier 26334e04225SDavid du Colombier vtThreadSetName("msgProc"); 2645e96a66cSDavid du Colombier 26534e04225SDavid du Colombier for(;;){ 26634e04225SDavid du Colombier /* 26734e04225SDavid du Colombier * If surplus to requirements, exit. 26834e04225SDavid du Colombier * If not, wait for and pull a message off 26934e04225SDavid du Colombier * the read queue. 27034e04225SDavid du Colombier */ 27134e04225SDavid du Colombier vtLock(mbox.rlock); 27234e04225SDavid du Colombier if(mbox.nproc > mbox.maxproc){ 27334e04225SDavid du Colombier mbox.nproc--; 27434e04225SDavid du Colombier vtUnlock(mbox.rlock); 27534e04225SDavid du Colombier break; 27634e04225SDavid du Colombier } 27734e04225SDavid du Colombier while(mbox.rhead == nil) 27834e04225SDavid du Colombier vtSleep(mbox.rrendez); 27934e04225SDavid du Colombier m = mbox.rhead; 28034e04225SDavid du Colombier mbox.rhead = m->rwnext; 28134e04225SDavid du Colombier m->rwnext = nil; 28234e04225SDavid du Colombier vtUnlock(mbox.rlock); 2835e96a66cSDavid du Colombier 2845e96a66cSDavid du Colombier con = m->con; 28534e04225SDavid du Colombier e = nil; 2865e96a66cSDavid du Colombier 28734e04225SDavid du Colombier /* 28828495efeSDavid du Colombier * If the message has been flushed before 28928495efeSDavid du Colombier * any 9P processing has started, mark it so 29028495efeSDavid du Colombier * none will be attempted. 29134e04225SDavid du Colombier */ 29234e04225SDavid du Colombier vtLock(con->mlock); 29328495efeSDavid du Colombier if(m->state == MsgF) 29428495efeSDavid du Colombier e = "flushed"; 29528495efeSDavid du Colombier else 29634e04225SDavid du Colombier m->state = Msg9; 29734e04225SDavid du Colombier vtUnlock(con->mlock); 29834e04225SDavid du Colombier 29928495efeSDavid du Colombier if(e == nil){ 30034e04225SDavid du Colombier /* 30134e04225SDavid du Colombier * explain this 30234e04225SDavid du Colombier */ 30334e04225SDavid du Colombier vtLock(con->lock); 3045e96a66cSDavid du Colombier if(m->t.type == Tversion){ 3055e96a66cSDavid du Colombier con->version = m; 30634e04225SDavid du Colombier con->state = ConDown; 30734e04225SDavid du Colombier while(con->mhead != m) 30834e04225SDavid du Colombier vtSleep(con->rendez); 30934e04225SDavid du Colombier assert(con->state == ConDown); 3105e96a66cSDavid du Colombier if(con->version == m){ 3115e96a66cSDavid du Colombier con->version = nil; 31234e04225SDavid du Colombier con->state = ConInit; 3135e96a66cSDavid du Colombier } 3145e96a66cSDavid du Colombier else 3155e96a66cSDavid du Colombier e = "Tversion aborted"; 3165e96a66cSDavid du Colombier } 31734e04225SDavid du Colombier else if(con->state != ConUp) 3185e96a66cSDavid du Colombier e = "connection not ready"; 3195e96a66cSDavid du Colombier vtUnlock(con->lock); 32028495efeSDavid du Colombier } 3215e96a66cSDavid du Colombier 3225e96a66cSDavid du Colombier /* 3235e96a66cSDavid du Colombier * Dispatch if not error already. 3245e96a66cSDavid du Colombier */ 3255e96a66cSDavid du Colombier m->r.tag = m->t.tag; 3265e96a66cSDavid du Colombier if(e == nil && !(*rFcall[m->t.type])(m)) 3275e96a66cSDavid du Colombier e = vtGetError(); 3285e96a66cSDavid du Colombier if(e != nil){ 3295e96a66cSDavid du Colombier m->r.type = Rerror; 3305e96a66cSDavid du Colombier m->r.ename = e; 3315e96a66cSDavid du Colombier } 3325e96a66cSDavid du Colombier else 3335e96a66cSDavid du Colombier m->r.type = m->t.type+1; 3345e96a66cSDavid du Colombier 3355e96a66cSDavid du Colombier /* 33634e04225SDavid du Colombier * Put the message (with reply) on the 33734e04225SDavid du Colombier * write queue and wakeup the write process. 3385e96a66cSDavid du Colombier */ 3397f1bc48aSDavid du Colombier if(!m->nowq){ 34034e04225SDavid du Colombier vtLock(con->wlock); 34134e04225SDavid du Colombier if(con->whead == nil) 34234e04225SDavid du Colombier con->whead = m; 3435e96a66cSDavid du Colombier else 34434e04225SDavid du Colombier con->wtail->rwnext = m; 34534e04225SDavid du Colombier con->wtail = m; 34634e04225SDavid du Colombier vtWakeup(con->wrendez); 34734e04225SDavid du Colombier vtUnlock(con->wlock); 3485e96a66cSDavid du Colombier } 3495e96a66cSDavid du Colombier } 3507f1bc48aSDavid du Colombier } 3515e96a66cSDavid du Colombier 3525e96a66cSDavid du Colombier static void 35334e04225SDavid du Colombier msgRead(void* v) 3545e96a66cSDavid du Colombier { 3555e96a66cSDavid du Colombier Msg *m; 3565e96a66cSDavid du Colombier Con *con; 3575e96a66cSDavid du Colombier int eof, fd, n; 3585e96a66cSDavid du Colombier 35934e04225SDavid du Colombier vtThreadSetName("msgRead"); 3605e96a66cSDavid du Colombier 3615e96a66cSDavid du Colombier con = v; 3625e96a66cSDavid du Colombier fd = con->fd; 3635e96a66cSDavid du Colombier eof = 0; 3645e96a66cSDavid du Colombier 3655e96a66cSDavid du Colombier while(!eof){ 36634e04225SDavid du Colombier m = msgAlloc(con); 3675e96a66cSDavid du Colombier 3685e96a66cSDavid du Colombier while((n = read9pmsg(fd, m->data, con->msize)) == 0) 3695e96a66cSDavid du Colombier ; 3705e96a66cSDavid du Colombier if(n < 0){ 3715e96a66cSDavid du Colombier m->t.type = Tversion; 3725e96a66cSDavid du Colombier m->t.fid = NOFID; 3735e96a66cSDavid du Colombier m->t.tag = NOTAG; 3745e96a66cSDavid du Colombier m->t.msize = con->msize; 3755e96a66cSDavid du Colombier m->t.version = "9PEoF"; 3765e96a66cSDavid du Colombier eof = 1; 3775e96a66cSDavid du Colombier } 3785e96a66cSDavid du Colombier else if(convM2S(m->data, n, &m->t) != n){ 3795e96a66cSDavid du Colombier if(Dflag) 38034e04225SDavid du Colombier fprint(2, "msgRead: convM2S error: %s\n", 3815e96a66cSDavid du Colombier con->name); 3825e96a66cSDavid du Colombier msgFree(m); 3835e96a66cSDavid du Colombier continue; 3845e96a66cSDavid du Colombier } 3855e96a66cSDavid du Colombier if(Dflag) 38639734e7eSDavid du Colombier fprint(2, "msgRead %p: t %F\n", con, &m->t); 3875e96a66cSDavid du Colombier 38834e04225SDavid du Colombier vtLock(con->mlock); 38934e04225SDavid du Colombier if(con->mtail != nil){ 39034e04225SDavid du Colombier m->mprev = con->mtail; 39134e04225SDavid du Colombier con->mtail->mnext = m; 39234e04225SDavid du Colombier } 39334e04225SDavid du Colombier else{ 39434e04225SDavid du Colombier con->mhead = m; 39534e04225SDavid du Colombier m->mprev = nil; 39634e04225SDavid du Colombier } 39734e04225SDavid du Colombier con->mtail = m; 39834e04225SDavid du Colombier vtUnlock(con->mlock); 39934e04225SDavid du Colombier 40034e04225SDavid du Colombier vtLock(mbox.rlock); 40134e04225SDavid du Colombier if(mbox.rhead == nil){ 40234e04225SDavid du Colombier mbox.rhead = m; 40334e04225SDavid du Colombier if(!vtWakeup(mbox.rrendez)){ 40434e04225SDavid du Colombier if(mbox.nproc < mbox.maxproc){ 4055e96a66cSDavid du Colombier if(vtThread(msgProc, nil) > 0) 4065e96a66cSDavid du Colombier mbox.nproc++; 4075e96a66cSDavid du Colombier } 40834e04225SDavid du Colombier else 40934e04225SDavid du Colombier mbox.nprocstarve++; 41034e04225SDavid du Colombier } 41134e04225SDavid du Colombier /* 41234e04225SDavid du Colombier * don't need this surely? 41334e04225SDavid du Colombier vtWakeup(mbox.rrendez); 41434e04225SDavid du Colombier */ 4155e96a66cSDavid du Colombier } 4165e96a66cSDavid du Colombier else 41734e04225SDavid du Colombier mbox.rtail->rwnext = m; 41834e04225SDavid du Colombier mbox.rtail = m; 41934e04225SDavid du Colombier vtUnlock(mbox.rlock); 4205e96a66cSDavid du Colombier } 42134e04225SDavid du Colombier } 42234e04225SDavid du Colombier 42334e04225SDavid du Colombier static void 42434e04225SDavid du Colombier msgWrite(void* v) 42534e04225SDavid du Colombier { 42634e04225SDavid du Colombier Con *con; 4277f1bc48aSDavid du Colombier int eof, n; 4287f1bc48aSDavid du Colombier Msg *flush, *m; 42934e04225SDavid du Colombier 43034e04225SDavid du Colombier vtThreadSetName("msgWrite"); 43134e04225SDavid du Colombier 43234e04225SDavid du Colombier con = v; 43334e04225SDavid du Colombier if(vtThread(msgRead, con) < 0){ 43434e04225SDavid du Colombier conFree(con); 43534e04225SDavid du Colombier return; 43634e04225SDavid du Colombier } 43734e04225SDavid du Colombier 43834e04225SDavid du Colombier for(;;){ 43934e04225SDavid du Colombier /* 44034e04225SDavid du Colombier * Wait for and pull a message off the write queue. 44134e04225SDavid du Colombier */ 44234e04225SDavid du Colombier vtLock(con->wlock); 44334e04225SDavid du Colombier while(con->whead == nil) 44434e04225SDavid du Colombier vtSleep(con->wrendez); 44534e04225SDavid du Colombier m = con->whead; 44634e04225SDavid du Colombier con->whead = m->rwnext; 44734e04225SDavid du Colombier m->rwnext = nil; 4487f1bc48aSDavid du Colombier assert(!m->nowq); 44934e04225SDavid du Colombier vtUnlock(con->wlock); 45034e04225SDavid du Colombier 4517f1bc48aSDavid du Colombier eof = 0; 4527f1bc48aSDavid du Colombier 45334e04225SDavid du Colombier /* 4547f1bc48aSDavid du Colombier * Write each message (if it hasn't been flushed) 4557f1bc48aSDavid du Colombier * followed by any messages waiting for it to complete. 45634e04225SDavid du Colombier */ 45734e04225SDavid du Colombier vtLock(con->mlock); 4587f1bc48aSDavid du Colombier while(m != nil){ 4597f1bc48aSDavid du Colombier msgMunlink(m); 4607f1bc48aSDavid du Colombier 4617f1bc48aSDavid du Colombier if(Dflag) 4627f1bc48aSDavid du Colombier fprint(2, "msgWrite %d: r %F\n", 4637f1bc48aSDavid du Colombier m->state, &m->r); 4647f1bc48aSDavid du Colombier 4657f1bc48aSDavid du Colombier if(m->state != MsgF){ 46634e04225SDavid du Colombier m->state = MsgW; 4677f1bc48aSDavid du Colombier vtUnlock(con->mlock); 4687f1bc48aSDavid du Colombier 4697f1bc48aSDavid du Colombier n = convS2M(&m->r, con->data, con->msize); 4707f1bc48aSDavid du Colombier if(write(con->fd, con->data, n) != n) 4717f1bc48aSDavid du Colombier eof = 1; 4727f1bc48aSDavid du Colombier 4737f1bc48aSDavid du Colombier vtLock(con->mlock); 4747f1bc48aSDavid du Colombier } 4757f1bc48aSDavid du Colombier 4767f1bc48aSDavid du Colombier if((flush = m->flush) != nil){ 4777f1bc48aSDavid du Colombier assert(flush->nowq); 4787f1bc48aSDavid du Colombier m->flush = nil; 4797f1bc48aSDavid du Colombier } 4807f1bc48aSDavid du Colombier msgFree(m); 4817f1bc48aSDavid du Colombier m = flush; 4827f1bc48aSDavid du Colombier } 48334e04225SDavid du Colombier vtUnlock(con->mlock); 48434e04225SDavid du Colombier 48534e04225SDavid du Colombier vtLock(con->lock); 48634e04225SDavid du Colombier if(eof && con->fd >= 0){ 48734e04225SDavid du Colombier close(con->fd); 48834e04225SDavid du Colombier con->fd = -1; 48934e04225SDavid du Colombier } 49034e04225SDavid du Colombier if(con->state == ConDown) 49134e04225SDavid du Colombier vtWakeup(con->rendez); 49234e04225SDavid du Colombier if(con->state == ConMoribund && con->mhead == nil){ 49334e04225SDavid du Colombier vtUnlock(con->lock); 49434e04225SDavid du Colombier conFree(con); 49534e04225SDavid du Colombier break; 49634e04225SDavid du Colombier } 49734e04225SDavid du Colombier vtUnlock(con->lock); 49834e04225SDavid du Colombier } 4995e96a66cSDavid du Colombier } 5005e96a66cSDavid du Colombier 5015e96a66cSDavid du Colombier Con* 5025e96a66cSDavid du Colombier conAlloc(int fd, char* name) 5035e96a66cSDavid du Colombier { 5045e96a66cSDavid du Colombier Con *con; 5055e96a66cSDavid du Colombier 50634e04225SDavid du Colombier vtLock(cbox.alock); 50734e04225SDavid du Colombier while(cbox.ahead == nil){ 50834e04225SDavid du Colombier if(cbox.ncon >= cbox.maxcon){ 50934e04225SDavid du Colombier cbox.nconstarve++; 51034e04225SDavid du Colombier vtSleep(cbox.arendez); 51134e04225SDavid du Colombier continue; 5125e96a66cSDavid du Colombier } 5135e96a66cSDavid du Colombier con = vtMemAllocZ(sizeof(Con)); 5145e96a66cSDavid du Colombier con->lock = vtLockAlloc(); 51534e04225SDavid du Colombier con->rendez = vtRendezAlloc(con->lock); 5165e96a66cSDavid du Colombier con->data = vtMemAlloc(cbox.msize); 5175e96a66cSDavid du Colombier con->msize = cbox.msize; 51834e04225SDavid du Colombier con->alock = vtLockAlloc(); 51934e04225SDavid du Colombier con->mlock = vtLockAlloc(); 52034e04225SDavid du Colombier con->mrendez = vtRendezAlloc(con->mlock); 52134e04225SDavid du Colombier con->wlock = vtLockAlloc(); 52234e04225SDavid du Colombier con->wrendez = vtRendezAlloc(con->wlock); 5235e96a66cSDavid du Colombier con->fidlock = vtLockAlloc(); 52434e04225SDavid du Colombier 52534e04225SDavid du Colombier cbox.ncon++; 52634e04225SDavid du Colombier cbox.ahead = con; 52734e04225SDavid du Colombier break; 5285e96a66cSDavid du Colombier } 52934e04225SDavid du Colombier con = cbox.ahead; 53034e04225SDavid du Colombier cbox.ahead = con->anext; 53134e04225SDavid du Colombier con->anext = nil; 53234e04225SDavid du Colombier 53334e04225SDavid du Colombier if(cbox.ctail != nil){ 53434e04225SDavid du Colombier con->cprev = cbox.ctail; 53534e04225SDavid du Colombier cbox.ctail->cnext = con; 53634e04225SDavid du Colombier } 53734e04225SDavid du Colombier else{ 53834e04225SDavid du Colombier cbox.chead = con; 53934e04225SDavid du Colombier con->cprev = nil; 54034e04225SDavid du Colombier } 54134e04225SDavid du Colombier cbox.ctail = con; 54234e04225SDavid du Colombier 5435e96a66cSDavid du Colombier assert(con->mhead == nil); 54434e04225SDavid du Colombier assert(con->whead == nil); 5455e96a66cSDavid du Colombier assert(con->fhead == nil); 5465e96a66cSDavid du Colombier assert(con->nfid == 0); 5475e96a66cSDavid du Colombier 54834e04225SDavid du Colombier con->state = ConNew; 5495e96a66cSDavid du Colombier con->fd = fd; 5505e96a66cSDavid du Colombier if(con->name != nil){ 5515e96a66cSDavid du Colombier vtMemFree(con->name); 5525e96a66cSDavid du Colombier con->name = nil; 5535e96a66cSDavid du Colombier } 5545e96a66cSDavid du Colombier if(name != nil) 5555e96a66cSDavid du Colombier con->name = vtStrDup(name); 55634e04225SDavid du Colombier else 55734e04225SDavid du Colombier con->name = vtStrDup("unknown"); 5585e96a66cSDavid du Colombier con->aok = 0; 55934e04225SDavid du Colombier vtUnlock(cbox.alock); 5605e96a66cSDavid du Colombier 56134e04225SDavid du Colombier if(vtThread(msgWrite, con) < 0){ 5625e96a66cSDavid du Colombier conFree(con); 5635e96a66cSDavid du Colombier return nil; 5645e96a66cSDavid du Colombier } 5655e96a66cSDavid du Colombier 5665e96a66cSDavid du Colombier return con; 5675e96a66cSDavid du Colombier } 5685e96a66cSDavid du Colombier 5695e96a66cSDavid du Colombier static int 5705e96a66cSDavid du Colombier cmdMsg(int argc, char* argv[]) 5715e96a66cSDavid du Colombier { 5725e96a66cSDavid du Colombier char *p; 5735e96a66cSDavid du Colombier char *usage = "usage: msg [-m nmsg] [-p nproc]"; 57434e04225SDavid du Colombier int maxmsg, nmsg, nmsgstarve, maxproc, nproc, nprocstarve; 5755e96a66cSDavid du Colombier 5765e96a66cSDavid du Colombier maxmsg = maxproc = 0; 5775e96a66cSDavid du Colombier 5785e96a66cSDavid du Colombier ARGBEGIN{ 5795e96a66cSDavid du Colombier default: 5805e96a66cSDavid du Colombier return cliError(usage); 5815e96a66cSDavid du Colombier case 'm': 5825e96a66cSDavid du Colombier p = ARGF(); 5835e96a66cSDavid du Colombier if(p == nil) 5845e96a66cSDavid du Colombier return cliError(usage); 5855e96a66cSDavid du Colombier maxmsg = strtol(argv[0], &p, 0); 5865e96a66cSDavid du Colombier if(maxmsg <= 0 || p == argv[0] || *p != '\0') 5875e96a66cSDavid du Colombier return cliError(usage); 5885e96a66cSDavid du Colombier break; 5895e96a66cSDavid du Colombier case 'p': 5905e96a66cSDavid du Colombier p = ARGF(); 5915e96a66cSDavid du Colombier if(p == nil) 5925e96a66cSDavid du Colombier return cliError(usage); 5935e96a66cSDavid du Colombier maxproc = strtol(argv[0], &p, 0); 5945e96a66cSDavid du Colombier if(maxproc <= 0 || p == argv[0] || *p != '\0') 5955e96a66cSDavid du Colombier return cliError(usage); 5965e96a66cSDavid du Colombier break; 5975e96a66cSDavid du Colombier }ARGEND 5985e96a66cSDavid du Colombier if(argc) 5995e96a66cSDavid du Colombier return cliError(usage); 6005e96a66cSDavid du Colombier 60134e04225SDavid du Colombier vtLock(mbox.alock); 6025e96a66cSDavid du Colombier if(maxmsg) 6035e96a66cSDavid du Colombier mbox.maxmsg = maxmsg; 6045e96a66cSDavid du Colombier maxmsg = mbox.maxmsg; 60534e04225SDavid du Colombier nmsg = mbox.nmsg; 60634e04225SDavid du Colombier nmsgstarve = mbox.nmsgstarve; 60734e04225SDavid du Colombier vtUnlock(mbox.alock); 60834e04225SDavid du Colombier 60934e04225SDavid du Colombier vtLock(mbox.rlock); 6105e96a66cSDavid du Colombier if(maxproc) 6115e96a66cSDavid du Colombier mbox.maxproc = maxproc; 6125e96a66cSDavid du Colombier maxproc = mbox.maxproc; 61334e04225SDavid du Colombier nproc = mbox.nproc; 61434e04225SDavid du Colombier nprocstarve = mbox.nprocstarve; 61534e04225SDavid du Colombier vtUnlock(mbox.rlock); 6165e96a66cSDavid du Colombier 6175e96a66cSDavid du Colombier consPrint("\tmsg -m %d -p %d\n", maxmsg, maxproc); 61834e04225SDavid du Colombier consPrint("\tnmsg %d nmsgstarve %d nproc %d nprocstarve %d\n", 61934e04225SDavid du Colombier nmsg, nmsgstarve, nproc, nprocstarve); 6205e96a66cSDavid du Colombier 6215e96a66cSDavid du Colombier return 1; 6225e96a66cSDavid du Colombier } 6235e96a66cSDavid du Colombier 62481cf8742SDavid du Colombier static int 62581cf8742SDavid du Colombier scmp(Fid *a, Fid *b) 62681cf8742SDavid du Colombier { 62781cf8742SDavid du Colombier if(a == 0) 62881cf8742SDavid du Colombier return 1; 62981cf8742SDavid du Colombier if(b == 0) 63081cf8742SDavid du Colombier return -1; 63181cf8742SDavid du Colombier return strcmp(a->uname, b->uname); 63281cf8742SDavid du Colombier } 63381cf8742SDavid du Colombier 63481cf8742SDavid du Colombier static Fid* 63581cf8742SDavid du Colombier fidMerge(Fid *a, Fid *b) 63681cf8742SDavid du Colombier { 63781cf8742SDavid du Colombier Fid *s, **l; 63881cf8742SDavid du Colombier 63981cf8742SDavid du Colombier l = &s; 64081cf8742SDavid du Colombier while(a || b){ 64181cf8742SDavid du Colombier if(scmp(a, b) < 0){ 64281cf8742SDavid du Colombier *l = a; 64381cf8742SDavid du Colombier l = &a->sort; 64481cf8742SDavid du Colombier a = a->sort; 64581cf8742SDavid du Colombier }else{ 64681cf8742SDavid du Colombier *l = b; 64781cf8742SDavid du Colombier l = &b->sort; 64881cf8742SDavid du Colombier b = b->sort; 64981cf8742SDavid du Colombier } 65081cf8742SDavid du Colombier } 65181cf8742SDavid du Colombier *l = 0; 65281cf8742SDavid du Colombier return s; 65381cf8742SDavid du Colombier } 65481cf8742SDavid du Colombier 65581cf8742SDavid du Colombier static Fid* 65681cf8742SDavid du Colombier fidMergeSort(Fid *f) 65781cf8742SDavid du Colombier { 65881cf8742SDavid du Colombier int delay; 65981cf8742SDavid du Colombier Fid *a, *b; 66081cf8742SDavid du Colombier 66181cf8742SDavid du Colombier if(f == nil) 66281cf8742SDavid du Colombier return nil; 66381cf8742SDavid du Colombier if(f->sort == nil) 66481cf8742SDavid du Colombier return f; 66581cf8742SDavid du Colombier 66681cf8742SDavid du Colombier a = b = f; 66781cf8742SDavid du Colombier delay = 1; 66881cf8742SDavid du Colombier while(a && b){ 66981cf8742SDavid du Colombier if(delay) /* easy way to handle 2-element list */ 67081cf8742SDavid du Colombier delay = 0; 67181cf8742SDavid du Colombier else 67281cf8742SDavid du Colombier a = a->sort; 67381cf8742SDavid du Colombier if(b = b->sort) 67481cf8742SDavid du Colombier b = b->sort; 67581cf8742SDavid du Colombier } 67681cf8742SDavid du Colombier 67781cf8742SDavid du Colombier b = a->sort; 67881cf8742SDavid du Colombier a->sort = nil; 67981cf8742SDavid du Colombier 68081cf8742SDavid du Colombier a = fidMergeSort(f); 68181cf8742SDavid du Colombier b = fidMergeSort(b); 68281cf8742SDavid du Colombier 68381cf8742SDavid du Colombier return fidMerge(a, b); 68481cf8742SDavid du Colombier } 68581cf8742SDavid du Colombier 68681cf8742SDavid du Colombier static int 68781cf8742SDavid du Colombier cmdWho(int argc, char* argv[]) 68881cf8742SDavid du Colombier { 68981cf8742SDavid du Colombier char *usage = "usage: who"; 69081cf8742SDavid du Colombier int i; 69181cf8742SDavid du Colombier Con *con; 69281cf8742SDavid du Colombier Fid *fid, *last; 69381cf8742SDavid du Colombier 69481cf8742SDavid du Colombier ARGBEGIN{ 69581cf8742SDavid du Colombier default: 69681cf8742SDavid du Colombier return cliError(usage); 69781cf8742SDavid du Colombier }ARGEND 69881cf8742SDavid du Colombier 69981cf8742SDavid du Colombier if(argc > 0) 70081cf8742SDavid du Colombier return cliError(usage); 70181cf8742SDavid du Colombier 70281cf8742SDavid du Colombier vtRLock(cbox.clock); 70381cf8742SDavid du Colombier for(con=cbox.chead; con; con=con->cnext){ 70481cf8742SDavid du Colombier consPrint("\t%q:", con->name); 70581cf8742SDavid du Colombier vtLock(con->fidlock); 70681cf8742SDavid du Colombier last = nil; 70781cf8742SDavid du Colombier for(i=0; i<NFidHash; i++) 70881cf8742SDavid du Colombier for(fid=con->fidhash[i]; fid; fid=fid->hash) 70981cf8742SDavid du Colombier if(fid->fidno != NOFID && fid->uname){ 71081cf8742SDavid du Colombier fid->sort = last; 71181cf8742SDavid du Colombier last = fid; 71281cf8742SDavid du Colombier } 71381cf8742SDavid du Colombier fid = fidMergeSort(last); 71481cf8742SDavid du Colombier last = nil; 71581cf8742SDavid du Colombier for(; fid; last=fid, fid=fid->sort) 71681cf8742SDavid du Colombier if(last==nil || strcmp(fid->uname, last->uname) != 0) 71781cf8742SDavid du Colombier consPrint(" %q", fid->uname); 71881cf8742SDavid du Colombier vtUnlock(con->fidlock); 71981cf8742SDavid du Colombier consPrint("\n"); 72081cf8742SDavid du Colombier } 72181cf8742SDavid du Colombier vtRUnlock(cbox.clock); 72281cf8742SDavid du Colombier return 1; 72381cf8742SDavid du Colombier } 72481cf8742SDavid du Colombier 7255e96a66cSDavid du Colombier void 72634e04225SDavid du Colombier msgInit(void) 7275e96a66cSDavid du Colombier { 72834e04225SDavid du Colombier mbox.alock = vtLockAlloc(); 72934e04225SDavid du Colombier mbox.arendez = vtRendezAlloc(mbox.alock); 73034e04225SDavid du Colombier 73134e04225SDavid du Colombier mbox.rlock = vtLockAlloc(); 73234e04225SDavid du Colombier mbox.rrendez = vtRendezAlloc(mbox.rlock); 7335e96a66cSDavid du Colombier 7345e96a66cSDavid du Colombier mbox.maxmsg = NMsgInit; 7355e96a66cSDavid du Colombier mbox.maxproc = NMsgProcInit; 7365e96a66cSDavid du Colombier mbox.msize = NMsizeInit; 7375e96a66cSDavid du Colombier 7385e96a66cSDavid du Colombier cliAddCmd("msg", cmdMsg); 73934e04225SDavid du Colombier } 7405e96a66cSDavid du Colombier 74134e04225SDavid du Colombier static int 74234e04225SDavid du Colombier cmdCon(int argc, char* argv[]) 74334e04225SDavid du Colombier { 74434e04225SDavid du Colombier char *p; 74534e04225SDavid du Colombier Con *con; 74634e04225SDavid du Colombier char *usage = "usage: con [-m ncon]"; 74734e04225SDavid du Colombier int maxcon, ncon, nconstarve; 74834e04225SDavid du Colombier 74934e04225SDavid du Colombier maxcon = 0; 75034e04225SDavid du Colombier 75134e04225SDavid du Colombier ARGBEGIN{ 75234e04225SDavid du Colombier default: 75334e04225SDavid du Colombier return cliError(usage); 75434e04225SDavid du Colombier case 'm': 75534e04225SDavid du Colombier p = ARGF(); 75634e04225SDavid du Colombier if(p == nil) 75734e04225SDavid du Colombier return cliError(usage); 75834e04225SDavid du Colombier maxcon = strtol(argv[0], &p, 0); 75934e04225SDavid du Colombier if(maxcon <= 0 || p == argv[0] || *p != '\0') 76034e04225SDavid du Colombier return cliError(usage); 76134e04225SDavid du Colombier break; 76234e04225SDavid du Colombier }ARGEND 76334e04225SDavid du Colombier if(argc) 76434e04225SDavid du Colombier return cliError(usage); 76534e04225SDavid du Colombier 76634e04225SDavid du Colombier vtLock(cbox.clock); 76734e04225SDavid du Colombier if(maxcon) 76834e04225SDavid du Colombier cbox.maxcon = maxcon; 76934e04225SDavid du Colombier maxcon = cbox.maxcon; 77034e04225SDavid du Colombier ncon = cbox.ncon; 77134e04225SDavid du Colombier nconstarve = cbox.nconstarve; 77234e04225SDavid du Colombier vtUnlock(cbox.clock); 77334e04225SDavid du Colombier 77434e04225SDavid du Colombier consPrint("\tcon -m %d\n", maxcon); 77534e04225SDavid du Colombier consPrint("\tncon %d nconstarve %d\n", ncon, nconstarve); 77634e04225SDavid du Colombier 77734e04225SDavid du Colombier vtRLock(cbox.clock); 77834e04225SDavid du Colombier for(con = cbox.chead; con != nil; con = con->cnext){ 77934e04225SDavid du Colombier consPrint("\t%s\n", con->name); 78034e04225SDavid du Colombier } 78134e04225SDavid du Colombier vtRUnlock(cbox.clock); 78234e04225SDavid du Colombier 78334e04225SDavid du Colombier return 1; 78434e04225SDavid du Colombier } 78534e04225SDavid du Colombier 78634e04225SDavid du Colombier void 78734e04225SDavid du Colombier conInit(void) 78834e04225SDavid du Colombier { 78934e04225SDavid du Colombier cbox.alock = vtLockAlloc(); 79034e04225SDavid du Colombier cbox.arendez = vtRendezAlloc(cbox.alock); 79134e04225SDavid du Colombier 79234e04225SDavid du Colombier cbox.clock = vtLockAlloc(); 79334e04225SDavid du Colombier 79434e04225SDavid du Colombier cbox.maxcon = NConInit; 7955e96a66cSDavid du Colombier cbox.msize = NMsizeInit; 79634e04225SDavid du Colombier 79734e04225SDavid du Colombier cliAddCmd("con", cmdCon); 79881cf8742SDavid du Colombier cliAddCmd("who", cmdWho); 7995e96a66cSDavid du Colombier } 800