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, 9fe853e23SDavid du Colombier NMsgInit = 384, 10fe853e23SDavid du Colombier NMsgProcInit = 64, 115e96a66cSDavid du Colombier NMsizeInit = 8192+IOHDRSZ, 125e96a66cSDavid du Colombier }; 135e96a66cSDavid du Colombier 145e96a66cSDavid du Colombier static struct { 15*d7aba6c3SDavid du Colombier QLock alock; /* alloc */ 1634e04225SDavid du Colombier Msg* ahead; 17*d7aba6c3SDavid du Colombier Rendez arendez; 185e96a66cSDavid du Colombier 195e96a66cSDavid du Colombier int maxmsg; 205e96a66cSDavid du Colombier int nmsg; 2134e04225SDavid du Colombier int nmsgstarve; 2234e04225SDavid du Colombier 23*d7aba6c3SDavid du Colombier QLock rlock; /* read */ 2434e04225SDavid du Colombier Msg* rhead; 2534e04225SDavid du Colombier Msg* rtail; 26*d7aba6c3SDavid du Colombier Rendez 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 { 36*d7aba6c3SDavid du Colombier QLock alock; /* alloc */ 3734e04225SDavid du Colombier Con* ahead; 38*d7aba6c3SDavid du Colombier Rendez arendez; 3934e04225SDavid du Colombier 40*d7aba6c3SDavid du Colombier RWLock 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; 655316891fSDavid du Colombier con->aok = 0; 662cca75a1SDavid du Colombier con->flags = 0; 675316891fSDavid du Colombier con->isconsole = 0; 685e96a66cSDavid du Colombier 69*d7aba6c3SDavid du Colombier qlock(&cbox.alock); 7034e04225SDavid du Colombier if(con->cprev != nil) 7134e04225SDavid du Colombier con->cprev->cnext = con->cnext; 7234e04225SDavid du Colombier else 7334e04225SDavid du Colombier cbox.chead = con->cnext; 7434e04225SDavid du Colombier if(con->cnext != nil) 7534e04225SDavid du Colombier con->cnext->cprev = con->cprev; 7634e04225SDavid du Colombier else 7734e04225SDavid du Colombier cbox.ctail = con->cprev; 7834e04225SDavid du Colombier con->cprev = con->cnext = nil; 795e96a66cSDavid du Colombier 8034e04225SDavid du Colombier if(cbox.ncon > cbox.maxcon){ 8134e04225SDavid du Colombier if(con->name != nil) 82*d7aba6c3SDavid du Colombier vtfree(con->name); 83*d7aba6c3SDavid du Colombier vtfree(con->data); 84*d7aba6c3SDavid du Colombier vtfree(con); 8534e04225SDavid du Colombier cbox.ncon--; 86*d7aba6c3SDavid du Colombier qunlock(&cbox.alock); 8734e04225SDavid du Colombier return; 8834e04225SDavid du Colombier } 8934e04225SDavid du Colombier con->anext = cbox.ahead; 9034e04225SDavid du Colombier cbox.ahead = con; 9134e04225SDavid du Colombier if(con->anext == nil) 92*d7aba6c3SDavid du Colombier rwakeup(&cbox.arendez); 93*d7aba6c3SDavid du Colombier qunlock(&cbox.alock); 9434e04225SDavid du Colombier } 9534e04225SDavid du Colombier 9634e04225SDavid du Colombier static void 9734e04225SDavid du Colombier msgFree(Msg* m) 9834e04225SDavid du Colombier { 9934e04225SDavid du Colombier assert(m->rwnext == nil); 1007f1bc48aSDavid du Colombier assert(m->flush == nil); 10134e04225SDavid du Colombier 102*d7aba6c3SDavid du Colombier qlock(&mbox.alock); 10334e04225SDavid du Colombier if(mbox.nmsg > mbox.maxmsg){ 104*d7aba6c3SDavid du Colombier vtfree(m->data); 105*d7aba6c3SDavid du Colombier vtfree(m); 10634e04225SDavid du Colombier mbox.nmsg--; 107*d7aba6c3SDavid du Colombier qunlock(&mbox.alock); 10834e04225SDavid du Colombier return; 10934e04225SDavid du Colombier } 11034e04225SDavid du Colombier m->anext = mbox.ahead; 11134e04225SDavid du Colombier mbox.ahead = m; 11234e04225SDavid du Colombier if(m->anext == nil) 113*d7aba6c3SDavid du Colombier rwakeup(&mbox.arendez); 114*d7aba6c3SDavid du Colombier qunlock(&mbox.alock); 11534e04225SDavid du Colombier } 11634e04225SDavid du Colombier 11734e04225SDavid du Colombier static Msg* 11834e04225SDavid du Colombier msgAlloc(Con* con) 11934e04225SDavid du Colombier { 12034e04225SDavid du Colombier Msg *m; 12134e04225SDavid du Colombier 122*d7aba6c3SDavid du Colombier qlock(&mbox.alock); 12334e04225SDavid du Colombier while(mbox.ahead == nil){ 12434e04225SDavid du Colombier if(mbox.nmsg >= mbox.maxmsg){ 12534e04225SDavid du Colombier mbox.nmsgstarve++; 126*d7aba6c3SDavid du Colombier rsleep(&mbox.arendez); 12734e04225SDavid du Colombier continue; 12834e04225SDavid du Colombier } 129*d7aba6c3SDavid du Colombier m = vtmallocz(sizeof(Msg)); 130*d7aba6c3SDavid du Colombier m->data = vtmalloc(mbox.msize); 13134e04225SDavid du Colombier m->msize = mbox.msize; 13234e04225SDavid du Colombier mbox.nmsg++; 13334e04225SDavid du Colombier mbox.ahead = m; 13434e04225SDavid du Colombier break; 13534e04225SDavid du Colombier } 13634e04225SDavid du Colombier m = mbox.ahead; 13734e04225SDavid du Colombier mbox.ahead = m->anext; 13834e04225SDavid du Colombier m->anext = nil; 139*d7aba6c3SDavid du Colombier qunlock(&mbox.alock); 14034e04225SDavid du Colombier 14134e04225SDavid du Colombier m->con = con; 14234e04225SDavid du Colombier m->state = MsgR; 1437f1bc48aSDavid du Colombier m->nowq = 0; 14434e04225SDavid du Colombier 14534e04225SDavid du Colombier return m; 14634e04225SDavid du Colombier } 14734e04225SDavid du Colombier 14834e04225SDavid du Colombier static void 14934e04225SDavid du Colombier msgMunlink(Msg* m) 15034e04225SDavid du Colombier { 15134e04225SDavid du Colombier Con *con; 15234e04225SDavid du Colombier 15334e04225SDavid du Colombier con = m->con; 15434e04225SDavid du Colombier 15534e04225SDavid du Colombier if(m->mprev != nil) 15634e04225SDavid du Colombier m->mprev->mnext = m->mnext; 15734e04225SDavid du Colombier else 15834e04225SDavid du Colombier con->mhead = m->mnext; 15934e04225SDavid du Colombier if(m->mnext != nil) 16034e04225SDavid du Colombier m->mnext->mprev = m->mprev; 16134e04225SDavid du Colombier else 16234e04225SDavid du Colombier con->mtail = m->mprev; 16334e04225SDavid du Colombier m->mprev = m->mnext = nil; 16434e04225SDavid du Colombier } 16534e04225SDavid du Colombier 16634e04225SDavid du Colombier void 16734e04225SDavid du Colombier msgFlush(Msg* m) 16834e04225SDavid du Colombier { 16934e04225SDavid du Colombier Con *con; 1707f1bc48aSDavid du Colombier Msg *flush, *old; 17134e04225SDavid du Colombier 17234e04225SDavid du Colombier con = m->con; 17334e04225SDavid du Colombier 17428495efeSDavid du Colombier if(Dflag) 17539734e7eSDavid du Colombier fprint(2, "msgFlush %F\n", &m->t); 17639734e7eSDavid du Colombier 17734e04225SDavid du Colombier /* 17828495efeSDavid du Colombier * If this Tflush has been flushed, nothing to do. 17934e04225SDavid du Colombier * Look for the message to be flushed in the 18034e04225SDavid du Colombier * queue of all messages still on this connection. 18128495efeSDavid du Colombier * If it's not found must assume Elvis has already 18228495efeSDavid du Colombier * left the building and reply normally. 18334e04225SDavid du Colombier */ 184*d7aba6c3SDavid du Colombier qlock(&con->mlock); 18528495efeSDavid du Colombier if(m->state == MsgF){ 186*d7aba6c3SDavid du Colombier qunlock(&con->mlock); 18728495efeSDavid du Colombier return; 18828495efeSDavid du Colombier } 18934e04225SDavid du Colombier for(old = con->mhead; old != nil; old = old->mnext) 19034e04225SDavid du Colombier if(old->t.tag == m->t.oldtag) 19134e04225SDavid du Colombier break; 19234e04225SDavid du Colombier if(old == nil){ 19334e04225SDavid du Colombier if(Dflag) 19434e04225SDavid du Colombier fprint(2, "msgFlush: cannot find %d\n", m->t.oldtag); 195*d7aba6c3SDavid du Colombier qunlock(&con->mlock); 19634e04225SDavid du Colombier return; 19734e04225SDavid du Colombier } 19834e04225SDavid du Colombier 19928495efeSDavid du Colombier if(Dflag) 20039734e7eSDavid du Colombier fprint(2, "\tmsgFlush found %F\n", &old->t); 20139734e7eSDavid du Colombier 20234e04225SDavid du Colombier /* 20334e04225SDavid du Colombier * Found it. 20428495efeSDavid du Colombier * There are two cases where the old message can be 20528495efeSDavid du Colombier * truly flushed and no reply to the original message given. 20628495efeSDavid du Colombier * The first is when the old message is in MsgR state; no 20728495efeSDavid du Colombier * processing has been done yet and it is still on the read 20828495efeSDavid du Colombier * queue. The second is if old is a Tflush, which doesn't 20928495efeSDavid du Colombier * affect the server state. In both cases, put the old 2107f1bc48aSDavid du Colombier * message into MsgF state and let MsgWrite toss it after 2117f1bc48aSDavid du Colombier * pulling it off the queue. 21234e04225SDavid du Colombier */ 21328495efeSDavid du Colombier if(old->state == MsgR || old->t.type == Tflush){ 21434e04225SDavid du Colombier old->state = MsgF; 21534e04225SDavid du Colombier if(Dflag) 21628495efeSDavid du Colombier fprint(2, "msgFlush: change %d from MsgR to MsgF\n", 21728495efeSDavid du Colombier m->t.oldtag); 21834e04225SDavid du Colombier } 21934e04225SDavid du Colombier 22034e04225SDavid du Colombier /* 22128495efeSDavid du Colombier * Link this flush message and the old message 2227f1bc48aSDavid du Colombier * so multiple flushes can be coalesced (if there are 22328495efeSDavid du Colombier * multiple Tflush messages for a particular pending 22428495efeSDavid du Colombier * request, it is only necessary to respond to the last 22528495efeSDavid du Colombier * one, so any previous can be removed) and to be 22628495efeSDavid du Colombier * sure flushes wait for their corresponding old 22728495efeSDavid du Colombier * message to go out first. 2287f1bc48aSDavid du Colombier * Waiting flush messages do not go on the write queue, 2297f1bc48aSDavid du Colombier * they are processed after the old message is dealt 2307f1bc48aSDavid du Colombier * with. There's no real need to protect the setting of 2317f1bc48aSDavid du Colombier * Msg.nowq, the only code to check it runs in this 2327f1bc48aSDavid du Colombier * process after this routine returns. 23334e04225SDavid du Colombier */ 2347f1bc48aSDavid du Colombier if((flush = old->flush) != nil){ 23534e04225SDavid du Colombier if(Dflag) 23628495efeSDavid du Colombier fprint(2, "msgFlush: remove %d from %d list\n", 2377f1bc48aSDavid du Colombier old->flush->t.tag, old->t.tag); 2387f1bc48aSDavid du Colombier m->flush = flush->flush; 2397f1bc48aSDavid du Colombier flush->flush = nil; 2407f1bc48aSDavid du Colombier msgMunlink(flush); 2417f1bc48aSDavid du Colombier msgFree(flush); 24234e04225SDavid du Colombier } 2437f1bc48aSDavid du Colombier old->flush = m; 2447f1bc48aSDavid du Colombier m->nowq = 1; 24534e04225SDavid du Colombier 24634e04225SDavid du Colombier if(Dflag) 24728495efeSDavid du Colombier fprint(2, "msgFlush: add %d to %d queue\n", 24828495efeSDavid du Colombier m->t.tag, old->t.tag); 249*d7aba6c3SDavid du Colombier qunlock(&con->mlock); 2505e96a66cSDavid du Colombier } 2515e96a66cSDavid du Colombier 2525e96a66cSDavid du Colombier static void 2535e96a66cSDavid du Colombier msgProc(void*) 2545e96a66cSDavid du Colombier { 2555e96a66cSDavid du Colombier Msg *m; 256*d7aba6c3SDavid du Colombier char e[ERRMAX]; 2575e96a66cSDavid du Colombier Con *con; 2585e96a66cSDavid du Colombier 259*d7aba6c3SDavid du Colombier threadsetname("msgProc"); 2605e96a66cSDavid du Colombier 26134e04225SDavid du Colombier for(;;){ 26234e04225SDavid du Colombier /* 26334e04225SDavid du Colombier * If surplus to requirements, exit. 26434e04225SDavid du Colombier * If not, wait for and pull a message off 26534e04225SDavid du Colombier * the read queue. 26634e04225SDavid du Colombier */ 267*d7aba6c3SDavid du Colombier qlock(&mbox.rlock); 26834e04225SDavid du Colombier if(mbox.nproc > mbox.maxproc){ 26934e04225SDavid du Colombier mbox.nproc--; 270*d7aba6c3SDavid du Colombier qunlock(&mbox.rlock); 27134e04225SDavid du Colombier break; 27234e04225SDavid du Colombier } 27334e04225SDavid du Colombier while(mbox.rhead == nil) 274*d7aba6c3SDavid du Colombier rsleep(&mbox.rrendez); 27534e04225SDavid du Colombier m = mbox.rhead; 27634e04225SDavid du Colombier mbox.rhead = m->rwnext; 27734e04225SDavid du Colombier m->rwnext = nil; 278*d7aba6c3SDavid du Colombier qunlock(&mbox.rlock); 2795e96a66cSDavid du Colombier 2805e96a66cSDavid du Colombier con = m->con; 281*d7aba6c3SDavid du Colombier *e = 0; 2825e96a66cSDavid du Colombier 28334e04225SDavid du Colombier /* 28428495efeSDavid du Colombier * If the message has been flushed before 28528495efeSDavid du Colombier * any 9P processing has started, mark it so 28628495efeSDavid du Colombier * none will be attempted. 28734e04225SDavid du Colombier */ 288*d7aba6c3SDavid du Colombier qlock(&con->mlock); 28928495efeSDavid du Colombier if(m->state == MsgF) 290*d7aba6c3SDavid du Colombier strcpy(e, "flushed"); 29128495efeSDavid du Colombier else 29234e04225SDavid du Colombier m->state = Msg9; 293*d7aba6c3SDavid du Colombier qunlock(&con->mlock); 29434e04225SDavid du Colombier 295*d7aba6c3SDavid du Colombier if(*e == 0){ 29634e04225SDavid du Colombier /* 29734e04225SDavid du Colombier * explain this 29834e04225SDavid du Colombier */ 299*d7aba6c3SDavid du Colombier qlock(&con->lock); 3005e96a66cSDavid du Colombier if(m->t.type == Tversion){ 3015e96a66cSDavid du Colombier con->version = m; 30234e04225SDavid du Colombier con->state = ConDown; 30334e04225SDavid du Colombier while(con->mhead != m) 304*d7aba6c3SDavid du Colombier rsleep(&con->rendez); 30534e04225SDavid du Colombier assert(con->state == ConDown); 3065e96a66cSDavid du Colombier if(con->version == m){ 3075e96a66cSDavid du Colombier con->version = nil; 30834e04225SDavid du Colombier con->state = ConInit; 3095e96a66cSDavid du Colombier } 3105e96a66cSDavid du Colombier else 311*d7aba6c3SDavid du Colombier strcpy(e, "Tversion aborted"); 3125e96a66cSDavid du Colombier } 31334e04225SDavid du Colombier else if(con->state != ConUp) 314*d7aba6c3SDavid du Colombier strcpy(e, "connection not ready"); 315*d7aba6c3SDavid du Colombier qunlock(&con->lock); 31628495efeSDavid du Colombier } 3175e96a66cSDavid du Colombier 3185e96a66cSDavid du Colombier /* 3195e96a66cSDavid du Colombier * Dispatch if not error already. 3205e96a66cSDavid du Colombier */ 3215e96a66cSDavid du Colombier m->r.tag = m->t.tag; 322*d7aba6c3SDavid du Colombier if(*e == 0 && !(*rFcall[m->t.type])(m)) 323*d7aba6c3SDavid du Colombier rerrstr(e, sizeof e); 324*d7aba6c3SDavid du Colombier if(*e != 0){ 3255e96a66cSDavid du Colombier m->r.type = Rerror; 3265e96a66cSDavid du Colombier m->r.ename = e; 3275e96a66cSDavid du Colombier } 3285e96a66cSDavid du Colombier else 3295e96a66cSDavid du Colombier m->r.type = m->t.type+1; 3305e96a66cSDavid du Colombier 3315e96a66cSDavid du Colombier /* 33234e04225SDavid du Colombier * Put the message (with reply) on the 33334e04225SDavid du Colombier * write queue and wakeup the write process. 3345e96a66cSDavid du Colombier */ 3357f1bc48aSDavid du Colombier if(!m->nowq){ 336*d7aba6c3SDavid du Colombier qlock(&con->wlock); 33734e04225SDavid du Colombier if(con->whead == nil) 33834e04225SDavid du Colombier con->whead = m; 3395e96a66cSDavid du Colombier else 34034e04225SDavid du Colombier con->wtail->rwnext = m; 34134e04225SDavid du Colombier con->wtail = m; 342*d7aba6c3SDavid du Colombier rwakeup(&con->wrendez); 343*d7aba6c3SDavid du Colombier qunlock(&con->wlock); 3445e96a66cSDavid du Colombier } 3455e96a66cSDavid du Colombier } 3467f1bc48aSDavid du Colombier } 3475e96a66cSDavid du Colombier 3485e96a66cSDavid du Colombier static void 34934e04225SDavid du Colombier msgRead(void* v) 3505e96a66cSDavid du Colombier { 3515e96a66cSDavid du Colombier Msg *m; 3525e96a66cSDavid du Colombier Con *con; 3535e96a66cSDavid du Colombier int eof, fd, n; 3545e96a66cSDavid du Colombier 355*d7aba6c3SDavid du Colombier threadsetname("msgRead"); 3565e96a66cSDavid du Colombier 3575e96a66cSDavid du Colombier con = v; 3585e96a66cSDavid du Colombier fd = con->fd; 3595e96a66cSDavid du Colombier eof = 0; 3605e96a66cSDavid du Colombier 3615e96a66cSDavid du Colombier while(!eof){ 36234e04225SDavid du Colombier m = msgAlloc(con); 3635e96a66cSDavid du Colombier 3645e96a66cSDavid du Colombier while((n = read9pmsg(fd, m->data, con->msize)) == 0) 3655e96a66cSDavid du Colombier ; 3665e96a66cSDavid du Colombier if(n < 0){ 3675e96a66cSDavid du Colombier m->t.type = Tversion; 3685e96a66cSDavid du Colombier m->t.fid = NOFID; 3695e96a66cSDavid du Colombier m->t.tag = NOTAG; 3705e96a66cSDavid du Colombier m->t.msize = con->msize; 3715e96a66cSDavid du Colombier m->t.version = "9PEoF"; 3725e96a66cSDavid du Colombier eof = 1; 3735e96a66cSDavid du Colombier } 3745e96a66cSDavid du Colombier else if(convM2S(m->data, n, &m->t) != n){ 3755e96a66cSDavid du Colombier if(Dflag) 37634e04225SDavid du Colombier fprint(2, "msgRead: convM2S error: %s\n", 3775e96a66cSDavid du Colombier con->name); 3785e96a66cSDavid du Colombier msgFree(m); 3795e96a66cSDavid du Colombier continue; 3805e96a66cSDavid du Colombier } 3815e96a66cSDavid du Colombier if(Dflag) 38239734e7eSDavid du Colombier fprint(2, "msgRead %p: t %F\n", con, &m->t); 3835e96a66cSDavid du Colombier 384*d7aba6c3SDavid du Colombier qlock(&con->mlock); 38534e04225SDavid du Colombier if(con->mtail != nil){ 38634e04225SDavid du Colombier m->mprev = con->mtail; 38734e04225SDavid du Colombier con->mtail->mnext = m; 38834e04225SDavid du Colombier } 38934e04225SDavid du Colombier else{ 39034e04225SDavid du Colombier con->mhead = m; 39134e04225SDavid du Colombier m->mprev = nil; 39234e04225SDavid du Colombier } 39334e04225SDavid du Colombier con->mtail = m; 394*d7aba6c3SDavid du Colombier qunlock(&con->mlock); 39534e04225SDavid du Colombier 396*d7aba6c3SDavid du Colombier qlock(&mbox.rlock); 39734e04225SDavid du Colombier if(mbox.rhead == nil){ 39834e04225SDavid du Colombier mbox.rhead = m; 399*d7aba6c3SDavid du Colombier if(!rwakeup(&mbox.rrendez)){ 40034e04225SDavid du Colombier if(mbox.nproc < mbox.maxproc){ 401*d7aba6c3SDavid du Colombier if(proccreate(msgProc, nil, STACK) > 0) 4025e96a66cSDavid du Colombier mbox.nproc++; 4035e96a66cSDavid du Colombier } 40434e04225SDavid du Colombier else 40534e04225SDavid du Colombier mbox.nprocstarve++; 40634e04225SDavid du Colombier } 40734e04225SDavid du Colombier /* 40834e04225SDavid du Colombier * don't need this surely? 409*d7aba6c3SDavid du Colombier rwakeup(&mbox.rrendez); 41034e04225SDavid du Colombier */ 4115e96a66cSDavid du Colombier } 4125e96a66cSDavid du Colombier else 41334e04225SDavid du Colombier mbox.rtail->rwnext = m; 41434e04225SDavid du Colombier mbox.rtail = m; 415*d7aba6c3SDavid du Colombier qunlock(&mbox.rlock); 4165e96a66cSDavid du Colombier } 41734e04225SDavid du Colombier } 41834e04225SDavid du Colombier 41934e04225SDavid du Colombier static void 42034e04225SDavid du Colombier msgWrite(void* v) 42134e04225SDavid du Colombier { 42234e04225SDavid du Colombier Con *con; 4237f1bc48aSDavid du Colombier int eof, n; 4247f1bc48aSDavid du Colombier Msg *flush, *m; 42534e04225SDavid du Colombier 426*d7aba6c3SDavid du Colombier threadsetname("msgWrite"); 42734e04225SDavid du Colombier 42834e04225SDavid du Colombier con = v; 429*d7aba6c3SDavid du Colombier if(proccreate(msgRead, con, STACK) < 0){ 43034e04225SDavid du Colombier conFree(con); 43134e04225SDavid du Colombier return; 43234e04225SDavid du Colombier } 43334e04225SDavid du Colombier 43434e04225SDavid du Colombier for(;;){ 43534e04225SDavid du Colombier /* 43634e04225SDavid du Colombier * Wait for and pull a message off the write queue. 43734e04225SDavid du Colombier */ 438*d7aba6c3SDavid du Colombier qlock(&con->wlock); 43934e04225SDavid du Colombier while(con->whead == nil) 440*d7aba6c3SDavid du Colombier rsleep(&con->wrendez); 44134e04225SDavid du Colombier m = con->whead; 44234e04225SDavid du Colombier con->whead = m->rwnext; 44334e04225SDavid du Colombier m->rwnext = nil; 4447f1bc48aSDavid du Colombier assert(!m->nowq); 445*d7aba6c3SDavid du Colombier qunlock(&con->wlock); 44634e04225SDavid du Colombier 4477f1bc48aSDavid du Colombier eof = 0; 4487f1bc48aSDavid du Colombier 44934e04225SDavid du Colombier /* 4507f1bc48aSDavid du Colombier * Write each message (if it hasn't been flushed) 4517f1bc48aSDavid du Colombier * followed by any messages waiting for it to complete. 45234e04225SDavid du Colombier */ 453*d7aba6c3SDavid du Colombier qlock(&con->mlock); 4547f1bc48aSDavid du Colombier while(m != nil){ 4557f1bc48aSDavid du Colombier msgMunlink(m); 4567f1bc48aSDavid du Colombier 4577f1bc48aSDavid du Colombier if(Dflag) 4587f1bc48aSDavid du Colombier fprint(2, "msgWrite %d: r %F\n", 4597f1bc48aSDavid du Colombier m->state, &m->r); 4607f1bc48aSDavid du Colombier 4617f1bc48aSDavid du Colombier if(m->state != MsgF){ 46234e04225SDavid du Colombier m->state = MsgW; 463*d7aba6c3SDavid du Colombier qunlock(&con->mlock); 4647f1bc48aSDavid du Colombier 4657f1bc48aSDavid du Colombier n = convS2M(&m->r, con->data, con->msize); 4667f1bc48aSDavid du Colombier if(write(con->fd, con->data, n) != n) 4677f1bc48aSDavid du Colombier eof = 1; 4687f1bc48aSDavid du Colombier 469*d7aba6c3SDavid du Colombier qlock(&con->mlock); 4707f1bc48aSDavid du Colombier } 4717f1bc48aSDavid du Colombier 4727f1bc48aSDavid du Colombier if((flush = m->flush) != nil){ 4737f1bc48aSDavid du Colombier assert(flush->nowq); 4747f1bc48aSDavid du Colombier m->flush = nil; 4757f1bc48aSDavid du Colombier } 4767f1bc48aSDavid du Colombier msgFree(m); 4777f1bc48aSDavid du Colombier m = flush; 4787f1bc48aSDavid du Colombier } 479*d7aba6c3SDavid du Colombier qunlock(&con->mlock); 48034e04225SDavid du Colombier 481*d7aba6c3SDavid du Colombier qlock(&con->lock); 48234e04225SDavid du Colombier if(eof && con->fd >= 0){ 48334e04225SDavid du Colombier close(con->fd); 48434e04225SDavid du Colombier con->fd = -1; 48534e04225SDavid du Colombier } 48634e04225SDavid du Colombier if(con->state == ConDown) 487*d7aba6c3SDavid du Colombier rwakeup(&con->rendez); 48834e04225SDavid du Colombier if(con->state == ConMoribund && con->mhead == nil){ 489*d7aba6c3SDavid du Colombier qunlock(&con->lock); 49034e04225SDavid du Colombier conFree(con); 49134e04225SDavid du Colombier break; 49234e04225SDavid du Colombier } 493*d7aba6c3SDavid du Colombier qunlock(&con->lock); 49434e04225SDavid du Colombier } 4955e96a66cSDavid du Colombier } 4965e96a66cSDavid du Colombier 4975e96a66cSDavid du Colombier Con* 4982cca75a1SDavid du Colombier conAlloc(int fd, char* name, int flags) 4995e96a66cSDavid du Colombier { 5005e96a66cSDavid du Colombier Con *con; 5012cca75a1SDavid du Colombier char buf[128], *p; 5022cca75a1SDavid du Colombier int rfd, n; 5035e96a66cSDavid du Colombier 504*d7aba6c3SDavid du Colombier qlock(&cbox.alock); 50534e04225SDavid du Colombier while(cbox.ahead == nil){ 50634e04225SDavid du Colombier if(cbox.ncon >= cbox.maxcon){ 50734e04225SDavid du Colombier cbox.nconstarve++; 508*d7aba6c3SDavid du Colombier rsleep(&cbox.arendez); 50934e04225SDavid du Colombier continue; 5105e96a66cSDavid du Colombier } 511*d7aba6c3SDavid du Colombier con = vtmallocz(sizeof(Con)); 512*d7aba6c3SDavid du Colombier con->rendez.l = &con->lock; 513*d7aba6c3SDavid du Colombier con->data = vtmalloc(cbox.msize); 5145e96a66cSDavid du Colombier con->msize = cbox.msize; 515*d7aba6c3SDavid du Colombier con->mrendez.l = &con->mlock; 516*d7aba6c3SDavid du Colombier con->wrendez.l = &con->wlock; 51734e04225SDavid du Colombier 51834e04225SDavid du Colombier cbox.ncon++; 51934e04225SDavid du Colombier cbox.ahead = con; 52034e04225SDavid du Colombier break; 5215e96a66cSDavid du Colombier } 52234e04225SDavid du Colombier con = cbox.ahead; 52334e04225SDavid du Colombier cbox.ahead = con->anext; 52434e04225SDavid du Colombier con->anext = nil; 52534e04225SDavid du Colombier 52634e04225SDavid du Colombier if(cbox.ctail != nil){ 52734e04225SDavid du Colombier con->cprev = cbox.ctail; 52834e04225SDavid du Colombier cbox.ctail->cnext = con; 52934e04225SDavid du Colombier } 53034e04225SDavid du Colombier else{ 53134e04225SDavid du Colombier cbox.chead = con; 53234e04225SDavid du Colombier con->cprev = nil; 53334e04225SDavid du Colombier } 53434e04225SDavid du Colombier cbox.ctail = con; 53534e04225SDavid du Colombier 5365e96a66cSDavid du Colombier assert(con->mhead == nil); 53734e04225SDavid du Colombier assert(con->whead == nil); 5385e96a66cSDavid du Colombier assert(con->fhead == nil); 5395e96a66cSDavid du Colombier assert(con->nfid == 0); 5405e96a66cSDavid du Colombier 54134e04225SDavid du Colombier con->state = ConNew; 5425e96a66cSDavid du Colombier con->fd = fd; 5435e96a66cSDavid du Colombier if(con->name != nil){ 544*d7aba6c3SDavid du Colombier vtfree(con->name); 5455e96a66cSDavid du Colombier con->name = nil; 5465e96a66cSDavid du Colombier } 5475e96a66cSDavid du Colombier if(name != nil) 548*d7aba6c3SDavid du Colombier con->name = vtstrdup(name); 54934e04225SDavid du Colombier else 550*d7aba6c3SDavid du Colombier con->name = vtstrdup("unknown"); 5512cca75a1SDavid du Colombier con->remote[0] = 0; 5522cca75a1SDavid du Colombier snprint(buf, sizeof buf, "%s/remote", con->name); 5532cca75a1SDavid du Colombier if((rfd = open(buf, OREAD)) >= 0){ 5542cca75a1SDavid du Colombier n = read(rfd, buf, sizeof buf-1); 5552cca75a1SDavid du Colombier close(rfd); 5562cca75a1SDavid du Colombier if(n > 0){ 5572cca75a1SDavid du Colombier buf[n] = 0; 5582cca75a1SDavid du Colombier if((p = strchr(buf, '\n')) != nil) 5592cca75a1SDavid du Colombier *p = 0; 5602cca75a1SDavid du Colombier strecpy(con->remote, con->remote+sizeof con->remote, buf); 5612cca75a1SDavid du Colombier } 5622cca75a1SDavid du Colombier } 5632cca75a1SDavid du Colombier con->flags = flags; 5645316891fSDavid du Colombier con->isconsole = 0; 565*d7aba6c3SDavid du Colombier qunlock(&cbox.alock); 5665e96a66cSDavid du Colombier 567*d7aba6c3SDavid du Colombier if(proccreate(msgWrite, con, STACK) < 0){ 5685e96a66cSDavid du Colombier conFree(con); 5695e96a66cSDavid du Colombier return nil; 5705e96a66cSDavid du Colombier } 5715e96a66cSDavid du Colombier 5725e96a66cSDavid du Colombier return con; 5735e96a66cSDavid du Colombier } 5745e96a66cSDavid du Colombier 5755e96a66cSDavid du Colombier static int 5765e96a66cSDavid du Colombier cmdMsg(int argc, char* argv[]) 5775e96a66cSDavid du Colombier { 5785e96a66cSDavid du Colombier char *p; 5795e96a66cSDavid du Colombier char *usage = "usage: msg [-m nmsg] [-p nproc]"; 58034e04225SDavid du Colombier int maxmsg, nmsg, nmsgstarve, maxproc, nproc, nprocstarve; 5815e96a66cSDavid du Colombier 5825e96a66cSDavid du Colombier maxmsg = maxproc = 0; 5835e96a66cSDavid du Colombier 5845e96a66cSDavid du Colombier ARGBEGIN{ 5855e96a66cSDavid du Colombier default: 5865e96a66cSDavid du Colombier return cliError(usage); 5875e96a66cSDavid du Colombier case 'm': 5885e96a66cSDavid du Colombier p = ARGF(); 5895e96a66cSDavid du Colombier if(p == nil) 5905e96a66cSDavid du Colombier return cliError(usage); 5915e96a66cSDavid du Colombier maxmsg = strtol(argv[0], &p, 0); 5925e96a66cSDavid du Colombier if(maxmsg <= 0 || p == argv[0] || *p != '\0') 5935e96a66cSDavid du Colombier return cliError(usage); 5945e96a66cSDavid du Colombier break; 5955e96a66cSDavid du Colombier case 'p': 5965e96a66cSDavid du Colombier p = ARGF(); 5975e96a66cSDavid du Colombier if(p == nil) 5985e96a66cSDavid du Colombier return cliError(usage); 5995e96a66cSDavid du Colombier maxproc = strtol(argv[0], &p, 0); 6005e96a66cSDavid du Colombier if(maxproc <= 0 || p == argv[0] || *p != '\0') 6015e96a66cSDavid du Colombier return cliError(usage); 6025e96a66cSDavid du Colombier break; 6035e96a66cSDavid du Colombier }ARGEND 6045e96a66cSDavid du Colombier if(argc) 6055e96a66cSDavid du Colombier return cliError(usage); 6065e96a66cSDavid du Colombier 607*d7aba6c3SDavid du Colombier qlock(&mbox.alock); 6085e96a66cSDavid du Colombier if(maxmsg) 6095e96a66cSDavid du Colombier mbox.maxmsg = maxmsg; 6105e96a66cSDavid du Colombier maxmsg = mbox.maxmsg; 61134e04225SDavid du Colombier nmsg = mbox.nmsg; 61234e04225SDavid du Colombier nmsgstarve = mbox.nmsgstarve; 613*d7aba6c3SDavid du Colombier qunlock(&mbox.alock); 61434e04225SDavid du Colombier 615*d7aba6c3SDavid du Colombier qlock(&mbox.rlock); 6165e96a66cSDavid du Colombier if(maxproc) 6175e96a66cSDavid du Colombier mbox.maxproc = maxproc; 6185e96a66cSDavid du Colombier maxproc = mbox.maxproc; 61934e04225SDavid du Colombier nproc = mbox.nproc; 62034e04225SDavid du Colombier nprocstarve = mbox.nprocstarve; 621*d7aba6c3SDavid du Colombier qunlock(&mbox.rlock); 6225e96a66cSDavid du Colombier 6235e96a66cSDavid du Colombier consPrint("\tmsg -m %d -p %d\n", maxmsg, maxproc); 62434e04225SDavid du Colombier consPrint("\tnmsg %d nmsgstarve %d nproc %d nprocstarve %d\n", 62534e04225SDavid du Colombier nmsg, nmsgstarve, nproc, nprocstarve); 6265e96a66cSDavid du Colombier 6275e96a66cSDavid du Colombier return 1; 6285e96a66cSDavid du Colombier } 6295e96a66cSDavid du Colombier 63081cf8742SDavid du Colombier static int 63181cf8742SDavid du Colombier scmp(Fid *a, Fid *b) 63281cf8742SDavid du Colombier { 63381cf8742SDavid du Colombier if(a == 0) 63481cf8742SDavid du Colombier return 1; 63581cf8742SDavid du Colombier if(b == 0) 63681cf8742SDavid du Colombier return -1; 63781cf8742SDavid du Colombier return strcmp(a->uname, b->uname); 63881cf8742SDavid du Colombier } 63981cf8742SDavid du Colombier 64081cf8742SDavid du Colombier static Fid* 64181cf8742SDavid du Colombier fidMerge(Fid *a, Fid *b) 64281cf8742SDavid du Colombier { 64381cf8742SDavid du Colombier Fid *s, **l; 64481cf8742SDavid du Colombier 64581cf8742SDavid du Colombier l = &s; 64681cf8742SDavid du Colombier while(a || b){ 64781cf8742SDavid du Colombier if(scmp(a, b) < 0){ 64881cf8742SDavid du Colombier *l = a; 64981cf8742SDavid du Colombier l = &a->sort; 65081cf8742SDavid du Colombier a = a->sort; 65181cf8742SDavid du Colombier }else{ 65281cf8742SDavid du Colombier *l = b; 65381cf8742SDavid du Colombier l = &b->sort; 65481cf8742SDavid du Colombier b = b->sort; 65581cf8742SDavid du Colombier } 65681cf8742SDavid du Colombier } 65781cf8742SDavid du Colombier *l = 0; 65881cf8742SDavid du Colombier return s; 65981cf8742SDavid du Colombier } 66081cf8742SDavid du Colombier 66181cf8742SDavid du Colombier static Fid* 66281cf8742SDavid du Colombier fidMergeSort(Fid *f) 66381cf8742SDavid du Colombier { 66481cf8742SDavid du Colombier int delay; 66581cf8742SDavid du Colombier Fid *a, *b; 66681cf8742SDavid du Colombier 66781cf8742SDavid du Colombier if(f == nil) 66881cf8742SDavid du Colombier return nil; 66981cf8742SDavid du Colombier if(f->sort == nil) 67081cf8742SDavid du Colombier return f; 67181cf8742SDavid du Colombier 67281cf8742SDavid du Colombier a = b = f; 67381cf8742SDavid du Colombier delay = 1; 67481cf8742SDavid du Colombier while(a && b){ 67581cf8742SDavid du Colombier if(delay) /* easy way to handle 2-element list */ 67681cf8742SDavid du Colombier delay = 0; 67781cf8742SDavid du Colombier else 67881cf8742SDavid du Colombier a = a->sort; 67981cf8742SDavid du Colombier if(b = b->sort) 68081cf8742SDavid du Colombier b = b->sort; 68181cf8742SDavid du Colombier } 68281cf8742SDavid du Colombier 68381cf8742SDavid du Colombier b = a->sort; 68481cf8742SDavid du Colombier a->sort = nil; 68581cf8742SDavid du Colombier 68681cf8742SDavid du Colombier a = fidMergeSort(f); 68781cf8742SDavid du Colombier b = fidMergeSort(b); 68881cf8742SDavid du Colombier 68981cf8742SDavid du Colombier return fidMerge(a, b); 69081cf8742SDavid du Colombier } 69181cf8742SDavid du Colombier 69281cf8742SDavid du Colombier static int 69381cf8742SDavid du Colombier cmdWho(int argc, char* argv[]) 69481cf8742SDavid du Colombier { 69581cf8742SDavid du Colombier char *usage = "usage: who"; 6962cca75a1SDavid du Colombier int i, l1, l2, l; 69781cf8742SDavid du Colombier Con *con; 69881cf8742SDavid du Colombier Fid *fid, *last; 69981cf8742SDavid du Colombier 70081cf8742SDavid du Colombier ARGBEGIN{ 70181cf8742SDavid du Colombier default: 70281cf8742SDavid du Colombier return cliError(usage); 70381cf8742SDavid du Colombier }ARGEND 70481cf8742SDavid du Colombier 70581cf8742SDavid du Colombier if(argc > 0) 70681cf8742SDavid du Colombier return cliError(usage); 70781cf8742SDavid du Colombier 708*d7aba6c3SDavid du Colombier rlock(&cbox.clock); 7092cca75a1SDavid du Colombier l1 = 0; 7102cca75a1SDavid du Colombier l2 = 0; 71181cf8742SDavid du Colombier for(con=cbox.chead; con; con=con->cnext){ 7122cca75a1SDavid du Colombier if((l = strlen(con->name)) > l1) 7132cca75a1SDavid du Colombier l1 = l; 7142cca75a1SDavid du Colombier if((l = strlen(con->remote)) > l2) 7152cca75a1SDavid du Colombier l2 = l; 7162cca75a1SDavid du Colombier } 7172cca75a1SDavid du Colombier for(con=cbox.chead; con; con=con->cnext){ 7182cca75a1SDavid du Colombier consPrint("\t%-*s %-*s", l1, con->name, l2, con->remote); 719*d7aba6c3SDavid du Colombier qlock(&con->fidlock); 72081cf8742SDavid du Colombier last = nil; 72181cf8742SDavid du Colombier for(i=0; i<NFidHash; i++) 72281cf8742SDavid du Colombier for(fid=con->fidhash[i]; fid; fid=fid->hash) 72381cf8742SDavid du Colombier if(fid->fidno != NOFID && fid->uname){ 72481cf8742SDavid du Colombier fid->sort = last; 72581cf8742SDavid du Colombier last = fid; 72681cf8742SDavid du Colombier } 72781cf8742SDavid du Colombier fid = fidMergeSort(last); 72881cf8742SDavid du Colombier last = nil; 72981cf8742SDavid du Colombier for(; fid; last=fid, fid=fid->sort) 73081cf8742SDavid du Colombier if(last==nil || strcmp(fid->uname, last->uname) != 0) 73181cf8742SDavid du Colombier consPrint(" %q", fid->uname); 732*d7aba6c3SDavid du Colombier qunlock(&con->fidlock); 73381cf8742SDavid du Colombier consPrint("\n"); 73481cf8742SDavid du Colombier } 735*d7aba6c3SDavid du Colombier runlock(&cbox.clock); 73681cf8742SDavid du Colombier return 1; 73781cf8742SDavid du Colombier } 73881cf8742SDavid du Colombier 7395e96a66cSDavid du Colombier void 74034e04225SDavid du Colombier msgInit(void) 7415e96a66cSDavid du Colombier { 742*d7aba6c3SDavid du Colombier mbox.arendez.l = &mbox.alock; 74334e04225SDavid du Colombier 744*d7aba6c3SDavid du Colombier mbox.rrendez.l = &mbox.rlock; 7455e96a66cSDavid du Colombier 7465e96a66cSDavid du Colombier mbox.maxmsg = NMsgInit; 7475e96a66cSDavid du Colombier mbox.maxproc = NMsgProcInit; 7485e96a66cSDavid du Colombier mbox.msize = NMsizeInit; 7495e96a66cSDavid du Colombier 7505e96a66cSDavid du Colombier cliAddCmd("msg", cmdMsg); 75134e04225SDavid du Colombier } 7525e96a66cSDavid du Colombier 75334e04225SDavid du Colombier static int 75434e04225SDavid du Colombier cmdCon(int argc, char* argv[]) 75534e04225SDavid du Colombier { 75634e04225SDavid du Colombier char *p; 75734e04225SDavid du Colombier Con *con; 75834e04225SDavid du Colombier char *usage = "usage: con [-m ncon]"; 75934e04225SDavid du Colombier int maxcon, ncon, nconstarve; 76034e04225SDavid du Colombier 76134e04225SDavid du Colombier maxcon = 0; 76234e04225SDavid du Colombier 76334e04225SDavid du Colombier ARGBEGIN{ 76434e04225SDavid du Colombier default: 76534e04225SDavid du Colombier return cliError(usage); 76634e04225SDavid du Colombier case 'm': 76734e04225SDavid du Colombier p = ARGF(); 76834e04225SDavid du Colombier if(p == nil) 76934e04225SDavid du Colombier return cliError(usage); 77034e04225SDavid du Colombier maxcon = strtol(argv[0], &p, 0); 77134e04225SDavid du Colombier if(maxcon <= 0 || p == argv[0] || *p != '\0') 77234e04225SDavid du Colombier return cliError(usage); 77334e04225SDavid du Colombier break; 77434e04225SDavid du Colombier }ARGEND 77534e04225SDavid du Colombier if(argc) 77634e04225SDavid du Colombier return cliError(usage); 77734e04225SDavid du Colombier 778*d7aba6c3SDavid du Colombier wlock(&cbox.clock); 77934e04225SDavid du Colombier if(maxcon) 78034e04225SDavid du Colombier cbox.maxcon = maxcon; 78134e04225SDavid du Colombier maxcon = cbox.maxcon; 78234e04225SDavid du Colombier ncon = cbox.ncon; 78334e04225SDavid du Colombier nconstarve = cbox.nconstarve; 784*d7aba6c3SDavid du Colombier wunlock(&cbox.clock); 78534e04225SDavid du Colombier 78634e04225SDavid du Colombier consPrint("\tcon -m %d\n", maxcon); 78734e04225SDavid du Colombier consPrint("\tncon %d nconstarve %d\n", ncon, nconstarve); 78834e04225SDavid du Colombier 789*d7aba6c3SDavid du Colombier rlock(&cbox.clock); 79034e04225SDavid du Colombier for(con = cbox.chead; con != nil; con = con->cnext){ 79134e04225SDavid du Colombier consPrint("\t%s\n", con->name); 79234e04225SDavid du Colombier } 793*d7aba6c3SDavid du Colombier runlock(&cbox.clock); 79434e04225SDavid du Colombier 79534e04225SDavid du Colombier return 1; 79634e04225SDavid du Colombier } 79734e04225SDavid du Colombier 79834e04225SDavid du Colombier void 79934e04225SDavid du Colombier conInit(void) 80034e04225SDavid du Colombier { 801*d7aba6c3SDavid du Colombier cbox.arendez.l = &cbox.alock; 80234e04225SDavid du Colombier 80334e04225SDavid du Colombier cbox.maxcon = NConInit; 8045e96a66cSDavid du Colombier cbox.msize = NMsizeInit; 80534e04225SDavid du Colombier 80634e04225SDavid du Colombier cliAddCmd("con", cmdCon); 80781cf8742SDavid du Colombier cliAddCmd("who", cmdWho); 8085e96a66cSDavid du Colombier } 809