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,
11*2ec6491fSDavid du Colombier NMsizeInit = 16*1024+IOHDRSZ,
125e96a66cSDavid du Colombier };
135e96a66cSDavid du Colombier
145e96a66cSDavid du Colombier static struct {
15d7aba6c3SDavid du Colombier QLock alock; /* alloc */
1634e04225SDavid du Colombier Msg* ahead;
17d7aba6c3SDavid 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
23d7aba6c3SDavid du Colombier QLock rlock; /* read */
2434e04225SDavid du Colombier Msg* rhead;
2534e04225SDavid du Colombier Msg* rtail;
26d7aba6c3SDavid 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 {
36d7aba6c3SDavid du Colombier QLock alock; /* alloc */
3734e04225SDavid du Colombier Con* ahead;
38d7aba6c3SDavid du Colombier Rendez arendez;
3934e04225SDavid du Colombier
40d7aba6c3SDavid 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
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;
662cca75a1SDavid du Colombier con->flags = 0;
675316891fSDavid du Colombier con->isconsole = 0;
685e96a66cSDavid du Colombier
69d7aba6c3SDavid 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)
82d7aba6c3SDavid du Colombier vtfree(con->name);
83d7aba6c3SDavid du Colombier vtfree(con->data);
84d7aba6c3SDavid du Colombier vtfree(con);
8534e04225SDavid du Colombier cbox.ncon--;
86d7aba6c3SDavid 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)
92d7aba6c3SDavid du Colombier rwakeup(&cbox.arendez);
93d7aba6c3SDavid du Colombier qunlock(&cbox.alock);
9434e04225SDavid du Colombier }
9534e04225SDavid du Colombier
9634e04225SDavid du Colombier static void
msgFree(Msg * m)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
102d7aba6c3SDavid du Colombier qlock(&mbox.alock);
10334e04225SDavid du Colombier if(mbox.nmsg > mbox.maxmsg){
104d7aba6c3SDavid du Colombier vtfree(m->data);
105d7aba6c3SDavid du Colombier vtfree(m);
10634e04225SDavid du Colombier mbox.nmsg--;
107d7aba6c3SDavid 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)
113d7aba6c3SDavid du Colombier rwakeup(&mbox.arendez);
114d7aba6c3SDavid du Colombier qunlock(&mbox.alock);
11534e04225SDavid du Colombier }
11634e04225SDavid du Colombier
11734e04225SDavid du Colombier static Msg*
msgAlloc(Con * con)11834e04225SDavid du Colombier msgAlloc(Con* con)
11934e04225SDavid du Colombier {
12034e04225SDavid du Colombier Msg *m;
12134e04225SDavid du Colombier
122d7aba6c3SDavid 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++;
126d7aba6c3SDavid du Colombier rsleep(&mbox.arendez);
12734e04225SDavid du Colombier continue;
12834e04225SDavid du Colombier }
129d7aba6c3SDavid du Colombier m = vtmallocz(sizeof(Msg));
130d7aba6c3SDavid 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;
139d7aba6c3SDavid 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
msgMunlink(Msg * m)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
msgFlush(Msg * m)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 */
184d7aba6c3SDavid du Colombier qlock(&con->mlock);
18528495efeSDavid du Colombier if(m->state == MsgF){
186d7aba6c3SDavid 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);
195d7aba6c3SDavid 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);
249d7aba6c3SDavid du Colombier qunlock(&con->mlock);
2505e96a66cSDavid du Colombier }
2515e96a66cSDavid du Colombier
2525e96a66cSDavid du Colombier static void
msgProc(void *)2535e96a66cSDavid du Colombier msgProc(void*)
2545e96a66cSDavid du Colombier {
2555e96a66cSDavid du Colombier Msg *m;
256d7aba6c3SDavid du Colombier char e[ERRMAX];
2575e96a66cSDavid du Colombier Con *con;
2585e96a66cSDavid du Colombier
259d7aba6c3SDavid 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 */
267d7aba6c3SDavid du Colombier qlock(&mbox.rlock);
26834e04225SDavid du Colombier if(mbox.nproc > mbox.maxproc){
26934e04225SDavid du Colombier mbox.nproc--;
270d7aba6c3SDavid du Colombier qunlock(&mbox.rlock);
27134e04225SDavid du Colombier break;
27234e04225SDavid du Colombier }
27334e04225SDavid du Colombier while(mbox.rhead == nil)
274d7aba6c3SDavid du Colombier rsleep(&mbox.rrendez);
27534e04225SDavid du Colombier m = mbox.rhead;
27634e04225SDavid du Colombier mbox.rhead = m->rwnext;
27734e04225SDavid du Colombier m->rwnext = nil;
278d7aba6c3SDavid du Colombier qunlock(&mbox.rlock);
2795e96a66cSDavid du Colombier
2805e96a66cSDavid du Colombier con = m->con;
281d7aba6c3SDavid 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 */
288d7aba6c3SDavid du Colombier qlock(&con->mlock);
28928495efeSDavid du Colombier if(m->state == MsgF)
290d7aba6c3SDavid du Colombier strcpy(e, "flushed");
29128495efeSDavid du Colombier else
29234e04225SDavid du Colombier m->state = Msg9;
293d7aba6c3SDavid du Colombier qunlock(&con->mlock);
29434e04225SDavid du Colombier
295d7aba6c3SDavid du Colombier if(*e == 0){
29634e04225SDavid du Colombier /*
29734e04225SDavid du Colombier * explain this
29834e04225SDavid du Colombier */
299d7aba6c3SDavid 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)
304d7aba6c3SDavid 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
311d7aba6c3SDavid du Colombier strcpy(e, "Tversion aborted");
3125e96a66cSDavid du Colombier }
31334e04225SDavid du Colombier else if(con->state != ConUp)
314d7aba6c3SDavid du Colombier strcpy(e, "connection not ready");
315d7aba6c3SDavid 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;
322d7aba6c3SDavid du Colombier if(*e == 0 && !(*rFcall[m->t.type])(m))
323d7aba6c3SDavid du Colombier rerrstr(e, sizeof e);
324d7aba6c3SDavid 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){
336d7aba6c3SDavid 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;
342d7aba6c3SDavid du Colombier rwakeup(&con->wrendez);
343d7aba6c3SDavid du Colombier qunlock(&con->wlock);
3445e96a66cSDavid du Colombier }
3455e96a66cSDavid du Colombier }
3467f1bc48aSDavid du Colombier }
3475e96a66cSDavid du Colombier
3485e96a66cSDavid du Colombier static void
msgRead(void * v)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
355d7aba6c3SDavid 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
384d7aba6c3SDavid 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;
394d7aba6c3SDavid du Colombier qunlock(&con->mlock);
39534e04225SDavid du Colombier
396d7aba6c3SDavid du Colombier qlock(&mbox.rlock);
39734e04225SDavid du Colombier if(mbox.rhead == nil){
39834e04225SDavid du Colombier mbox.rhead = m;
399d7aba6c3SDavid du Colombier if(!rwakeup(&mbox.rrendez)){
40034e04225SDavid du Colombier if(mbox.nproc < mbox.maxproc){
401d7aba6c3SDavid 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?
409d7aba6c3SDavid 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;
415d7aba6c3SDavid du Colombier qunlock(&mbox.rlock);
4165e96a66cSDavid du Colombier }
41734e04225SDavid du Colombier }
41834e04225SDavid du Colombier
41934e04225SDavid du Colombier static void
msgWrite(void * v)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
426d7aba6c3SDavid du Colombier threadsetname("msgWrite");
42734e04225SDavid du Colombier
42834e04225SDavid du Colombier con = v;
429d7aba6c3SDavid 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 */
438d7aba6c3SDavid du Colombier qlock(&con->wlock);
43934e04225SDavid du Colombier while(con->whead == nil)
440d7aba6c3SDavid 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);
445d7aba6c3SDavid 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 */
453d7aba6c3SDavid 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;
463d7aba6c3SDavid 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
469d7aba6c3SDavid 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 }
479d7aba6c3SDavid du Colombier qunlock(&con->mlock);
48034e04225SDavid du Colombier
481d7aba6c3SDavid 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)
487d7aba6c3SDavid du Colombier rwakeup(&con->rendez);
48834e04225SDavid du Colombier if(con->state == ConMoribund && con->mhead == nil){
489d7aba6c3SDavid du Colombier qunlock(&con->lock);
49034e04225SDavid du Colombier conFree(con);
49134e04225SDavid du Colombier break;
49234e04225SDavid du Colombier }
493d7aba6c3SDavid du Colombier qunlock(&con->lock);
49434e04225SDavid du Colombier }
4955e96a66cSDavid du Colombier }
4965e96a66cSDavid du Colombier
4975e96a66cSDavid du Colombier Con*
conAlloc(int fd,char * name,int flags)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
504d7aba6c3SDavid 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++;
508d7aba6c3SDavid du Colombier rsleep(&cbox.arendez);
50934e04225SDavid du Colombier continue;
5105e96a66cSDavid du Colombier }
511d7aba6c3SDavid du Colombier con = vtmallocz(sizeof(Con));
512d7aba6c3SDavid du Colombier con->rendez.l = &con->lock;
513d7aba6c3SDavid du Colombier con->data = vtmalloc(cbox.msize);
5145e96a66cSDavid du Colombier con->msize = cbox.msize;
515d7aba6c3SDavid du Colombier con->mrendez.l = &con->mlock;
516d7aba6c3SDavid 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){
544d7aba6c3SDavid du Colombier vtfree(con->name);
5455e96a66cSDavid du Colombier con->name = nil;
5465e96a66cSDavid du Colombier }
5475e96a66cSDavid du Colombier if(name != nil)
548d7aba6c3SDavid du Colombier con->name = vtstrdup(name);
54934e04225SDavid du Colombier else
550d7aba6c3SDavid 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;
565d7aba6c3SDavid du Colombier qunlock(&cbox.alock);
5665e96a66cSDavid du Colombier
567d7aba6c3SDavid 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
cmdMsg(int argc,char * argv[])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
607d7aba6c3SDavid 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;
613d7aba6c3SDavid du Colombier qunlock(&mbox.alock);
61434e04225SDavid du Colombier
615d7aba6c3SDavid 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;
621d7aba6c3SDavid 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
scmp(Fid * a,Fid * b)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*
fidMerge(Fid * a,Fid * b)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*
fidMergeSort(Fid * f)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
cmdWho(int argc,char * argv[])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
708d7aba6c3SDavid 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);
719d7aba6c3SDavid 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);
732d7aba6c3SDavid du Colombier qunlock(&con->fidlock);
73381cf8742SDavid du Colombier consPrint("\n");
73481cf8742SDavid du Colombier }
735d7aba6c3SDavid du Colombier runlock(&cbox.clock);
73681cf8742SDavid du Colombier return 1;
73781cf8742SDavid du Colombier }
73881cf8742SDavid du Colombier
7395e96a66cSDavid du Colombier void
msgInit(void)74034e04225SDavid du Colombier msgInit(void)
7415e96a66cSDavid du Colombier {
742d7aba6c3SDavid du Colombier mbox.arendez.l = &mbox.alock;
74334e04225SDavid du Colombier
744d7aba6c3SDavid 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
cmdCon(int argc,char * argv[])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
778d7aba6c3SDavid 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;
784d7aba6c3SDavid 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
789d7aba6c3SDavid 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 }
793d7aba6c3SDavid du Colombier runlock(&cbox.clock);
79434e04225SDavid du Colombier
79534e04225SDavid du Colombier return 1;
79634e04225SDavid du Colombier }
79734e04225SDavid du Colombier
79834e04225SDavid du Colombier void
conInit(void)79934e04225SDavid du Colombier conInit(void)
80034e04225SDavid du Colombier {
801d7aba6c3SDavid 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