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