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 {
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
conFree(Con * con)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;
66*2cca75a1SDavid du Colombier con->flags = 0;
675316891fSDavid du Colombier con->isconsole = 0;
685e96a66cSDavid du Colombier
6934e04225SDavid du Colombier vtLock(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)
8234e04225SDavid du Colombier vtMemFree(con->name);
8334e04225SDavid du Colombier vtLockFree(con->fidlock);
8434e04225SDavid du Colombier vtMemFree(con->data);
85c366c7d4SDavid du Colombier vtRendezFree(con->wrendez);
8634e04225SDavid du Colombier vtLockFree(con->wlock);
87c366c7d4SDavid du Colombier vtRendezFree(con->mrendez);
8834e04225SDavid du Colombier vtLockFree(con->mlock);
89c366c7d4SDavid du Colombier vtRendezFree(con->rendez);
9034e04225SDavid du Colombier vtLockFree(con->lock);
9134e04225SDavid du Colombier vtMemFree(con);
9234e04225SDavid du Colombier cbox.ncon--;
9334e04225SDavid du Colombier vtUnlock(cbox.alock);
9434e04225SDavid du Colombier return;
9534e04225SDavid du Colombier }
9634e04225SDavid du Colombier con->anext = cbox.ahead;
9734e04225SDavid du Colombier cbox.ahead = con;
9834e04225SDavid du Colombier if(con->anext == nil)
9934e04225SDavid du Colombier vtWakeup(cbox.arendez);
10034e04225SDavid du Colombier vtUnlock(cbox.alock);
10134e04225SDavid du Colombier }
10234e04225SDavid du Colombier
10334e04225SDavid du Colombier static void
msgFree(Msg * m)10434e04225SDavid du Colombier msgFree(Msg* m)
10534e04225SDavid du Colombier {
10634e04225SDavid du Colombier assert(m->rwnext == nil);
1077f1bc48aSDavid du Colombier assert(m->flush == nil);
10834e04225SDavid du Colombier
10934e04225SDavid du Colombier vtLock(mbox.alock);
11034e04225SDavid du Colombier if(mbox.nmsg > mbox.maxmsg){
11134e04225SDavid du Colombier vtMemFree(m->data);
11234e04225SDavid du Colombier vtMemFree(m);
11334e04225SDavid du Colombier mbox.nmsg--;
11434e04225SDavid du Colombier vtUnlock(mbox.alock);
11534e04225SDavid du Colombier return;
11634e04225SDavid du Colombier }
11734e04225SDavid du Colombier m->anext = mbox.ahead;
11834e04225SDavid du Colombier mbox.ahead = m;
11934e04225SDavid du Colombier if(m->anext == nil)
12034e04225SDavid du Colombier vtWakeup(mbox.arendez);
12134e04225SDavid du Colombier vtUnlock(mbox.alock);
12234e04225SDavid du Colombier }
12334e04225SDavid du Colombier
12434e04225SDavid du Colombier static Msg*
msgAlloc(Con * con)12534e04225SDavid du Colombier msgAlloc(Con* con)
12634e04225SDavid du Colombier {
12734e04225SDavid du Colombier Msg *m;
12834e04225SDavid du Colombier
12934e04225SDavid du Colombier vtLock(mbox.alock);
13034e04225SDavid du Colombier while(mbox.ahead == nil){
13134e04225SDavid du Colombier if(mbox.nmsg >= mbox.maxmsg){
13234e04225SDavid du Colombier mbox.nmsgstarve++;
13334e04225SDavid du Colombier vtSleep(mbox.arendez);
13434e04225SDavid du Colombier continue;
13534e04225SDavid du Colombier }
13634e04225SDavid du Colombier m = vtMemAllocZ(sizeof(Msg));
13734e04225SDavid du Colombier m->data = vtMemAlloc(mbox.msize);
13834e04225SDavid du Colombier m->msize = mbox.msize;
13934e04225SDavid du Colombier mbox.nmsg++;
14034e04225SDavid du Colombier mbox.ahead = m;
14134e04225SDavid du Colombier break;
14234e04225SDavid du Colombier }
14334e04225SDavid du Colombier m = mbox.ahead;
14434e04225SDavid du Colombier mbox.ahead = m->anext;
14534e04225SDavid du Colombier m->anext = nil;
14634e04225SDavid du Colombier vtUnlock(mbox.alock);
14734e04225SDavid du Colombier
14834e04225SDavid du Colombier m->con = con;
14934e04225SDavid du Colombier m->state = MsgR;
1507f1bc48aSDavid du Colombier m->nowq = 0;
15134e04225SDavid du Colombier
15234e04225SDavid du Colombier return m;
15334e04225SDavid du Colombier }
15434e04225SDavid du Colombier
15534e04225SDavid du Colombier static void
msgMunlink(Msg * m)15634e04225SDavid du Colombier msgMunlink(Msg* m)
15734e04225SDavid du Colombier {
15834e04225SDavid du Colombier Con *con;
15934e04225SDavid du Colombier
16034e04225SDavid du Colombier con = m->con;
16134e04225SDavid du Colombier
16234e04225SDavid du Colombier if(m->mprev != nil)
16334e04225SDavid du Colombier m->mprev->mnext = m->mnext;
16434e04225SDavid du Colombier else
16534e04225SDavid du Colombier con->mhead = m->mnext;
16634e04225SDavid du Colombier if(m->mnext != nil)
16734e04225SDavid du Colombier m->mnext->mprev = m->mprev;
16834e04225SDavid du Colombier else
16934e04225SDavid du Colombier con->mtail = m->mprev;
17034e04225SDavid du Colombier m->mprev = m->mnext = nil;
17134e04225SDavid du Colombier }
17234e04225SDavid du Colombier
17334e04225SDavid du Colombier void
msgFlush(Msg * m)17434e04225SDavid du Colombier msgFlush(Msg* m)
17534e04225SDavid du Colombier {
17634e04225SDavid du Colombier Con *con;
1777f1bc48aSDavid du Colombier Msg *flush, *old;
17834e04225SDavid du Colombier
17934e04225SDavid du Colombier con = m->con;
18034e04225SDavid du Colombier
18128495efeSDavid du Colombier if(Dflag)
18239734e7eSDavid du Colombier fprint(2, "msgFlush %F\n", &m->t);
18339734e7eSDavid du Colombier
18434e04225SDavid du Colombier /*
18528495efeSDavid du Colombier * If this Tflush has been flushed, nothing to do.
18634e04225SDavid du Colombier * Look for the message to be flushed in the
18734e04225SDavid du Colombier * queue of all messages still on this connection.
18828495efeSDavid du Colombier * If it's not found must assume Elvis has already
18928495efeSDavid du Colombier * left the building and reply normally.
19034e04225SDavid du Colombier */
19134e04225SDavid du Colombier vtLock(con->mlock);
19228495efeSDavid du Colombier if(m->state == MsgF){
19328495efeSDavid du Colombier vtUnlock(con->mlock);
19428495efeSDavid du Colombier return;
19528495efeSDavid du Colombier }
19634e04225SDavid du Colombier for(old = con->mhead; old != nil; old = old->mnext)
19734e04225SDavid du Colombier if(old->t.tag == m->t.oldtag)
19834e04225SDavid du Colombier break;
19934e04225SDavid du Colombier if(old == nil){
20034e04225SDavid du Colombier if(Dflag)
20134e04225SDavid du Colombier fprint(2, "msgFlush: cannot find %d\n", m->t.oldtag);
20234e04225SDavid du Colombier vtUnlock(con->mlock);
20334e04225SDavid du Colombier return;
20434e04225SDavid du Colombier }
20534e04225SDavid du Colombier
20628495efeSDavid du Colombier if(Dflag)
20739734e7eSDavid du Colombier fprint(2, "\tmsgFlush found %F\n", &old->t);
20839734e7eSDavid du Colombier
20934e04225SDavid du Colombier /*
21034e04225SDavid du Colombier * Found it.
21128495efeSDavid du Colombier * There are two cases where the old message can be
21228495efeSDavid du Colombier * truly flushed and no reply to the original message given.
21328495efeSDavid du Colombier * The first is when the old message is in MsgR state; no
21428495efeSDavid du Colombier * processing has been done yet and it is still on the read
21528495efeSDavid du Colombier * queue. The second is if old is a Tflush, which doesn't
21628495efeSDavid du Colombier * affect the server state. In both cases, put the old
2177f1bc48aSDavid du Colombier * message into MsgF state and let MsgWrite toss it after
2187f1bc48aSDavid du Colombier * pulling it off the queue.
21934e04225SDavid du Colombier */
22028495efeSDavid du Colombier if(old->state == MsgR || old->t.type == Tflush){
22134e04225SDavid du Colombier old->state = MsgF;
22234e04225SDavid du Colombier if(Dflag)
22328495efeSDavid du Colombier fprint(2, "msgFlush: change %d from MsgR to MsgF\n",
22428495efeSDavid du Colombier m->t.oldtag);
22534e04225SDavid du Colombier }
22634e04225SDavid du Colombier
22734e04225SDavid du Colombier /*
22828495efeSDavid du Colombier * Link this flush message and the old message
2297f1bc48aSDavid du Colombier * so multiple flushes can be coalesced (if there are
23028495efeSDavid du Colombier * multiple Tflush messages for a particular pending
23128495efeSDavid du Colombier * request, it is only necessary to respond to the last
23228495efeSDavid du Colombier * one, so any previous can be removed) and to be
23328495efeSDavid du Colombier * sure flushes wait for their corresponding old
23428495efeSDavid du Colombier * message to go out first.
2357f1bc48aSDavid du Colombier * Waiting flush messages do not go on the write queue,
2367f1bc48aSDavid du Colombier * they are processed after the old message is dealt
2377f1bc48aSDavid du Colombier * with. There's no real need to protect the setting of
2387f1bc48aSDavid du Colombier * Msg.nowq, the only code to check it runs in this
2397f1bc48aSDavid du Colombier * process after this routine returns.
24034e04225SDavid du Colombier */
2417f1bc48aSDavid du Colombier if((flush = old->flush) != nil){
24234e04225SDavid du Colombier if(Dflag)
24328495efeSDavid du Colombier fprint(2, "msgFlush: remove %d from %d list\n",
2447f1bc48aSDavid du Colombier old->flush->t.tag, old->t.tag);
2457f1bc48aSDavid du Colombier m->flush = flush->flush;
2467f1bc48aSDavid du Colombier flush->flush = nil;
2477f1bc48aSDavid du Colombier msgMunlink(flush);
2487f1bc48aSDavid du Colombier msgFree(flush);
24934e04225SDavid du Colombier }
2507f1bc48aSDavid du Colombier old->flush = m;
2517f1bc48aSDavid du Colombier m->nowq = 1;
25234e04225SDavid du Colombier
25334e04225SDavid du Colombier if(Dflag)
25428495efeSDavid du Colombier fprint(2, "msgFlush: add %d to %d queue\n",
25528495efeSDavid du Colombier m->t.tag, old->t.tag);
25634e04225SDavid du Colombier vtUnlock(con->mlock);
2575e96a66cSDavid du Colombier }
2585e96a66cSDavid du Colombier
2595e96a66cSDavid du Colombier static void
msgProc(void *)2605e96a66cSDavid du Colombier msgProc(void*)
2615e96a66cSDavid du Colombier {
2625e96a66cSDavid du Colombier Msg *m;
2635e96a66cSDavid du Colombier char *e;
2645e96a66cSDavid du Colombier Con *con;
2655e96a66cSDavid du Colombier
26634e04225SDavid du Colombier vtThreadSetName("msgProc");
2675e96a66cSDavid du Colombier
26834e04225SDavid du Colombier for(;;){
26934e04225SDavid du Colombier /*
27034e04225SDavid du Colombier * If surplus to requirements, exit.
27134e04225SDavid du Colombier * If not, wait for and pull a message off
27234e04225SDavid du Colombier * the read queue.
27334e04225SDavid du Colombier */
27434e04225SDavid du Colombier vtLock(mbox.rlock);
27534e04225SDavid du Colombier if(mbox.nproc > mbox.maxproc){
27634e04225SDavid du Colombier mbox.nproc--;
27734e04225SDavid du Colombier vtUnlock(mbox.rlock);
27834e04225SDavid du Colombier break;
27934e04225SDavid du Colombier }
28034e04225SDavid du Colombier while(mbox.rhead == nil)
28134e04225SDavid du Colombier vtSleep(mbox.rrendez);
28234e04225SDavid du Colombier m = mbox.rhead;
28334e04225SDavid du Colombier mbox.rhead = m->rwnext;
28434e04225SDavid du Colombier m->rwnext = nil;
28534e04225SDavid du Colombier vtUnlock(mbox.rlock);
2865e96a66cSDavid du Colombier
2875e96a66cSDavid du Colombier con = m->con;
28834e04225SDavid du Colombier e = nil;
2895e96a66cSDavid du Colombier
29034e04225SDavid du Colombier /*
29128495efeSDavid du Colombier * If the message has been flushed before
29228495efeSDavid du Colombier * any 9P processing has started, mark it so
29328495efeSDavid du Colombier * none will be attempted.
29434e04225SDavid du Colombier */
29534e04225SDavid du Colombier vtLock(con->mlock);
29628495efeSDavid du Colombier if(m->state == MsgF)
29728495efeSDavid du Colombier e = "flushed";
29828495efeSDavid du Colombier else
29934e04225SDavid du Colombier m->state = Msg9;
30034e04225SDavid du Colombier vtUnlock(con->mlock);
30134e04225SDavid du Colombier
30228495efeSDavid du Colombier if(e == nil){
30334e04225SDavid du Colombier /*
30434e04225SDavid du Colombier * explain this
30534e04225SDavid du Colombier */
30634e04225SDavid du Colombier vtLock(con->lock);
3075e96a66cSDavid du Colombier if(m->t.type == Tversion){
3085e96a66cSDavid du Colombier con->version = m;
30934e04225SDavid du Colombier con->state = ConDown;
31034e04225SDavid du Colombier while(con->mhead != m)
31134e04225SDavid du Colombier vtSleep(con->rendez);
31234e04225SDavid du Colombier assert(con->state == ConDown);
3135e96a66cSDavid du Colombier if(con->version == m){
3145e96a66cSDavid du Colombier con->version = nil;
31534e04225SDavid du Colombier con->state = ConInit;
3165e96a66cSDavid du Colombier }
3175e96a66cSDavid du Colombier else
3185e96a66cSDavid du Colombier e = "Tversion aborted";
3195e96a66cSDavid du Colombier }
32034e04225SDavid du Colombier else if(con->state != ConUp)
3215e96a66cSDavid du Colombier e = "connection not ready";
3225e96a66cSDavid du Colombier vtUnlock(con->lock);
32328495efeSDavid du Colombier }
3245e96a66cSDavid du Colombier
3255e96a66cSDavid du Colombier /*
3265e96a66cSDavid du Colombier * Dispatch if not error already.
3275e96a66cSDavid du Colombier */
3285e96a66cSDavid du Colombier m->r.tag = m->t.tag;
3295e96a66cSDavid du Colombier if(e == nil && !(*rFcall[m->t.type])(m))
3305e96a66cSDavid du Colombier e = vtGetError();
3315e96a66cSDavid du Colombier if(e != nil){
3325e96a66cSDavid du Colombier m->r.type = Rerror;
3335e96a66cSDavid du Colombier m->r.ename = e;
3345e96a66cSDavid du Colombier }
3355e96a66cSDavid du Colombier else
3365e96a66cSDavid du Colombier m->r.type = m->t.type+1;
3375e96a66cSDavid du Colombier
3385e96a66cSDavid du Colombier /*
33934e04225SDavid du Colombier * Put the message (with reply) on the
34034e04225SDavid du Colombier * write queue and wakeup the write process.
3415e96a66cSDavid du Colombier */
3427f1bc48aSDavid du Colombier if(!m->nowq){
34334e04225SDavid du Colombier vtLock(con->wlock);
34434e04225SDavid du Colombier if(con->whead == nil)
34534e04225SDavid du Colombier con->whead = m;
3465e96a66cSDavid du Colombier else
34734e04225SDavid du Colombier con->wtail->rwnext = m;
34834e04225SDavid du Colombier con->wtail = m;
34934e04225SDavid du Colombier vtWakeup(con->wrendez);
35034e04225SDavid du Colombier vtUnlock(con->wlock);
3515e96a66cSDavid du Colombier }
3525e96a66cSDavid du Colombier }
3537f1bc48aSDavid du Colombier }
3545e96a66cSDavid du Colombier
3555e96a66cSDavid du Colombier static void
msgRead(void * v)35634e04225SDavid du Colombier msgRead(void* v)
3575e96a66cSDavid du Colombier {
3585e96a66cSDavid du Colombier Msg *m;
3595e96a66cSDavid du Colombier Con *con;
3605e96a66cSDavid du Colombier int eof, fd, n;
3615e96a66cSDavid du Colombier
36234e04225SDavid du Colombier vtThreadSetName("msgRead");
3635e96a66cSDavid du Colombier
3645e96a66cSDavid du Colombier con = v;
3655e96a66cSDavid du Colombier fd = con->fd;
3665e96a66cSDavid du Colombier eof = 0;
3675e96a66cSDavid du Colombier
3685e96a66cSDavid du Colombier while(!eof){
36934e04225SDavid du Colombier m = msgAlloc(con);
3705e96a66cSDavid du Colombier
3715e96a66cSDavid du Colombier while((n = read9pmsg(fd, m->data, con->msize)) == 0)
3725e96a66cSDavid du Colombier ;
3735e96a66cSDavid du Colombier if(n < 0){
3745e96a66cSDavid du Colombier m->t.type = Tversion;
3755e96a66cSDavid du Colombier m->t.fid = NOFID;
3765e96a66cSDavid du Colombier m->t.tag = NOTAG;
3775e96a66cSDavid du Colombier m->t.msize = con->msize;
3785e96a66cSDavid du Colombier m->t.version = "9PEoF";
3795e96a66cSDavid du Colombier eof = 1;
3805e96a66cSDavid du Colombier }
3815e96a66cSDavid du Colombier else if(convM2S(m->data, n, &m->t) != n){
3825e96a66cSDavid du Colombier if(Dflag)
38334e04225SDavid du Colombier fprint(2, "msgRead: convM2S error: %s\n",
3845e96a66cSDavid du Colombier con->name);
3855e96a66cSDavid du Colombier msgFree(m);
3865e96a66cSDavid du Colombier continue;
3875e96a66cSDavid du Colombier }
3885e96a66cSDavid du Colombier if(Dflag)
38939734e7eSDavid du Colombier fprint(2, "msgRead %p: t %F\n", con, &m->t);
3905e96a66cSDavid du Colombier
39134e04225SDavid du Colombier vtLock(con->mlock);
39234e04225SDavid du Colombier if(con->mtail != nil){
39334e04225SDavid du Colombier m->mprev = con->mtail;
39434e04225SDavid du Colombier con->mtail->mnext = m;
39534e04225SDavid du Colombier }
39634e04225SDavid du Colombier else{
39734e04225SDavid du Colombier con->mhead = m;
39834e04225SDavid du Colombier m->mprev = nil;
39934e04225SDavid du Colombier }
40034e04225SDavid du Colombier con->mtail = m;
40134e04225SDavid du Colombier vtUnlock(con->mlock);
40234e04225SDavid du Colombier
40334e04225SDavid du Colombier vtLock(mbox.rlock);
40434e04225SDavid du Colombier if(mbox.rhead == nil){
40534e04225SDavid du Colombier mbox.rhead = m;
40634e04225SDavid du Colombier if(!vtWakeup(mbox.rrendez)){
40734e04225SDavid du Colombier if(mbox.nproc < mbox.maxproc){
4085e96a66cSDavid du Colombier if(vtThread(msgProc, nil) > 0)
4095e96a66cSDavid du Colombier mbox.nproc++;
4105e96a66cSDavid du Colombier }
41134e04225SDavid du Colombier else
41234e04225SDavid du Colombier mbox.nprocstarve++;
41334e04225SDavid du Colombier }
41434e04225SDavid du Colombier /*
41534e04225SDavid du Colombier * don't need this surely?
41634e04225SDavid du Colombier vtWakeup(mbox.rrendez);
41734e04225SDavid du Colombier */
4185e96a66cSDavid du Colombier }
4195e96a66cSDavid du Colombier else
42034e04225SDavid du Colombier mbox.rtail->rwnext = m;
42134e04225SDavid du Colombier mbox.rtail = m;
42234e04225SDavid du Colombier vtUnlock(mbox.rlock);
4235e96a66cSDavid du Colombier }
42434e04225SDavid du Colombier }
42534e04225SDavid du Colombier
42634e04225SDavid du Colombier static void
msgWrite(void * v)42734e04225SDavid du Colombier msgWrite(void* v)
42834e04225SDavid du Colombier {
42934e04225SDavid du Colombier Con *con;
4307f1bc48aSDavid du Colombier int eof, n;
4317f1bc48aSDavid du Colombier Msg *flush, *m;
43234e04225SDavid du Colombier
43334e04225SDavid du Colombier vtThreadSetName("msgWrite");
43434e04225SDavid du Colombier
43534e04225SDavid du Colombier con = v;
43634e04225SDavid du Colombier if(vtThread(msgRead, con) < 0){
43734e04225SDavid du Colombier conFree(con);
43834e04225SDavid du Colombier return;
43934e04225SDavid du Colombier }
44034e04225SDavid du Colombier
44134e04225SDavid du Colombier for(;;){
44234e04225SDavid du Colombier /*
44334e04225SDavid du Colombier * Wait for and pull a message off the write queue.
44434e04225SDavid du Colombier */
44534e04225SDavid du Colombier vtLock(con->wlock);
44634e04225SDavid du Colombier while(con->whead == nil)
44734e04225SDavid du Colombier vtSleep(con->wrendez);
44834e04225SDavid du Colombier m = con->whead;
44934e04225SDavid du Colombier con->whead = m->rwnext;
45034e04225SDavid du Colombier m->rwnext = nil;
4517f1bc48aSDavid du Colombier assert(!m->nowq);
45234e04225SDavid du Colombier vtUnlock(con->wlock);
45334e04225SDavid du Colombier
4547f1bc48aSDavid du Colombier eof = 0;
4557f1bc48aSDavid du Colombier
45634e04225SDavid du Colombier /*
4577f1bc48aSDavid du Colombier * Write each message (if it hasn't been flushed)
4587f1bc48aSDavid du Colombier * followed by any messages waiting for it to complete.
45934e04225SDavid du Colombier */
46034e04225SDavid du Colombier vtLock(con->mlock);
4617f1bc48aSDavid du Colombier while(m != nil){
4627f1bc48aSDavid du Colombier msgMunlink(m);
4637f1bc48aSDavid du Colombier
4647f1bc48aSDavid du Colombier if(Dflag)
4657f1bc48aSDavid du Colombier fprint(2, "msgWrite %d: r %F\n",
4667f1bc48aSDavid du Colombier m->state, &m->r);
4677f1bc48aSDavid du Colombier
4687f1bc48aSDavid du Colombier if(m->state != MsgF){
46934e04225SDavid du Colombier m->state = MsgW;
4707f1bc48aSDavid du Colombier vtUnlock(con->mlock);
4717f1bc48aSDavid du Colombier
4727f1bc48aSDavid du Colombier n = convS2M(&m->r, con->data, con->msize);
4737f1bc48aSDavid du Colombier if(write(con->fd, con->data, n) != n)
4747f1bc48aSDavid du Colombier eof = 1;
4757f1bc48aSDavid du Colombier
4767f1bc48aSDavid du Colombier vtLock(con->mlock);
4777f1bc48aSDavid du Colombier }
4787f1bc48aSDavid du Colombier
4797f1bc48aSDavid du Colombier if((flush = m->flush) != nil){
4807f1bc48aSDavid du Colombier assert(flush->nowq);
4817f1bc48aSDavid du Colombier m->flush = nil;
4827f1bc48aSDavid du Colombier }
4837f1bc48aSDavid du Colombier msgFree(m);
4847f1bc48aSDavid du Colombier m = flush;
4857f1bc48aSDavid du Colombier }
48634e04225SDavid du Colombier vtUnlock(con->mlock);
48734e04225SDavid du Colombier
48834e04225SDavid du Colombier vtLock(con->lock);
48934e04225SDavid du Colombier if(eof && con->fd >= 0){
49034e04225SDavid du Colombier close(con->fd);
49134e04225SDavid du Colombier con->fd = -1;
49234e04225SDavid du Colombier }
49334e04225SDavid du Colombier if(con->state == ConDown)
49434e04225SDavid du Colombier vtWakeup(con->rendez);
49534e04225SDavid du Colombier if(con->state == ConMoribund && con->mhead == nil){
49634e04225SDavid du Colombier vtUnlock(con->lock);
49734e04225SDavid du Colombier conFree(con);
49834e04225SDavid du Colombier break;
49934e04225SDavid du Colombier }
50034e04225SDavid du Colombier vtUnlock(con->lock);
50134e04225SDavid du Colombier }
5025e96a66cSDavid du Colombier }
5035e96a66cSDavid du Colombier
5045e96a66cSDavid du Colombier Con*
conAlloc(int fd,char * name,int flags)505*2cca75a1SDavid du Colombier conAlloc(int fd, char* name, int flags)
5065e96a66cSDavid du Colombier {
5075e96a66cSDavid du Colombier Con *con;
508*2cca75a1SDavid du Colombier char buf[128], *p;
509*2cca75a1SDavid du Colombier int rfd, n;
5105e96a66cSDavid du Colombier
51134e04225SDavid du Colombier vtLock(cbox.alock);
51234e04225SDavid du Colombier while(cbox.ahead == nil){
51334e04225SDavid du Colombier if(cbox.ncon >= cbox.maxcon){
51434e04225SDavid du Colombier cbox.nconstarve++;
51534e04225SDavid du Colombier vtSleep(cbox.arendez);
51634e04225SDavid du Colombier continue;
5175e96a66cSDavid du Colombier }
5185e96a66cSDavid du Colombier con = vtMemAllocZ(sizeof(Con));
5195e96a66cSDavid du Colombier con->lock = vtLockAlloc();
52034e04225SDavid du Colombier con->rendez = vtRendezAlloc(con->lock);
5215e96a66cSDavid du Colombier con->data = vtMemAlloc(cbox.msize);
5225e96a66cSDavid du Colombier con->msize = cbox.msize;
52334e04225SDavid du Colombier con->alock = vtLockAlloc();
52434e04225SDavid du Colombier con->mlock = vtLockAlloc();
52534e04225SDavid du Colombier con->mrendez = vtRendezAlloc(con->mlock);
52634e04225SDavid du Colombier con->wlock = vtLockAlloc();
52734e04225SDavid du Colombier con->wrendez = vtRendezAlloc(con->wlock);
5285e96a66cSDavid du Colombier con->fidlock = vtLockAlloc();
52934e04225SDavid du Colombier
53034e04225SDavid du Colombier cbox.ncon++;
53134e04225SDavid du Colombier cbox.ahead = con;
53234e04225SDavid du Colombier break;
5335e96a66cSDavid du Colombier }
53434e04225SDavid du Colombier con = cbox.ahead;
53534e04225SDavid du Colombier cbox.ahead = con->anext;
53634e04225SDavid du Colombier con->anext = nil;
53734e04225SDavid du Colombier
53834e04225SDavid du Colombier if(cbox.ctail != nil){
53934e04225SDavid du Colombier con->cprev = cbox.ctail;
54034e04225SDavid du Colombier cbox.ctail->cnext = con;
54134e04225SDavid du Colombier }
54234e04225SDavid du Colombier else{
54334e04225SDavid du Colombier cbox.chead = con;
54434e04225SDavid du Colombier con->cprev = nil;
54534e04225SDavid du Colombier }
54634e04225SDavid du Colombier cbox.ctail = con;
54734e04225SDavid du Colombier
5485e96a66cSDavid du Colombier assert(con->mhead == nil);
54934e04225SDavid du Colombier assert(con->whead == nil);
5505e96a66cSDavid du Colombier assert(con->fhead == nil);
5515e96a66cSDavid du Colombier assert(con->nfid == 0);
5525e96a66cSDavid du Colombier
55334e04225SDavid du Colombier con->state = ConNew;
5545e96a66cSDavid du Colombier con->fd = fd;
5555e96a66cSDavid du Colombier if(con->name != nil){
5565e96a66cSDavid du Colombier vtMemFree(con->name);
5575e96a66cSDavid du Colombier con->name = nil;
5585e96a66cSDavid du Colombier }
5595e96a66cSDavid du Colombier if(name != nil)
5605e96a66cSDavid du Colombier con->name = vtStrDup(name);
56134e04225SDavid du Colombier else
56234e04225SDavid du Colombier con->name = vtStrDup("unknown");
563*2cca75a1SDavid du Colombier con->remote[0] = 0;
564*2cca75a1SDavid du Colombier snprint(buf, sizeof buf, "%s/remote", con->name);
565*2cca75a1SDavid du Colombier if((rfd = open(buf, OREAD)) >= 0){
566*2cca75a1SDavid du Colombier n = read(rfd, buf, sizeof buf-1);
567*2cca75a1SDavid du Colombier close(rfd);
568*2cca75a1SDavid du Colombier if(n > 0){
569*2cca75a1SDavid du Colombier buf[n] = 0;
570*2cca75a1SDavid du Colombier if((p = strchr(buf, '\n')) != nil)
571*2cca75a1SDavid du Colombier *p = 0;
572*2cca75a1SDavid du Colombier strecpy(con->remote, con->remote+sizeof con->remote, buf);
573*2cca75a1SDavid du Colombier }
574*2cca75a1SDavid du Colombier }
575*2cca75a1SDavid du Colombier con->flags = flags;
5765316891fSDavid du Colombier con->isconsole = 0;
57734e04225SDavid du Colombier vtUnlock(cbox.alock);
5785e96a66cSDavid du Colombier
57934e04225SDavid du Colombier if(vtThread(msgWrite, con) < 0){
5805e96a66cSDavid du Colombier conFree(con);
5815e96a66cSDavid du Colombier return nil;
5825e96a66cSDavid du Colombier }
5835e96a66cSDavid du Colombier
5845e96a66cSDavid du Colombier return con;
5855e96a66cSDavid du Colombier }
5865e96a66cSDavid du Colombier
5875e96a66cSDavid du Colombier static int
cmdMsg(int argc,char * argv[])5885e96a66cSDavid du Colombier cmdMsg(int argc, char* argv[])
5895e96a66cSDavid du Colombier {
5905e96a66cSDavid du Colombier char *p;
5915e96a66cSDavid du Colombier char *usage = "usage: msg [-m nmsg] [-p nproc]";
59234e04225SDavid du Colombier int maxmsg, nmsg, nmsgstarve, maxproc, nproc, nprocstarve;
5935e96a66cSDavid du Colombier
5945e96a66cSDavid du Colombier maxmsg = maxproc = 0;
5955e96a66cSDavid du Colombier
5965e96a66cSDavid du Colombier ARGBEGIN{
5975e96a66cSDavid du Colombier default:
5985e96a66cSDavid du Colombier return cliError(usage);
5995e96a66cSDavid du Colombier case 'm':
6005e96a66cSDavid du Colombier p = ARGF();
6015e96a66cSDavid du Colombier if(p == nil)
6025e96a66cSDavid du Colombier return cliError(usage);
6035e96a66cSDavid du Colombier maxmsg = strtol(argv[0], &p, 0);
6045e96a66cSDavid du Colombier if(maxmsg <= 0 || p == argv[0] || *p != '\0')
6055e96a66cSDavid du Colombier return cliError(usage);
6065e96a66cSDavid du Colombier break;
6075e96a66cSDavid du Colombier case 'p':
6085e96a66cSDavid du Colombier p = ARGF();
6095e96a66cSDavid du Colombier if(p == nil)
6105e96a66cSDavid du Colombier return cliError(usage);
6115e96a66cSDavid du Colombier maxproc = strtol(argv[0], &p, 0);
6125e96a66cSDavid du Colombier if(maxproc <= 0 || p == argv[0] || *p != '\0')
6135e96a66cSDavid du Colombier return cliError(usage);
6145e96a66cSDavid du Colombier break;
6155e96a66cSDavid du Colombier }ARGEND
6165e96a66cSDavid du Colombier if(argc)
6175e96a66cSDavid du Colombier return cliError(usage);
6185e96a66cSDavid du Colombier
61934e04225SDavid du Colombier vtLock(mbox.alock);
6205e96a66cSDavid du Colombier if(maxmsg)
6215e96a66cSDavid du Colombier mbox.maxmsg = maxmsg;
6225e96a66cSDavid du Colombier maxmsg = mbox.maxmsg;
62334e04225SDavid du Colombier nmsg = mbox.nmsg;
62434e04225SDavid du Colombier nmsgstarve = mbox.nmsgstarve;
62534e04225SDavid du Colombier vtUnlock(mbox.alock);
62634e04225SDavid du Colombier
62734e04225SDavid du Colombier vtLock(mbox.rlock);
6285e96a66cSDavid du Colombier if(maxproc)
6295e96a66cSDavid du Colombier mbox.maxproc = maxproc;
6305e96a66cSDavid du Colombier maxproc = mbox.maxproc;
63134e04225SDavid du Colombier nproc = mbox.nproc;
63234e04225SDavid du Colombier nprocstarve = mbox.nprocstarve;
63334e04225SDavid du Colombier vtUnlock(mbox.rlock);
6345e96a66cSDavid du Colombier
6355e96a66cSDavid du Colombier consPrint("\tmsg -m %d -p %d\n", maxmsg, maxproc);
63634e04225SDavid du Colombier consPrint("\tnmsg %d nmsgstarve %d nproc %d nprocstarve %d\n",
63734e04225SDavid du Colombier nmsg, nmsgstarve, nproc, nprocstarve);
6385e96a66cSDavid du Colombier
6395e96a66cSDavid du Colombier return 1;
6405e96a66cSDavid du Colombier }
6415e96a66cSDavid du Colombier
64281cf8742SDavid du Colombier static int
scmp(Fid * a,Fid * b)64381cf8742SDavid du Colombier scmp(Fid *a, Fid *b)
64481cf8742SDavid du Colombier {
64581cf8742SDavid du Colombier if(a == 0)
64681cf8742SDavid du Colombier return 1;
64781cf8742SDavid du Colombier if(b == 0)
64881cf8742SDavid du Colombier return -1;
64981cf8742SDavid du Colombier return strcmp(a->uname, b->uname);
65081cf8742SDavid du Colombier }
65181cf8742SDavid du Colombier
65281cf8742SDavid du Colombier static Fid*
fidMerge(Fid * a,Fid * b)65381cf8742SDavid du Colombier fidMerge(Fid *a, Fid *b)
65481cf8742SDavid du Colombier {
65581cf8742SDavid du Colombier Fid *s, **l;
65681cf8742SDavid du Colombier
65781cf8742SDavid du Colombier l = &s;
65881cf8742SDavid du Colombier while(a || b){
65981cf8742SDavid du Colombier if(scmp(a, b) < 0){
66081cf8742SDavid du Colombier *l = a;
66181cf8742SDavid du Colombier l = &a->sort;
66281cf8742SDavid du Colombier a = a->sort;
66381cf8742SDavid du Colombier }else{
66481cf8742SDavid du Colombier *l = b;
66581cf8742SDavid du Colombier l = &b->sort;
66681cf8742SDavid du Colombier b = b->sort;
66781cf8742SDavid du Colombier }
66881cf8742SDavid du Colombier }
66981cf8742SDavid du Colombier *l = 0;
67081cf8742SDavid du Colombier return s;
67181cf8742SDavid du Colombier }
67281cf8742SDavid du Colombier
67381cf8742SDavid du Colombier static Fid*
fidMergeSort(Fid * f)67481cf8742SDavid du Colombier fidMergeSort(Fid *f)
67581cf8742SDavid du Colombier {
67681cf8742SDavid du Colombier int delay;
67781cf8742SDavid du Colombier Fid *a, *b;
67881cf8742SDavid du Colombier
67981cf8742SDavid du Colombier if(f == nil)
68081cf8742SDavid du Colombier return nil;
68181cf8742SDavid du Colombier if(f->sort == nil)
68281cf8742SDavid du Colombier return f;
68381cf8742SDavid du Colombier
68481cf8742SDavid du Colombier a = b = f;
68581cf8742SDavid du Colombier delay = 1;
68681cf8742SDavid du Colombier while(a && b){
68781cf8742SDavid du Colombier if(delay) /* easy way to handle 2-element list */
68881cf8742SDavid du Colombier delay = 0;
68981cf8742SDavid du Colombier else
69081cf8742SDavid du Colombier a = a->sort;
69181cf8742SDavid du Colombier if(b = b->sort)
69281cf8742SDavid du Colombier b = b->sort;
69381cf8742SDavid du Colombier }
69481cf8742SDavid du Colombier
69581cf8742SDavid du Colombier b = a->sort;
69681cf8742SDavid du Colombier a->sort = nil;
69781cf8742SDavid du Colombier
69881cf8742SDavid du Colombier a = fidMergeSort(f);
69981cf8742SDavid du Colombier b = fidMergeSort(b);
70081cf8742SDavid du Colombier
70181cf8742SDavid du Colombier return fidMerge(a, b);
70281cf8742SDavid du Colombier }
70381cf8742SDavid du Colombier
70481cf8742SDavid du Colombier static int
cmdWho(int argc,char * argv[])70581cf8742SDavid du Colombier cmdWho(int argc, char* argv[])
70681cf8742SDavid du Colombier {
70781cf8742SDavid du Colombier char *usage = "usage: who";
708*2cca75a1SDavid du Colombier int i, l1, l2, l;
70981cf8742SDavid du Colombier Con *con;
71081cf8742SDavid du Colombier Fid *fid, *last;
71181cf8742SDavid du Colombier
71281cf8742SDavid du Colombier ARGBEGIN{
71381cf8742SDavid du Colombier default:
71481cf8742SDavid du Colombier return cliError(usage);
71581cf8742SDavid du Colombier }ARGEND
71681cf8742SDavid du Colombier
71781cf8742SDavid du Colombier if(argc > 0)
71881cf8742SDavid du Colombier return cliError(usage);
71981cf8742SDavid du Colombier
72081cf8742SDavid du Colombier vtRLock(cbox.clock);
721*2cca75a1SDavid du Colombier l1 = 0;
722*2cca75a1SDavid du Colombier l2 = 0;
72381cf8742SDavid du Colombier for(con=cbox.chead; con; con=con->cnext){
724*2cca75a1SDavid du Colombier if((l = strlen(con->name)) > l1)
725*2cca75a1SDavid du Colombier l1 = l;
726*2cca75a1SDavid du Colombier if((l = strlen(con->remote)) > l2)
727*2cca75a1SDavid du Colombier l2 = l;
728*2cca75a1SDavid du Colombier }
729*2cca75a1SDavid du Colombier for(con=cbox.chead; con; con=con->cnext){
730*2cca75a1SDavid du Colombier consPrint("\t%-*s %-*s", l1, con->name, l2, con->remote);
73181cf8742SDavid du Colombier vtLock(con->fidlock);
73281cf8742SDavid du Colombier last = nil;
73381cf8742SDavid du Colombier for(i=0; i<NFidHash; i++)
73481cf8742SDavid du Colombier for(fid=con->fidhash[i]; fid; fid=fid->hash)
73581cf8742SDavid du Colombier if(fid->fidno != NOFID && fid->uname){
73681cf8742SDavid du Colombier fid->sort = last;
73781cf8742SDavid du Colombier last = fid;
73881cf8742SDavid du Colombier }
73981cf8742SDavid du Colombier fid = fidMergeSort(last);
74081cf8742SDavid du Colombier last = nil;
74181cf8742SDavid du Colombier for(; fid; last=fid, fid=fid->sort)
74281cf8742SDavid du Colombier if(last==nil || strcmp(fid->uname, last->uname) != 0)
74381cf8742SDavid du Colombier consPrint(" %q", fid->uname);
74481cf8742SDavid du Colombier vtUnlock(con->fidlock);
74581cf8742SDavid du Colombier consPrint("\n");
74681cf8742SDavid du Colombier }
74781cf8742SDavid du Colombier vtRUnlock(cbox.clock);
74881cf8742SDavid du Colombier return 1;
74981cf8742SDavid du Colombier }
75081cf8742SDavid du Colombier
7515e96a66cSDavid du Colombier void
msgInit(void)75234e04225SDavid du Colombier msgInit(void)
7535e96a66cSDavid du Colombier {
75434e04225SDavid du Colombier mbox.alock = vtLockAlloc();
75534e04225SDavid du Colombier mbox.arendez = vtRendezAlloc(mbox.alock);
75634e04225SDavid du Colombier
75734e04225SDavid du Colombier mbox.rlock = vtLockAlloc();
75834e04225SDavid du Colombier mbox.rrendez = vtRendezAlloc(mbox.rlock);
7595e96a66cSDavid du Colombier
7605e96a66cSDavid du Colombier mbox.maxmsg = NMsgInit;
7615e96a66cSDavid du Colombier mbox.maxproc = NMsgProcInit;
7625e96a66cSDavid du Colombier mbox.msize = NMsizeInit;
7635e96a66cSDavid du Colombier
7645e96a66cSDavid du Colombier cliAddCmd("msg", cmdMsg);
76534e04225SDavid du Colombier }
7665e96a66cSDavid du Colombier
76734e04225SDavid du Colombier static int
cmdCon(int argc,char * argv[])76834e04225SDavid du Colombier cmdCon(int argc, char* argv[])
76934e04225SDavid du Colombier {
77034e04225SDavid du Colombier char *p;
77134e04225SDavid du Colombier Con *con;
77234e04225SDavid du Colombier char *usage = "usage: con [-m ncon]";
77334e04225SDavid du Colombier int maxcon, ncon, nconstarve;
77434e04225SDavid du Colombier
77534e04225SDavid du Colombier maxcon = 0;
77634e04225SDavid du Colombier
77734e04225SDavid du Colombier ARGBEGIN{
77834e04225SDavid du Colombier default:
77934e04225SDavid du Colombier return cliError(usage);
78034e04225SDavid du Colombier case 'm':
78134e04225SDavid du Colombier p = ARGF();
78234e04225SDavid du Colombier if(p == nil)
78334e04225SDavid du Colombier return cliError(usage);
78434e04225SDavid du Colombier maxcon = strtol(argv[0], &p, 0);
78534e04225SDavid du Colombier if(maxcon <= 0 || p == argv[0] || *p != '\0')
78634e04225SDavid du Colombier return cliError(usage);
78734e04225SDavid du Colombier break;
78834e04225SDavid du Colombier }ARGEND
78934e04225SDavid du Colombier if(argc)
79034e04225SDavid du Colombier return cliError(usage);
79134e04225SDavid du Colombier
79234e04225SDavid du Colombier vtLock(cbox.clock);
79334e04225SDavid du Colombier if(maxcon)
79434e04225SDavid du Colombier cbox.maxcon = maxcon;
79534e04225SDavid du Colombier maxcon = cbox.maxcon;
79634e04225SDavid du Colombier ncon = cbox.ncon;
79734e04225SDavid du Colombier nconstarve = cbox.nconstarve;
79834e04225SDavid du Colombier vtUnlock(cbox.clock);
79934e04225SDavid du Colombier
80034e04225SDavid du Colombier consPrint("\tcon -m %d\n", maxcon);
80134e04225SDavid du Colombier consPrint("\tncon %d nconstarve %d\n", ncon, nconstarve);
80234e04225SDavid du Colombier
80334e04225SDavid du Colombier vtRLock(cbox.clock);
80434e04225SDavid du Colombier for(con = cbox.chead; con != nil; con = con->cnext){
80534e04225SDavid du Colombier consPrint("\t%s\n", con->name);
80634e04225SDavid du Colombier }
80734e04225SDavid du Colombier vtRUnlock(cbox.clock);
80834e04225SDavid du Colombier
80934e04225SDavid du Colombier return 1;
81034e04225SDavid du Colombier }
81134e04225SDavid du Colombier
81234e04225SDavid du Colombier void
conInit(void)81334e04225SDavid du Colombier conInit(void)
81434e04225SDavid du Colombier {
81534e04225SDavid du Colombier cbox.alock = vtLockAlloc();
81634e04225SDavid du Colombier cbox.arendez = vtRendezAlloc(cbox.alock);
81734e04225SDavid du Colombier
81834e04225SDavid du Colombier cbox.clock = vtLockAlloc();
81934e04225SDavid du Colombier
82034e04225SDavid du Colombier cbox.maxcon = NConInit;
8215e96a66cSDavid du Colombier cbox.msize = NMsizeInit;
82234e04225SDavid du Colombier
82334e04225SDavid du Colombier cliAddCmd("con", cmdCon);
82481cf8742SDavid du Colombier cliAddCmd("who", cmdWho);
8255e96a66cSDavid du Colombier }
826