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); 8234e04225SDavid du Colombier vtRendezAlloc(con->wrendez); 8334e04225SDavid du Colombier vtLockFree(con->wlock); 8434e04225SDavid du Colombier vtRendezAlloc(con->mrendez); 8534e04225SDavid du Colombier vtLockFree(con->mlock); 8634e04225SDavid du Colombier vtRendezAlloc(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 19634e04225SDavid du Colombier /* 19734e04225SDavid du Colombier * Look for the message to be flushed in the 19834e04225SDavid du Colombier * queue of all messages still on this connection. 19934e04225SDavid du Colombier */ 20034e04225SDavid du Colombier vtLock(con->mlock); 20134e04225SDavid du Colombier for(old = con->mhead; old != nil; old = old->mnext) 20234e04225SDavid du Colombier if(old->t.tag == m->t.oldtag) 20334e04225SDavid du Colombier break; 20434e04225SDavid du Colombier if(old == nil){ 20534e04225SDavid du Colombier if(Dflag) 20634e04225SDavid du Colombier fprint(2, "msgFlush: cannot find %d\n", m->t.oldtag); 20734e04225SDavid du Colombier vtUnlock(con->mlock); 20834e04225SDavid du Colombier return; 20934e04225SDavid du Colombier } 21034e04225SDavid du Colombier 21134e04225SDavid du Colombier /* 21234e04225SDavid du Colombier * Found it. 21334e04225SDavid du Colombier * 21434e04225SDavid du Colombier * Easy case is no 9P processing done yet, 21534e04225SDavid du Colombier * message is on the read queue. 21634e04225SDavid du Colombier * Mark the message as flushed and let the read 21734e04225SDavid du Colombier * process throw it away after after pulling 21834e04225SDavid du Colombier * it off the read queue. 21934e04225SDavid du Colombier */ 22034e04225SDavid du Colombier if(old->state == MsgR){ 22134e04225SDavid du Colombier old->state = MsgF; 22234e04225SDavid du Colombier if(Dflag) 22334e04225SDavid du Colombier fprint(2, "msgFlush: change %d from MsgR to MsgF\n", m->t.oldtag); 22434e04225SDavid du Colombier vtUnlock(con->mlock); 22534e04225SDavid du Colombier return; 22634e04225SDavid du Colombier } 22734e04225SDavid du Colombier 22834e04225SDavid du Colombier /* 22934e04225SDavid du Colombier * Flushing flushes. 23034e04225SDavid du Colombier * Since they don't affect the server state, flushes 23134e04225SDavid du Colombier * can be deleted when in Msg9 or MsgW state. 23234e04225SDavid du Colombier */ 23334e04225SDavid du Colombier if(old->t.type == Tflush){ 23434e04225SDavid du Colombier /* 23534e04225SDavid du Colombier * For Msg9 state, the old message may 23634e04225SDavid du Colombier * or may not be on the write queue. 23734e04225SDavid du Colombier * Mark the message as flushed and let 23834e04225SDavid du Colombier * the write process throw it away after 23934e04225SDavid du Colombier * after pulling it off the write queue. 24034e04225SDavid du Colombier */ 24134e04225SDavid du Colombier if(old->state == Msg9){ 24234e04225SDavid du Colombier old->state = MsgF; 24334e04225SDavid du Colombier if(Dflag) 24434e04225SDavid du Colombier fprint(2, "msgFlush: change %d from Msg9 to MsgF\n", m->t.oldtag); 24534e04225SDavid du Colombier vtUnlock(con->mlock); 24634e04225SDavid du Colombier return; 24734e04225SDavid du Colombier } 24834e04225SDavid du Colombier assert(old->state == MsgW); 24934e04225SDavid du Colombier 25034e04225SDavid du Colombier /* 25134e04225SDavid du Colombier * A flush in MsgW state implies it is waiting 25234e04225SDavid du Colombier * for its corresponding old message to be written, 25334e04225SDavid du Colombier * so it can be deleted right here, right now... 25434e04225SDavid du Colombier * right here, right now... right here, right now... 25534e04225SDavid du Colombier * right about now... the funk soul brother. 25634e04225SDavid du Colombier */ 25734e04225SDavid du Colombier if(Dflag) 25834e04225SDavid du Colombier fprint(2, "msgFlush: delete pending flush %F\n", &old->t); 25934e04225SDavid du Colombier msgUnlinkUnlockAndFree(old); 26034e04225SDavid du Colombier return; 26134e04225SDavid du Colombier } 26234e04225SDavid du Colombier 26334e04225SDavid du Colombier /* 26434e04225SDavid du Colombier * Must wait for the old message to be written. 26534e04225SDavid du Colombier * Add m to old's flush queue. 26634e04225SDavid du Colombier * Old is the head of its own flush queue. 26734e04225SDavid du Colombier */ 26834e04225SDavid du Colombier m->fprev = old; 26934e04225SDavid du Colombier m->fnext = old->fnext; 27034e04225SDavid du Colombier if(m->fnext) 27134e04225SDavid du Colombier m->fnext->fprev = m; 27234e04225SDavid du Colombier old->fnext = m; 27334e04225SDavid du Colombier if(Dflag) 27434e04225SDavid du Colombier fprint(2, "msgFlush: add %d to %d queue\n", m->t.tag, old->t.tag); 27534e04225SDavid du Colombier vtUnlock(con->mlock); 2765e96a66cSDavid du Colombier } 2775e96a66cSDavid du Colombier 2785e96a66cSDavid du Colombier static void 2795e96a66cSDavid du Colombier msgProc(void*) 2805e96a66cSDavid du Colombier { 2815e96a66cSDavid du Colombier Msg *m; 2825e96a66cSDavid du Colombier char *e; 2835e96a66cSDavid du Colombier Con *con; 2845e96a66cSDavid du Colombier 28534e04225SDavid du Colombier vtThreadSetName("msgProc"); 2865e96a66cSDavid du Colombier 28734e04225SDavid du Colombier for(;;){ 28834e04225SDavid du Colombier /* 28934e04225SDavid du Colombier * If surplus to requirements, exit. 29034e04225SDavid du Colombier * If not, wait for and pull a message off 29134e04225SDavid du Colombier * the read queue. 29234e04225SDavid du Colombier */ 29334e04225SDavid du Colombier vtLock(mbox.rlock); 29434e04225SDavid du Colombier if(mbox.nproc > mbox.maxproc){ 29534e04225SDavid du Colombier mbox.nproc--; 29634e04225SDavid du Colombier vtUnlock(mbox.rlock); 29734e04225SDavid du Colombier break; 29834e04225SDavid du Colombier } 29934e04225SDavid du Colombier while(mbox.rhead == nil) 30034e04225SDavid du Colombier vtSleep(mbox.rrendez); 30134e04225SDavid du Colombier m = mbox.rhead; 30234e04225SDavid du Colombier mbox.rhead = m->rwnext; 30334e04225SDavid du Colombier m->rwnext = nil; 30434e04225SDavid du Colombier vtUnlock(mbox.rlock); 3055e96a66cSDavid du Colombier 3065e96a66cSDavid du Colombier con = m->con; 30734e04225SDavid du Colombier e = nil; 3085e96a66cSDavid du Colombier 30934e04225SDavid du Colombier /* 31034e04225SDavid du Colombier * If the message has been flushed before any 31134e04225SDavid du Colombier * 9P processing has started, just throw it away. 31234e04225SDavid du Colombier */ 31334e04225SDavid du Colombier vtLock(con->mlock); 31434e04225SDavid du Colombier if(m->state == MsgF){ 31534e04225SDavid du Colombier msgUnlinkUnlockAndFree(m); 31634e04225SDavid du Colombier continue; 31734e04225SDavid du Colombier } 31834e04225SDavid du Colombier m->state = Msg9; 31934e04225SDavid du Colombier vtUnlock(con->mlock); 32034e04225SDavid du Colombier 32134e04225SDavid du Colombier /* 32234e04225SDavid du Colombier * explain this 32334e04225SDavid du Colombier */ 32434e04225SDavid du Colombier vtLock(con->lock); 3255e96a66cSDavid du Colombier if(m->t.type == Tversion){ 3265e96a66cSDavid du Colombier con->version = m; 32734e04225SDavid du Colombier con->state = ConDown; 32834e04225SDavid du Colombier while(con->mhead != m) 32934e04225SDavid du Colombier vtSleep(con->rendez); 33034e04225SDavid du Colombier assert(con->state == ConDown); 3315e96a66cSDavid du Colombier if(con->version == m){ 3325e96a66cSDavid du Colombier con->version = nil; 33334e04225SDavid du Colombier con->state = ConInit; 3345e96a66cSDavid du Colombier } 3355e96a66cSDavid du Colombier else 3365e96a66cSDavid du Colombier e = "Tversion aborted"; 3375e96a66cSDavid du Colombier } 33834e04225SDavid du Colombier else if(con->state != ConUp) 3395e96a66cSDavid du Colombier e = "connection not ready"; 3405e96a66cSDavid du Colombier vtUnlock(con->lock); 3415e96a66cSDavid du Colombier 3425e96a66cSDavid du Colombier /* 3435e96a66cSDavid du Colombier * Dispatch if not error already. 3445e96a66cSDavid du Colombier */ 3455e96a66cSDavid du Colombier m->r.tag = m->t.tag; 3465e96a66cSDavid du Colombier if(e == nil && !(*rFcall[m->t.type])(m)) 3475e96a66cSDavid du Colombier e = vtGetError(); 3485e96a66cSDavid du Colombier if(e != nil){ 3495e96a66cSDavid du Colombier m->r.type = Rerror; 3505e96a66cSDavid du Colombier m->r.ename = e; 3515e96a66cSDavid du Colombier } 3525e96a66cSDavid du Colombier else 3535e96a66cSDavid du Colombier m->r.type = m->t.type+1; 3545e96a66cSDavid du Colombier 35534e04225SDavid du Colombier 3565e96a66cSDavid du Colombier /* 35734e04225SDavid du Colombier * Put the message (with reply) on the 35834e04225SDavid du Colombier * write queue and wakeup the write process. 3595e96a66cSDavid du Colombier */ 36034e04225SDavid du Colombier vtLock(con->wlock); 36134e04225SDavid du Colombier if(con->whead == nil) 36234e04225SDavid du Colombier con->whead = m; 3635e96a66cSDavid du Colombier else 36434e04225SDavid du Colombier con->wtail->rwnext = m; 36534e04225SDavid du Colombier con->wtail = m; 36634e04225SDavid du Colombier vtWakeup(con->wrendez); 36734e04225SDavid du Colombier vtUnlock(con->wlock); 3685e96a66cSDavid du Colombier } 3695e96a66cSDavid du Colombier } 3705e96a66cSDavid du Colombier 3715e96a66cSDavid du Colombier static void 37234e04225SDavid du Colombier msgRead(void* v) 3735e96a66cSDavid du Colombier { 3745e96a66cSDavid du Colombier Msg *m; 3755e96a66cSDavid du Colombier Con *con; 3765e96a66cSDavid du Colombier int eof, fd, n; 3775e96a66cSDavid du Colombier 37834e04225SDavid du Colombier vtThreadSetName("msgRead"); 3795e96a66cSDavid du Colombier 3805e96a66cSDavid du Colombier con = v; 3815e96a66cSDavid du Colombier fd = con->fd; 3825e96a66cSDavid du Colombier eof = 0; 3835e96a66cSDavid du Colombier 3845e96a66cSDavid du Colombier while(!eof){ 38534e04225SDavid du Colombier m = msgAlloc(con); 3865e96a66cSDavid du Colombier 3875e96a66cSDavid du Colombier while((n = read9pmsg(fd, m->data, con->msize)) == 0) 3885e96a66cSDavid du Colombier ; 3895e96a66cSDavid du Colombier if(n < 0){ 3905e96a66cSDavid du Colombier m->t.type = Tversion; 3915e96a66cSDavid du Colombier m->t.fid = NOFID; 3925e96a66cSDavid du Colombier m->t.tag = NOTAG; 3935e96a66cSDavid du Colombier m->t.msize = con->msize; 3945e96a66cSDavid du Colombier m->t.version = "9PEoF"; 3955e96a66cSDavid du Colombier eof = 1; 3965e96a66cSDavid du Colombier } 3975e96a66cSDavid du Colombier else if(convM2S(m->data, n, &m->t) != n){ 3985e96a66cSDavid du Colombier if(Dflag) 39934e04225SDavid du Colombier fprint(2, "msgRead: convM2S error: %s\n", 4005e96a66cSDavid du Colombier con->name); 4015e96a66cSDavid du Colombier msgFree(m); 4025e96a66cSDavid du Colombier continue; 4035e96a66cSDavid du Colombier } 4045e96a66cSDavid du Colombier if(Dflag) 40534e04225SDavid du Colombier fprint(2, "msgRead: t %F\n", &m->t); 4065e96a66cSDavid du Colombier 40734e04225SDavid du Colombier vtLock(con->mlock); 40834e04225SDavid du Colombier if(con->mtail != nil){ 40934e04225SDavid du Colombier m->mprev = con->mtail; 41034e04225SDavid du Colombier con->mtail->mnext = m; 41134e04225SDavid du Colombier } 41234e04225SDavid du Colombier else{ 41334e04225SDavid du Colombier con->mhead = m; 41434e04225SDavid du Colombier m->mprev = nil; 41534e04225SDavid du Colombier } 41634e04225SDavid du Colombier con->mtail = m; 41734e04225SDavid du Colombier vtUnlock(con->mlock); 41834e04225SDavid du Colombier 41934e04225SDavid du Colombier vtLock(mbox.rlock); 42034e04225SDavid du Colombier if(mbox.rhead == nil){ 42134e04225SDavid du Colombier mbox.rhead = m; 42234e04225SDavid du Colombier if(!vtWakeup(mbox.rrendez)){ 42334e04225SDavid du Colombier if(mbox.nproc < mbox.maxproc){ 4245e96a66cSDavid du Colombier if(vtThread(msgProc, nil) > 0) 4255e96a66cSDavid du Colombier mbox.nproc++; 4265e96a66cSDavid du Colombier } 42734e04225SDavid du Colombier else 42834e04225SDavid du Colombier mbox.nprocstarve++; 42934e04225SDavid du Colombier } 43034e04225SDavid du Colombier /* 43134e04225SDavid du Colombier * don't need this surely? 43234e04225SDavid du Colombier vtWakeup(mbox.rrendez); 43334e04225SDavid du Colombier */ 4345e96a66cSDavid du Colombier } 4355e96a66cSDavid du Colombier else 43634e04225SDavid du Colombier mbox.rtail->rwnext = m; 43734e04225SDavid du Colombier mbox.rtail = m; 43834e04225SDavid du Colombier vtUnlock(mbox.rlock); 4395e96a66cSDavid du Colombier } 44034e04225SDavid du Colombier } 44134e04225SDavid du Colombier 44234e04225SDavid du Colombier static int 44334e04225SDavid du Colombier _msgWrite(Msg* m) 44434e04225SDavid du Colombier { 44534e04225SDavid du Colombier Con *con; 44634e04225SDavid du Colombier int eof, n; 44734e04225SDavid du Colombier 44834e04225SDavid du Colombier con = m->con; 44934e04225SDavid du Colombier 45034e04225SDavid du Colombier /* 45134e04225SDavid du Colombier * An Rflush with a .fprev implies it is on a flush queue waiting for 45234e04225SDavid du Colombier * its corresponding 'oldtag' message to go out first, so punt 45334e04225SDavid du Colombier * until the 'oldtag' message goes out (see below). 45434e04225SDavid du Colombier */ 45534e04225SDavid du Colombier if(m->r.type == Rflush && m->fprev != nil){ 45634e04225SDavid du Colombier fprint(2, "msgWrite: delay r %F\n", &m->r); 45734e04225SDavid du Colombier return 0; 45834e04225SDavid du Colombier } 45934e04225SDavid du Colombier 46034e04225SDavid du Colombier msgMunlink(m); 46134e04225SDavid du Colombier vtUnlock(con->mlock); 46234e04225SDavid du Colombier 46334e04225SDavid du Colombier /* 46434e04225SDavid du Colombier * TODO: optimise this copy away somehow for 46534e04225SDavid du Colombier * read, stat, etc. 46634e04225SDavid du Colombier */ 46734e04225SDavid du Colombier assert(n = convS2M(&m->r, con->data, con->msize)); 46834e04225SDavid du Colombier if(write(con->fd, con->data, n) != n) 46934e04225SDavid du Colombier eof = 1; 47034e04225SDavid du Colombier else 47134e04225SDavid du Colombier eof = 0; 47234e04225SDavid du Colombier 47334e04225SDavid du Colombier if(Dflag) 47434e04225SDavid du Colombier fprint(2, "msgWrite: r %F\n", &m->r); 47534e04225SDavid du Colombier 47634e04225SDavid du Colombier /* 47734e04225SDavid du Colombier * Just wrote a reply. If it has any flushes waiting 47834e04225SDavid du Colombier * for it to have gone out, recurse down the list writing 47934e04225SDavid du Colombier * them out too. 48034e04225SDavid du Colombier */ 48134e04225SDavid du Colombier vtLock(con->mlock); 48234e04225SDavid du Colombier if(m->fnext != nil){ 48334e04225SDavid du Colombier m->fnext->fprev = nil; 48434e04225SDavid du Colombier eof += _msgWrite(m->fnext); 48534e04225SDavid du Colombier m->fnext = nil; 48634e04225SDavid du Colombier } 48734e04225SDavid du Colombier msgFree(m); 48834e04225SDavid du Colombier 48934e04225SDavid du Colombier return eof; 49034e04225SDavid du Colombier } 49134e04225SDavid du Colombier 49234e04225SDavid du Colombier static void 49334e04225SDavid du Colombier msgWrite(void* v) 49434e04225SDavid du Colombier { 49534e04225SDavid du Colombier Msg *m; 49634e04225SDavid du Colombier int eof; 49734e04225SDavid du Colombier Con *con; 49834e04225SDavid du Colombier 49934e04225SDavid du Colombier vtThreadSetName("msgWrite"); 50034e04225SDavid du Colombier 50134e04225SDavid du Colombier con = v; 50234e04225SDavid du Colombier if(vtThread(msgRead, con) < 0){ 50334e04225SDavid du Colombier conFree(con); 50434e04225SDavid du Colombier return; 50534e04225SDavid du Colombier } 50634e04225SDavid du Colombier 50734e04225SDavid du Colombier for(;;){ 50834e04225SDavid du Colombier /* 50934e04225SDavid du Colombier * Wait for and pull a message off the write queue. 51034e04225SDavid du Colombier */ 51134e04225SDavid du Colombier vtLock(con->wlock); 51234e04225SDavid du Colombier while(con->whead == nil) 51334e04225SDavid du Colombier vtSleep(con->wrendez); 51434e04225SDavid du Colombier m = con->whead; 51534e04225SDavid du Colombier con->whead = m->rwnext; 51634e04225SDavid du Colombier m->rwnext = nil; 51734e04225SDavid du Colombier vtUnlock(con->wlock); 51834e04225SDavid du Colombier 51934e04225SDavid du Colombier /* 52034e04225SDavid du Colombier * Throw the message away if it's a flushed flush, 52134e04225SDavid du Colombier * otherwise change its state and try to write it out. 52234e04225SDavid du Colombier */ 52334e04225SDavid du Colombier vtLock(con->mlock); 52434e04225SDavid du Colombier if(m->state == MsgF){ 52534e04225SDavid du Colombier assert(m->t.type == Tflush); 52634e04225SDavid du Colombier msgUnlinkUnlockAndFree(m); 52734e04225SDavid du Colombier continue; 52834e04225SDavid du Colombier } 52934e04225SDavid du Colombier m->state = MsgW; 53034e04225SDavid du Colombier eof = _msgWrite(m); 53134e04225SDavid du Colombier vtUnlock(con->mlock); 53234e04225SDavid du Colombier 53334e04225SDavid du Colombier vtLock(con->lock); 53434e04225SDavid du Colombier if(eof && con->fd >= 0){ 53534e04225SDavid du Colombier close(con->fd); 53634e04225SDavid du Colombier con->fd = -1; 53734e04225SDavid du Colombier } 53834e04225SDavid du Colombier if(con->state == ConDown) 53934e04225SDavid du Colombier vtWakeup(con->rendez); 54034e04225SDavid du Colombier if(con->state == ConMoribund && con->mhead == nil){ 54134e04225SDavid du Colombier vtUnlock(con->lock); 54234e04225SDavid du Colombier conFree(con); 54334e04225SDavid du Colombier break; 54434e04225SDavid du Colombier } 54534e04225SDavid du Colombier vtUnlock(con->lock); 54634e04225SDavid du Colombier } 5475e96a66cSDavid du Colombier } 5485e96a66cSDavid du Colombier 5495e96a66cSDavid du Colombier Con* 5505e96a66cSDavid du Colombier conAlloc(int fd, char* name) 5515e96a66cSDavid du Colombier { 5525e96a66cSDavid du Colombier Con *con; 5535e96a66cSDavid du Colombier 55434e04225SDavid du Colombier vtLock(cbox.alock); 55534e04225SDavid du Colombier while(cbox.ahead == nil){ 55634e04225SDavid du Colombier if(cbox.ncon >= cbox.maxcon){ 55734e04225SDavid du Colombier cbox.nconstarve++; 55834e04225SDavid du Colombier vtSleep(cbox.arendez); 55934e04225SDavid du Colombier continue; 5605e96a66cSDavid du Colombier } 5615e96a66cSDavid du Colombier con = vtMemAllocZ(sizeof(Con)); 5625e96a66cSDavid du Colombier con->lock = vtLockAlloc(); 56334e04225SDavid du Colombier con->rendez = vtRendezAlloc(con->lock); 5645e96a66cSDavid du Colombier con->data = vtMemAlloc(cbox.msize); 5655e96a66cSDavid du Colombier con->msize = cbox.msize; 56634e04225SDavid du Colombier con->alock = vtLockAlloc(); 56734e04225SDavid du Colombier con->mlock = vtLockAlloc(); 56834e04225SDavid du Colombier con->mrendez = vtRendezAlloc(con->mlock); 56934e04225SDavid du Colombier con->wlock = vtLockAlloc(); 57034e04225SDavid du Colombier con->wrendez = vtRendezAlloc(con->wlock); 5715e96a66cSDavid du Colombier con->fidlock = vtLockAlloc(); 57234e04225SDavid du Colombier 57334e04225SDavid du Colombier cbox.ncon++; 57434e04225SDavid du Colombier cbox.ahead = con; 57534e04225SDavid du Colombier break; 5765e96a66cSDavid du Colombier } 57734e04225SDavid du Colombier con = cbox.ahead; 57834e04225SDavid du Colombier cbox.ahead = con->anext; 57934e04225SDavid du Colombier con->anext = nil; 58034e04225SDavid du Colombier 58134e04225SDavid du Colombier if(cbox.ctail != nil){ 58234e04225SDavid du Colombier con->cprev = cbox.ctail; 58334e04225SDavid du Colombier cbox.ctail->cnext = con; 58434e04225SDavid du Colombier } 58534e04225SDavid du Colombier else{ 58634e04225SDavid du Colombier cbox.chead = con; 58734e04225SDavid du Colombier con->cprev = nil; 58834e04225SDavid du Colombier } 58934e04225SDavid du Colombier cbox.ctail = con; 59034e04225SDavid du Colombier 5915e96a66cSDavid du Colombier assert(con->mhead == nil); 59234e04225SDavid du Colombier assert(con->whead == nil); 5935e96a66cSDavid du Colombier assert(con->fhead == nil); 5945e96a66cSDavid du Colombier assert(con->nfid == 0); 5955e96a66cSDavid du Colombier 59634e04225SDavid du Colombier con->state = ConNew; 5975e96a66cSDavid du Colombier con->fd = fd; 5985e96a66cSDavid du Colombier if(con->name != nil){ 5995e96a66cSDavid du Colombier vtMemFree(con->name); 6005e96a66cSDavid du Colombier con->name = nil; 6015e96a66cSDavid du Colombier } 6025e96a66cSDavid du Colombier if(name != nil) 6035e96a66cSDavid du Colombier con->name = vtStrDup(name); 60434e04225SDavid du Colombier else 60534e04225SDavid du Colombier con->name = vtStrDup("unknown"); 6065e96a66cSDavid du Colombier con->aok = 0; 60734e04225SDavid du Colombier vtUnlock(cbox.alock); 6085e96a66cSDavid du Colombier 60934e04225SDavid du Colombier if(vtThread(msgWrite, con) < 0){ 6105e96a66cSDavid du Colombier conFree(con); 6115e96a66cSDavid du Colombier return nil; 6125e96a66cSDavid du Colombier } 6135e96a66cSDavid du Colombier 6145e96a66cSDavid du Colombier return con; 6155e96a66cSDavid du Colombier } 6165e96a66cSDavid du Colombier 6175e96a66cSDavid du Colombier static int 6185e96a66cSDavid du Colombier cmdMsg(int argc, char* argv[]) 6195e96a66cSDavid du Colombier { 6205e96a66cSDavid du Colombier char *p; 6215e96a66cSDavid du Colombier char *usage = "usage: msg [-m nmsg] [-p nproc]"; 62234e04225SDavid du Colombier int maxmsg, nmsg, nmsgstarve, maxproc, nproc, nprocstarve; 6235e96a66cSDavid du Colombier 6245e96a66cSDavid du Colombier maxmsg = maxproc = 0; 6255e96a66cSDavid du Colombier 6265e96a66cSDavid du Colombier ARGBEGIN{ 6275e96a66cSDavid du Colombier default: 6285e96a66cSDavid du Colombier return cliError(usage); 6295e96a66cSDavid du Colombier case 'm': 6305e96a66cSDavid du Colombier p = ARGF(); 6315e96a66cSDavid du Colombier if(p == nil) 6325e96a66cSDavid du Colombier return cliError(usage); 6335e96a66cSDavid du Colombier maxmsg = strtol(argv[0], &p, 0); 6345e96a66cSDavid du Colombier if(maxmsg <= 0 || p == argv[0] || *p != '\0') 6355e96a66cSDavid du Colombier return cliError(usage); 6365e96a66cSDavid du Colombier break; 6375e96a66cSDavid du Colombier case 'p': 6385e96a66cSDavid du Colombier p = ARGF(); 6395e96a66cSDavid du Colombier if(p == nil) 6405e96a66cSDavid du Colombier return cliError(usage); 6415e96a66cSDavid du Colombier maxproc = strtol(argv[0], &p, 0); 6425e96a66cSDavid du Colombier if(maxproc <= 0 || p == argv[0] || *p != '\0') 6435e96a66cSDavid du Colombier return cliError(usage); 6445e96a66cSDavid du Colombier break; 6455e96a66cSDavid du Colombier }ARGEND 6465e96a66cSDavid du Colombier if(argc) 6475e96a66cSDavid du Colombier return cliError(usage); 6485e96a66cSDavid du Colombier 64934e04225SDavid du Colombier vtLock(mbox.alock); 6505e96a66cSDavid du Colombier if(maxmsg) 6515e96a66cSDavid du Colombier mbox.maxmsg = maxmsg; 6525e96a66cSDavid du Colombier maxmsg = mbox.maxmsg; 65334e04225SDavid du Colombier nmsg = mbox.nmsg; 65434e04225SDavid du Colombier nmsgstarve = mbox.nmsgstarve; 65534e04225SDavid du Colombier vtUnlock(mbox.alock); 65634e04225SDavid du Colombier 65734e04225SDavid du Colombier vtLock(mbox.rlock); 6585e96a66cSDavid du Colombier if(maxproc) 6595e96a66cSDavid du Colombier mbox.maxproc = maxproc; 6605e96a66cSDavid du Colombier maxproc = mbox.maxproc; 66134e04225SDavid du Colombier nproc = mbox.nproc; 66234e04225SDavid du Colombier nprocstarve = mbox.nprocstarve; 66334e04225SDavid du Colombier vtUnlock(mbox.rlock); 6645e96a66cSDavid du Colombier 6655e96a66cSDavid du Colombier consPrint("\tmsg -m %d -p %d\n", maxmsg, maxproc); 66634e04225SDavid du Colombier consPrint("\tnmsg %d nmsgstarve %d nproc %d nprocstarve %d\n", 66734e04225SDavid du Colombier nmsg, nmsgstarve, nproc, nprocstarve); 6685e96a66cSDavid du Colombier 6695e96a66cSDavid du Colombier return 1; 6705e96a66cSDavid du Colombier } 6715e96a66cSDavid du Colombier 672*81cf8742SDavid du Colombier static int 673*81cf8742SDavid du Colombier scmp(Fid *a, Fid *b) 674*81cf8742SDavid du Colombier { 675*81cf8742SDavid du Colombier if(a == 0) 676*81cf8742SDavid du Colombier return 1; 677*81cf8742SDavid du Colombier if(b == 0) 678*81cf8742SDavid du Colombier return -1; 679*81cf8742SDavid du Colombier return strcmp(a->uname, b->uname); 680*81cf8742SDavid du Colombier } 681*81cf8742SDavid du Colombier 682*81cf8742SDavid du Colombier static Fid* 683*81cf8742SDavid du Colombier fidMerge(Fid *a, Fid *b) 684*81cf8742SDavid du Colombier { 685*81cf8742SDavid du Colombier Fid *s, **l; 686*81cf8742SDavid du Colombier 687*81cf8742SDavid du Colombier l = &s; 688*81cf8742SDavid du Colombier while(a || b){ 689*81cf8742SDavid du Colombier if(scmp(a, b) < 0){ 690*81cf8742SDavid du Colombier *l = a; 691*81cf8742SDavid du Colombier l = &a->sort; 692*81cf8742SDavid du Colombier a = a->sort; 693*81cf8742SDavid du Colombier }else{ 694*81cf8742SDavid du Colombier *l = b; 695*81cf8742SDavid du Colombier l = &b->sort; 696*81cf8742SDavid du Colombier b = b->sort; 697*81cf8742SDavid du Colombier } 698*81cf8742SDavid du Colombier } 699*81cf8742SDavid du Colombier *l = 0; 700*81cf8742SDavid du Colombier return s; 701*81cf8742SDavid du Colombier } 702*81cf8742SDavid du Colombier 703*81cf8742SDavid du Colombier static Fid* 704*81cf8742SDavid du Colombier fidMergeSort(Fid *f) 705*81cf8742SDavid du Colombier { 706*81cf8742SDavid du Colombier int delay; 707*81cf8742SDavid du Colombier Fid *a, *b; 708*81cf8742SDavid du Colombier 709*81cf8742SDavid du Colombier if(f == nil) 710*81cf8742SDavid du Colombier return nil; 711*81cf8742SDavid du Colombier if(f->sort == nil) 712*81cf8742SDavid du Colombier return f; 713*81cf8742SDavid du Colombier 714*81cf8742SDavid du Colombier a = b = f; 715*81cf8742SDavid du Colombier delay = 1; 716*81cf8742SDavid du Colombier while(a && b){ 717*81cf8742SDavid du Colombier if(delay) /* easy way to handle 2-element list */ 718*81cf8742SDavid du Colombier delay = 0; 719*81cf8742SDavid du Colombier else 720*81cf8742SDavid du Colombier a = a->sort; 721*81cf8742SDavid du Colombier if(b = b->sort) 722*81cf8742SDavid du Colombier b = b->sort; 723*81cf8742SDavid du Colombier } 724*81cf8742SDavid du Colombier 725*81cf8742SDavid du Colombier b = a->sort; 726*81cf8742SDavid du Colombier a->sort = nil; 727*81cf8742SDavid du Colombier 728*81cf8742SDavid du Colombier a = fidMergeSort(f); 729*81cf8742SDavid du Colombier b = fidMergeSort(b); 730*81cf8742SDavid du Colombier 731*81cf8742SDavid du Colombier return fidMerge(a, b); 732*81cf8742SDavid du Colombier } 733*81cf8742SDavid du Colombier 734*81cf8742SDavid du Colombier 735*81cf8742SDavid du Colombier static int 736*81cf8742SDavid du Colombier cmdWho(int argc, char* argv[]) 737*81cf8742SDavid du Colombier { 738*81cf8742SDavid du Colombier char *usage = "usage: who"; 739*81cf8742SDavid du Colombier int i; 740*81cf8742SDavid du Colombier Con *con; 741*81cf8742SDavid du Colombier Fid *fid, *last; 742*81cf8742SDavid du Colombier 743*81cf8742SDavid du Colombier ARGBEGIN{ 744*81cf8742SDavid du Colombier default: 745*81cf8742SDavid du Colombier return cliError(usage); 746*81cf8742SDavid du Colombier }ARGEND 747*81cf8742SDavid du Colombier 748*81cf8742SDavid du Colombier if(argc > 0) 749*81cf8742SDavid du Colombier return cliError(usage); 750*81cf8742SDavid du Colombier 751*81cf8742SDavid du Colombier vtRLock(cbox.clock); 752*81cf8742SDavid du Colombier for(con=cbox.chead; con; con=con->cnext){ 753*81cf8742SDavid du Colombier consPrint("\t%q:", con->name); 754*81cf8742SDavid du Colombier vtLock(con->fidlock); 755*81cf8742SDavid du Colombier last = nil; 756*81cf8742SDavid du Colombier for(i=0; i<NFidHash; i++) 757*81cf8742SDavid du Colombier for(fid=con->fidhash[i]; fid; fid=fid->hash) 758*81cf8742SDavid du Colombier if(fid->fidno != NOFID && fid->uname){ 759*81cf8742SDavid du Colombier fid->sort = last; 760*81cf8742SDavid du Colombier last = fid; 761*81cf8742SDavid du Colombier } 762*81cf8742SDavid du Colombier fid = fidMergeSort(last); 763*81cf8742SDavid du Colombier last = nil; 764*81cf8742SDavid du Colombier for(; fid; last=fid, fid=fid->sort) 765*81cf8742SDavid du Colombier if(last==nil || strcmp(fid->uname, last->uname) != 0) 766*81cf8742SDavid du Colombier consPrint(" %q", fid->uname); 767*81cf8742SDavid du Colombier vtUnlock(con->fidlock); 768*81cf8742SDavid du Colombier consPrint("\n"); 769*81cf8742SDavid du Colombier } 770*81cf8742SDavid du Colombier vtRUnlock(cbox.clock); 771*81cf8742SDavid du Colombier return 1; 772*81cf8742SDavid du Colombier } 773*81cf8742SDavid du Colombier 7745e96a66cSDavid du Colombier void 77534e04225SDavid du Colombier msgInit(void) 7765e96a66cSDavid du Colombier { 77734e04225SDavid du Colombier mbox.alock = vtLockAlloc(); 77834e04225SDavid du Colombier mbox.arendez = vtRendezAlloc(mbox.alock); 77934e04225SDavid du Colombier 78034e04225SDavid du Colombier mbox.rlock = vtLockAlloc(); 78134e04225SDavid du Colombier mbox.rrendez = vtRendezAlloc(mbox.rlock); 7825e96a66cSDavid du Colombier 7835e96a66cSDavid du Colombier mbox.maxmsg = NMsgInit; 7845e96a66cSDavid du Colombier mbox.maxproc = NMsgProcInit; 7855e96a66cSDavid du Colombier mbox.msize = NMsizeInit; 7865e96a66cSDavid du Colombier 7875e96a66cSDavid du Colombier cliAddCmd("msg", cmdMsg); 78834e04225SDavid du Colombier } 7895e96a66cSDavid du Colombier 79034e04225SDavid du Colombier static int 79134e04225SDavid du Colombier cmdCon(int argc, char* argv[]) 79234e04225SDavid du Colombier { 79334e04225SDavid du Colombier char *p; 79434e04225SDavid du Colombier Con *con; 79534e04225SDavid du Colombier char *usage = "usage: con [-m ncon]"; 79634e04225SDavid du Colombier int maxcon, ncon, nconstarve; 79734e04225SDavid du Colombier 79834e04225SDavid du Colombier maxcon = 0; 79934e04225SDavid du Colombier 80034e04225SDavid du Colombier ARGBEGIN{ 80134e04225SDavid du Colombier default: 80234e04225SDavid du Colombier return cliError(usage); 80334e04225SDavid du Colombier case 'm': 80434e04225SDavid du Colombier p = ARGF(); 80534e04225SDavid du Colombier if(p == nil) 80634e04225SDavid du Colombier return cliError(usage); 80734e04225SDavid du Colombier maxcon = strtol(argv[0], &p, 0); 80834e04225SDavid du Colombier if(maxcon <= 0 || p == argv[0] || *p != '\0') 80934e04225SDavid du Colombier return cliError(usage); 81034e04225SDavid du Colombier break; 81134e04225SDavid du Colombier }ARGEND 81234e04225SDavid du Colombier if(argc) 81334e04225SDavid du Colombier return cliError(usage); 81434e04225SDavid du Colombier 81534e04225SDavid du Colombier vtLock(cbox.clock); 81634e04225SDavid du Colombier if(maxcon) 81734e04225SDavid du Colombier cbox.maxcon = maxcon; 81834e04225SDavid du Colombier maxcon = cbox.maxcon; 81934e04225SDavid du Colombier ncon = cbox.ncon; 82034e04225SDavid du Colombier nconstarve = cbox.nconstarve; 82134e04225SDavid du Colombier vtUnlock(cbox.clock); 82234e04225SDavid du Colombier 82334e04225SDavid du Colombier consPrint("\tcon -m %d\n", maxcon); 82434e04225SDavid du Colombier consPrint("\tncon %d nconstarve %d\n", ncon, nconstarve); 82534e04225SDavid du Colombier 82634e04225SDavid du Colombier vtRLock(cbox.clock); 82734e04225SDavid du Colombier for(con = cbox.chead; con != nil; con = con->cnext){ 82834e04225SDavid du Colombier consPrint("\t%s\n", con->name); 82934e04225SDavid du Colombier } 83034e04225SDavid du Colombier vtRUnlock(cbox.clock); 83134e04225SDavid du Colombier 83234e04225SDavid du Colombier return 1; 83334e04225SDavid du Colombier } 83434e04225SDavid du Colombier 83534e04225SDavid du Colombier void 83634e04225SDavid du Colombier conInit(void) 83734e04225SDavid du Colombier { 83834e04225SDavid du Colombier cbox.alock = vtLockAlloc(); 83934e04225SDavid du Colombier cbox.arendez = vtRendezAlloc(cbox.alock); 84034e04225SDavid du Colombier 84134e04225SDavid du Colombier cbox.clock = vtLockAlloc(); 84234e04225SDavid du Colombier 84334e04225SDavid du Colombier cbox.maxcon = NConInit; 8445e96a66cSDavid du Colombier cbox.msize = NMsizeInit; 84534e04225SDavid du Colombier 84634e04225SDavid du Colombier cliAddCmd("con", cmdCon); 847*81cf8742SDavid du Colombier cliAddCmd("who", cmdWho); 8485e96a66cSDavid du Colombier } 849