xref: /plan9/sys/src/cmd/fossil/9proc.c (revision 2cca75a1b2b8c6083390679d69d5c50cf66d9a01)
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