xref: /plan9-contrib/sys/src/cmd/fossil/9proc.c (revision fe853e2326f51910bb38886e9bfc22ecdef993d7)
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,
9*fe853e23SDavid du Colombier 	NMsgInit	= 384,
10*fe853e23SDavid 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
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;
655e96a66cSDavid du Colombier 
6634e04225SDavid du Colombier 	vtLock(cbox.alock);
6734e04225SDavid du Colombier 	if(con->cprev != nil)
6834e04225SDavid du Colombier 		con->cprev->cnext = con->cnext;
6934e04225SDavid du Colombier 	else
7034e04225SDavid du Colombier 		cbox.chead = con->cnext;
7134e04225SDavid du Colombier 	if(con->cnext != nil)
7234e04225SDavid du Colombier 		con->cnext->cprev = con->cprev;
7334e04225SDavid du Colombier 	else
7434e04225SDavid du Colombier 		cbox.ctail = con->cprev;
7534e04225SDavid du Colombier 	con->cprev = con->cnext = nil;
765e96a66cSDavid du Colombier 
7734e04225SDavid du Colombier 	if(cbox.ncon > cbox.maxcon){
7834e04225SDavid du Colombier 		if(con->name != nil)
7934e04225SDavid du Colombier 			vtMemFree(con->name);
8034e04225SDavid du Colombier 		vtLockFree(con->fidlock);
8134e04225SDavid du Colombier 		vtMemFree(con->data);
82c366c7d4SDavid du Colombier 		vtRendezFree(con->wrendez);
8334e04225SDavid du Colombier 		vtLockFree(con->wlock);
84c366c7d4SDavid du Colombier 		vtRendezFree(con->mrendez);
8534e04225SDavid du Colombier 		vtLockFree(con->mlock);
86c366c7d4SDavid du Colombier 		vtRendezFree(con->rendez);
8734e04225SDavid du Colombier 		vtLockFree(con->lock);
8834e04225SDavid du Colombier 		vtMemFree(con);
8934e04225SDavid du Colombier 		cbox.ncon--;
9034e04225SDavid du Colombier 		vtUnlock(cbox.alock);
9134e04225SDavid du Colombier 		return;
9234e04225SDavid du Colombier 	}
9334e04225SDavid du Colombier 	con->anext = cbox.ahead;
9434e04225SDavid du Colombier 	cbox.ahead = con;
9534e04225SDavid du Colombier 	if(con->anext == nil)
9634e04225SDavid du Colombier 		vtWakeup(cbox.arendez);
9734e04225SDavid du Colombier 	vtUnlock(cbox.alock);
9834e04225SDavid du Colombier }
9934e04225SDavid du Colombier 
10034e04225SDavid du Colombier static void
10134e04225SDavid du Colombier msgFree(Msg* m)
10234e04225SDavid du Colombier {
10334e04225SDavid du Colombier 	assert(m->rwnext == nil);
1047f1bc48aSDavid du Colombier 	assert(m->flush == nil);
10534e04225SDavid du Colombier 
10634e04225SDavid du Colombier 	vtLock(mbox.alock);
10734e04225SDavid du Colombier 	if(mbox.nmsg > mbox.maxmsg){
10834e04225SDavid du Colombier 		vtMemFree(m->data);
10934e04225SDavid du Colombier 		vtMemFree(m);
11034e04225SDavid du Colombier 		mbox.nmsg--;
11134e04225SDavid du Colombier 		vtUnlock(mbox.alock);
11234e04225SDavid du Colombier 		return;
11334e04225SDavid du Colombier 	}
11434e04225SDavid du Colombier 	m->anext = mbox.ahead;
11534e04225SDavid du Colombier 	mbox.ahead = m;
11634e04225SDavid du Colombier 	if(m->anext == nil)
11734e04225SDavid du Colombier 		vtWakeup(mbox.arendez);
11834e04225SDavid du Colombier 	vtUnlock(mbox.alock);
11934e04225SDavid du Colombier }
12034e04225SDavid du Colombier 
12134e04225SDavid du Colombier static Msg*
12234e04225SDavid du Colombier msgAlloc(Con* con)
12334e04225SDavid du Colombier {
12434e04225SDavid du Colombier 	Msg *m;
12534e04225SDavid du Colombier 
12634e04225SDavid du Colombier 	vtLock(mbox.alock);
12734e04225SDavid du Colombier 	while(mbox.ahead == nil){
12834e04225SDavid du Colombier 		if(mbox.nmsg >= mbox.maxmsg){
12934e04225SDavid du Colombier 			mbox.nmsgstarve++;
13034e04225SDavid du Colombier 			vtSleep(mbox.arendez);
13134e04225SDavid du Colombier 			continue;
13234e04225SDavid du Colombier 		}
13334e04225SDavid du Colombier 		m = vtMemAllocZ(sizeof(Msg));
13434e04225SDavid du Colombier 		m->data = vtMemAlloc(mbox.msize);
13534e04225SDavid du Colombier 		m->msize = mbox.msize;
13634e04225SDavid du Colombier 		mbox.nmsg++;
13734e04225SDavid du Colombier 		mbox.ahead = m;
13834e04225SDavid du Colombier 		break;
13934e04225SDavid du Colombier 	}
14034e04225SDavid du Colombier 	m = mbox.ahead;
14134e04225SDavid du Colombier 	mbox.ahead = m->anext;
14234e04225SDavid du Colombier 	m->anext = nil;
14334e04225SDavid du Colombier 	vtUnlock(mbox.alock);
14434e04225SDavid du Colombier 
14534e04225SDavid du Colombier 	m->con = con;
14634e04225SDavid du Colombier 	m->state = MsgR;
1477f1bc48aSDavid du Colombier 	m->nowq = 0;
14834e04225SDavid du Colombier 
14934e04225SDavid du Colombier 	return m;
15034e04225SDavid du Colombier }
15134e04225SDavid du Colombier 
15234e04225SDavid du Colombier static void
15334e04225SDavid du Colombier msgMunlink(Msg* m)
15434e04225SDavid du Colombier {
15534e04225SDavid du Colombier 	Con *con;
15634e04225SDavid du Colombier 
15734e04225SDavid du Colombier 	con = m->con;
15834e04225SDavid du Colombier 
15934e04225SDavid du Colombier 	if(m->mprev != nil)
16034e04225SDavid du Colombier 		m->mprev->mnext = m->mnext;
16134e04225SDavid du Colombier 	else
16234e04225SDavid du Colombier 		con->mhead = m->mnext;
16334e04225SDavid du Colombier 	if(m->mnext != nil)
16434e04225SDavid du Colombier 		m->mnext->mprev = m->mprev;
16534e04225SDavid du Colombier 	else
16634e04225SDavid du Colombier 		con->mtail = m->mprev;
16734e04225SDavid du Colombier 	m->mprev = m->mnext = nil;
16834e04225SDavid du Colombier }
16934e04225SDavid du Colombier 
17034e04225SDavid du Colombier void
17134e04225SDavid du Colombier msgFlush(Msg* m)
17234e04225SDavid du Colombier {
17334e04225SDavid du Colombier 	Con *con;
1747f1bc48aSDavid du Colombier 	Msg *flush, *old;
17534e04225SDavid du Colombier 
17634e04225SDavid du Colombier 	con = m->con;
17734e04225SDavid du Colombier 
17828495efeSDavid du Colombier 	if(Dflag)
17939734e7eSDavid du Colombier 		fprint(2, "msgFlush %F\n", &m->t);
18039734e7eSDavid du Colombier 
18134e04225SDavid du Colombier 	/*
18228495efeSDavid du Colombier 	 * If this Tflush has been flushed, nothing to do.
18334e04225SDavid du Colombier 	 * Look for the message to be flushed in the
18434e04225SDavid du Colombier 	 * queue of all messages still on this connection.
18528495efeSDavid du Colombier 	 * If it's not found must assume Elvis has already
18628495efeSDavid du Colombier 	 * left the building and reply normally.
18734e04225SDavid du Colombier 	 */
18834e04225SDavid du Colombier 	vtLock(con->mlock);
18928495efeSDavid du Colombier 	if(m->state == MsgF){
19028495efeSDavid du Colombier 		vtUnlock(con->mlock);
19128495efeSDavid du Colombier 		return;
19228495efeSDavid du Colombier 	}
19334e04225SDavid du Colombier 	for(old = con->mhead; old != nil; old = old->mnext)
19434e04225SDavid du Colombier 		if(old->t.tag == m->t.oldtag)
19534e04225SDavid du Colombier 			break;
19634e04225SDavid du Colombier 	if(old == nil){
19734e04225SDavid du Colombier 		if(Dflag)
19834e04225SDavid du Colombier 			fprint(2, "msgFlush: cannot find %d\n", m->t.oldtag);
19934e04225SDavid du Colombier 		vtUnlock(con->mlock);
20034e04225SDavid du Colombier 		return;
20134e04225SDavid du Colombier 	}
20234e04225SDavid du Colombier 
20328495efeSDavid du Colombier 	if(Dflag)
20439734e7eSDavid du Colombier 		fprint(2, "\tmsgFlush found %F\n", &old->t);
20539734e7eSDavid du Colombier 
20634e04225SDavid du Colombier 	/*
20734e04225SDavid du Colombier 	 * Found it.
20828495efeSDavid du Colombier 	 * There are two cases where the old message can be
20928495efeSDavid du Colombier 	 * truly flushed and no reply to the original message given.
21028495efeSDavid du Colombier 	 * The first is when the old message is in MsgR state; no
21128495efeSDavid du Colombier 	 * processing has been done yet and it is still on the read
21228495efeSDavid du Colombier 	 * queue. The second is if old is a Tflush, which doesn't
21328495efeSDavid du Colombier 	 * affect the server state. In both cases, put the old
2147f1bc48aSDavid du Colombier 	 * message into MsgF state and let MsgWrite toss it after
2157f1bc48aSDavid du Colombier 	 * pulling it off the queue.
21634e04225SDavid du Colombier 	 */
21728495efeSDavid du Colombier 	if(old->state == MsgR || old->t.type == Tflush){
21834e04225SDavid du Colombier 		old->state = MsgF;
21934e04225SDavid du Colombier 		if(Dflag)
22028495efeSDavid du Colombier 			fprint(2, "msgFlush: change %d from MsgR to MsgF\n",
22128495efeSDavid du Colombier 				m->t.oldtag);
22234e04225SDavid du Colombier 	}
22334e04225SDavid du Colombier 
22434e04225SDavid du Colombier 	/*
22528495efeSDavid du Colombier 	 * Link this flush message and the old message
2267f1bc48aSDavid du Colombier 	 * so multiple flushes can be coalesced (if there are
22728495efeSDavid du Colombier 	 * multiple Tflush messages for a particular pending
22828495efeSDavid du Colombier 	 * request, it is only necessary to respond to the last
22928495efeSDavid du Colombier 	 * one, so any previous can be removed) and to be
23028495efeSDavid du Colombier 	 * sure flushes wait for their corresponding old
23128495efeSDavid du Colombier 	 * message to go out first.
2327f1bc48aSDavid du Colombier 	 * Waiting flush messages do not go on the write queue,
2337f1bc48aSDavid du Colombier 	 * they are processed after the old message is dealt
2347f1bc48aSDavid du Colombier 	 * with. There's no real need to protect the setting of
2357f1bc48aSDavid du Colombier 	 * Msg.nowq, the only code to check it runs in this
2367f1bc48aSDavid du Colombier 	 * process after this routine returns.
23734e04225SDavid du Colombier 	 */
2387f1bc48aSDavid du Colombier 	if((flush = old->flush) != nil){
23934e04225SDavid du Colombier 		if(Dflag)
24028495efeSDavid du Colombier 			fprint(2, "msgFlush: remove %d from %d list\n",
2417f1bc48aSDavid du Colombier 				old->flush->t.tag, old->t.tag);
2427f1bc48aSDavid du Colombier 		m->flush = flush->flush;
2437f1bc48aSDavid du Colombier 		flush->flush = nil;
2447f1bc48aSDavid du Colombier 		msgMunlink(flush);
2457f1bc48aSDavid du Colombier 		msgFree(flush);
24634e04225SDavid du Colombier 	}
2477f1bc48aSDavid du Colombier 	old->flush = m;
2487f1bc48aSDavid du Colombier 	m->nowq = 1;
24934e04225SDavid du Colombier 
25034e04225SDavid du Colombier 	if(Dflag)
25128495efeSDavid du Colombier 		fprint(2, "msgFlush: add %d to %d queue\n",
25228495efeSDavid du Colombier 			m->t.tag, old->t.tag);
25334e04225SDavid du Colombier 	vtUnlock(con->mlock);
2545e96a66cSDavid du Colombier }
2555e96a66cSDavid du Colombier 
2565e96a66cSDavid du Colombier static void
2575e96a66cSDavid du Colombier msgProc(void*)
2585e96a66cSDavid du Colombier {
2595e96a66cSDavid du Colombier 	Msg *m;
2605e96a66cSDavid du Colombier 	char *e;
2615e96a66cSDavid du Colombier 	Con *con;
2625e96a66cSDavid du Colombier 
26334e04225SDavid du Colombier 	vtThreadSetName("msgProc");
2645e96a66cSDavid du Colombier 
26534e04225SDavid du Colombier 	for(;;){
26634e04225SDavid du Colombier 		/*
26734e04225SDavid du Colombier 		 * If surplus to requirements, exit.
26834e04225SDavid du Colombier 		 * If not, wait for and pull a message off
26934e04225SDavid du Colombier 		 * the read queue.
27034e04225SDavid du Colombier 		 */
27134e04225SDavid du Colombier 		vtLock(mbox.rlock);
27234e04225SDavid du Colombier 		if(mbox.nproc > mbox.maxproc){
27334e04225SDavid du Colombier 			mbox.nproc--;
27434e04225SDavid du Colombier 			vtUnlock(mbox.rlock);
27534e04225SDavid du Colombier 			break;
27634e04225SDavid du Colombier 		}
27734e04225SDavid du Colombier 		while(mbox.rhead == nil)
27834e04225SDavid du Colombier 			vtSleep(mbox.rrendez);
27934e04225SDavid du Colombier 		m = mbox.rhead;
28034e04225SDavid du Colombier 		mbox.rhead = m->rwnext;
28134e04225SDavid du Colombier 		m->rwnext = nil;
28234e04225SDavid du Colombier 		vtUnlock(mbox.rlock);
2835e96a66cSDavid du Colombier 
2845e96a66cSDavid du Colombier 		con = m->con;
28534e04225SDavid du Colombier 		e = nil;
2865e96a66cSDavid du Colombier 
28734e04225SDavid du Colombier 		/*
28828495efeSDavid du Colombier 		 * If the message has been flushed before
28928495efeSDavid du Colombier 		 * any 9P processing has started, mark it so
29028495efeSDavid du Colombier 		 * none will be attempted.
29134e04225SDavid du Colombier 		 */
29234e04225SDavid du Colombier 		vtLock(con->mlock);
29328495efeSDavid du Colombier 		if(m->state == MsgF)
29428495efeSDavid du Colombier 			e = "flushed";
29528495efeSDavid du Colombier 		else
29634e04225SDavid du Colombier 			m->state = Msg9;
29734e04225SDavid du Colombier 		vtUnlock(con->mlock);
29834e04225SDavid du Colombier 
29928495efeSDavid du Colombier 		if(e == nil){
30034e04225SDavid du Colombier 			/*
30134e04225SDavid du Colombier 			 * explain this
30234e04225SDavid du Colombier 			 */
30334e04225SDavid du Colombier 			vtLock(con->lock);
3045e96a66cSDavid du Colombier 			if(m->t.type == Tversion){
3055e96a66cSDavid du Colombier 				con->version = m;
30634e04225SDavid du Colombier 				con->state = ConDown;
30734e04225SDavid du Colombier 				while(con->mhead != m)
30834e04225SDavid du Colombier 					vtSleep(con->rendez);
30934e04225SDavid du Colombier 				assert(con->state == ConDown);
3105e96a66cSDavid du Colombier 				if(con->version == m){
3115e96a66cSDavid du Colombier 					con->version = nil;
31234e04225SDavid du Colombier 					con->state = ConInit;
3135e96a66cSDavid du Colombier 				}
3145e96a66cSDavid du Colombier 				else
3155e96a66cSDavid du Colombier 					e = "Tversion aborted";
3165e96a66cSDavid du Colombier 			}
31734e04225SDavid du Colombier 			else if(con->state != ConUp)
3185e96a66cSDavid du Colombier 				e = "connection not ready";
3195e96a66cSDavid du Colombier 			vtUnlock(con->lock);
32028495efeSDavid du Colombier 		}
3215e96a66cSDavid du Colombier 
3225e96a66cSDavid du Colombier 		/*
3235e96a66cSDavid du Colombier 		 * Dispatch if not error already.
3245e96a66cSDavid du Colombier 		 */
3255e96a66cSDavid du Colombier 		m->r.tag = m->t.tag;
3265e96a66cSDavid du Colombier 		if(e == nil && !(*rFcall[m->t.type])(m))
3275e96a66cSDavid du Colombier 			e = vtGetError();
3285e96a66cSDavid du Colombier 		if(e != nil){
3295e96a66cSDavid du Colombier 			m->r.type = Rerror;
3305e96a66cSDavid du Colombier 			m->r.ename = e;
3315e96a66cSDavid du Colombier 		}
3325e96a66cSDavid du Colombier 		else
3335e96a66cSDavid du Colombier 			m->r.type = m->t.type+1;
3345e96a66cSDavid du Colombier 
3355e96a66cSDavid du Colombier 		/*
33634e04225SDavid du Colombier 		 * Put the message (with reply) on the
33734e04225SDavid du Colombier 		 * write queue and wakeup the write process.
3385e96a66cSDavid du Colombier 		 */
3397f1bc48aSDavid du Colombier 		if(!m->nowq){
34034e04225SDavid du Colombier 			vtLock(con->wlock);
34134e04225SDavid du Colombier 			if(con->whead == nil)
34234e04225SDavid du Colombier 				con->whead = m;
3435e96a66cSDavid du Colombier 			else
34434e04225SDavid du Colombier 				con->wtail->rwnext = m;
34534e04225SDavid du Colombier 			con->wtail = m;
34634e04225SDavid du Colombier 			vtWakeup(con->wrendez);
34734e04225SDavid du Colombier 			vtUnlock(con->wlock);
3485e96a66cSDavid du Colombier 		}
3495e96a66cSDavid du Colombier 	}
3507f1bc48aSDavid du Colombier }
3515e96a66cSDavid du Colombier 
3525e96a66cSDavid du Colombier static void
35334e04225SDavid du Colombier msgRead(void* v)
3545e96a66cSDavid du Colombier {
3555e96a66cSDavid du Colombier 	Msg *m;
3565e96a66cSDavid du Colombier 	Con *con;
3575e96a66cSDavid du Colombier 	int eof, fd, n;
3585e96a66cSDavid du Colombier 
35934e04225SDavid du Colombier 	vtThreadSetName("msgRead");
3605e96a66cSDavid du Colombier 
3615e96a66cSDavid du Colombier 	con = v;
3625e96a66cSDavid du Colombier 	fd = con->fd;
3635e96a66cSDavid du Colombier 	eof = 0;
3645e96a66cSDavid du Colombier 
3655e96a66cSDavid du Colombier 	while(!eof){
36634e04225SDavid du Colombier 		m = msgAlloc(con);
3675e96a66cSDavid du Colombier 
3685e96a66cSDavid du Colombier 		while((n = read9pmsg(fd, m->data, con->msize)) == 0)
3695e96a66cSDavid du Colombier 			;
3705e96a66cSDavid du Colombier 		if(n < 0){
3715e96a66cSDavid du Colombier 			m->t.type = Tversion;
3725e96a66cSDavid du Colombier 			m->t.fid = NOFID;
3735e96a66cSDavid du Colombier 			m->t.tag = NOTAG;
3745e96a66cSDavid du Colombier 			m->t.msize = con->msize;
3755e96a66cSDavid du Colombier 			m->t.version = "9PEoF";
3765e96a66cSDavid du Colombier 			eof = 1;
3775e96a66cSDavid du Colombier 		}
3785e96a66cSDavid du Colombier 		else if(convM2S(m->data, n, &m->t) != n){
3795e96a66cSDavid du Colombier 			if(Dflag)
38034e04225SDavid du Colombier 				fprint(2, "msgRead: convM2S error: %s\n",
3815e96a66cSDavid du Colombier 					con->name);
3825e96a66cSDavid du Colombier 			msgFree(m);
3835e96a66cSDavid du Colombier 			continue;
3845e96a66cSDavid du Colombier 		}
3855e96a66cSDavid du Colombier 		if(Dflag)
38639734e7eSDavid du Colombier 			fprint(2, "msgRead %p: t %F\n", con, &m->t);
3875e96a66cSDavid du Colombier 
38834e04225SDavid du Colombier 		vtLock(con->mlock);
38934e04225SDavid du Colombier 		if(con->mtail != nil){
39034e04225SDavid du Colombier 			m->mprev = con->mtail;
39134e04225SDavid du Colombier 			con->mtail->mnext = m;
39234e04225SDavid du Colombier 		}
39334e04225SDavid du Colombier 		else{
39434e04225SDavid du Colombier 			con->mhead = m;
39534e04225SDavid du Colombier 			m->mprev = nil;
39634e04225SDavid du Colombier 		}
39734e04225SDavid du Colombier 		con->mtail = m;
39834e04225SDavid du Colombier 		vtUnlock(con->mlock);
39934e04225SDavid du Colombier 
40034e04225SDavid du Colombier 		vtLock(mbox.rlock);
40134e04225SDavid du Colombier 		if(mbox.rhead == nil){
40234e04225SDavid du Colombier 			mbox.rhead = m;
40334e04225SDavid du Colombier 			if(!vtWakeup(mbox.rrendez)){
40434e04225SDavid du Colombier 				if(mbox.nproc < mbox.maxproc){
4055e96a66cSDavid du Colombier 					if(vtThread(msgProc, nil) > 0)
4065e96a66cSDavid du Colombier 						mbox.nproc++;
4075e96a66cSDavid du Colombier 				}
40834e04225SDavid du Colombier 				else
40934e04225SDavid du Colombier 					mbox.nprocstarve++;
41034e04225SDavid du Colombier 			}
41134e04225SDavid du Colombier 			/*
41234e04225SDavid du Colombier 			 * don't need this surely?
41334e04225SDavid du Colombier 			vtWakeup(mbox.rrendez);
41434e04225SDavid du Colombier 			 */
4155e96a66cSDavid du Colombier 		}
4165e96a66cSDavid du Colombier 		else
41734e04225SDavid du Colombier 			mbox.rtail->rwnext = m;
41834e04225SDavid du Colombier 		mbox.rtail = m;
41934e04225SDavid du Colombier 		vtUnlock(mbox.rlock);
4205e96a66cSDavid du Colombier 	}
42134e04225SDavid du Colombier }
42234e04225SDavid du Colombier 
42334e04225SDavid du Colombier static void
42434e04225SDavid du Colombier msgWrite(void* v)
42534e04225SDavid du Colombier {
42634e04225SDavid du Colombier 	Con *con;
4277f1bc48aSDavid du Colombier 	int eof, n;
4287f1bc48aSDavid du Colombier 	Msg *flush, *m;
42934e04225SDavid du Colombier 
43034e04225SDavid du Colombier 	vtThreadSetName("msgWrite");
43134e04225SDavid du Colombier 
43234e04225SDavid du Colombier 	con = v;
43334e04225SDavid du Colombier 	if(vtThread(msgRead, con) < 0){
43434e04225SDavid du Colombier 		conFree(con);
43534e04225SDavid du Colombier 		return;
43634e04225SDavid du Colombier 	}
43734e04225SDavid du Colombier 
43834e04225SDavid du Colombier 	for(;;){
43934e04225SDavid du Colombier 		/*
44034e04225SDavid du Colombier 		 * Wait for and pull a message off the write queue.
44134e04225SDavid du Colombier 		 */
44234e04225SDavid du Colombier 		vtLock(con->wlock);
44334e04225SDavid du Colombier 		while(con->whead == nil)
44434e04225SDavid du Colombier 			vtSleep(con->wrendez);
44534e04225SDavid du Colombier 		m = con->whead;
44634e04225SDavid du Colombier 		con->whead = m->rwnext;
44734e04225SDavid du Colombier 		m->rwnext = nil;
4487f1bc48aSDavid du Colombier 		assert(!m->nowq);
44934e04225SDavid du Colombier 		vtUnlock(con->wlock);
45034e04225SDavid du Colombier 
4517f1bc48aSDavid du Colombier 		eof = 0;
4527f1bc48aSDavid du Colombier 
45334e04225SDavid du Colombier 		/*
4547f1bc48aSDavid du Colombier 		 * Write each message (if it hasn't been flushed)
4557f1bc48aSDavid du Colombier 		 * followed by any messages waiting for it to complete.
45634e04225SDavid du Colombier 		 */
45734e04225SDavid du Colombier 		vtLock(con->mlock);
4587f1bc48aSDavid du Colombier 		while(m != nil){
4597f1bc48aSDavid du Colombier 			msgMunlink(m);
4607f1bc48aSDavid du Colombier 
4617f1bc48aSDavid du Colombier 			if(Dflag)
4627f1bc48aSDavid du Colombier 				fprint(2, "msgWrite %d: r %F\n",
4637f1bc48aSDavid du Colombier 					m->state, &m->r);
4647f1bc48aSDavid du Colombier 
4657f1bc48aSDavid du Colombier 			if(m->state != MsgF){
46634e04225SDavid du Colombier 				m->state = MsgW;
4677f1bc48aSDavid du Colombier 				vtUnlock(con->mlock);
4687f1bc48aSDavid du Colombier 
4697f1bc48aSDavid du Colombier 				n = convS2M(&m->r, con->data, con->msize);
4707f1bc48aSDavid du Colombier 				if(write(con->fd, con->data, n) != n)
4717f1bc48aSDavid du Colombier 					eof = 1;
4727f1bc48aSDavid du Colombier 
4737f1bc48aSDavid du Colombier 				vtLock(con->mlock);
4747f1bc48aSDavid du Colombier 			}
4757f1bc48aSDavid du Colombier 
4767f1bc48aSDavid du Colombier 			if((flush = m->flush) != nil){
4777f1bc48aSDavid du Colombier 				assert(flush->nowq);
4787f1bc48aSDavid du Colombier 				m->flush = nil;
4797f1bc48aSDavid du Colombier 			}
4807f1bc48aSDavid du Colombier 			msgFree(m);
4817f1bc48aSDavid du Colombier 			m = flush;
4827f1bc48aSDavid du Colombier 		}
48334e04225SDavid du Colombier 		vtUnlock(con->mlock);
48434e04225SDavid du Colombier 
48534e04225SDavid du Colombier 		vtLock(con->lock);
48634e04225SDavid du Colombier 		if(eof && con->fd >= 0){
48734e04225SDavid du Colombier 			close(con->fd);
48834e04225SDavid du Colombier 			con->fd = -1;
48934e04225SDavid du Colombier 		}
49034e04225SDavid du Colombier 		if(con->state == ConDown)
49134e04225SDavid du Colombier 			vtWakeup(con->rendez);
49234e04225SDavid du Colombier 		if(con->state == ConMoribund && con->mhead == nil){
49334e04225SDavid du Colombier 			vtUnlock(con->lock);
49434e04225SDavid du Colombier 			conFree(con);
49534e04225SDavid du Colombier 			break;
49634e04225SDavid du Colombier 		}
49734e04225SDavid du Colombier 		vtUnlock(con->lock);
49834e04225SDavid du Colombier 	}
4995e96a66cSDavid du Colombier }
5005e96a66cSDavid du Colombier 
5015e96a66cSDavid du Colombier Con*
5025e96a66cSDavid du Colombier conAlloc(int fd, char* name)
5035e96a66cSDavid du Colombier {
5045e96a66cSDavid du Colombier 	Con *con;
5055e96a66cSDavid du Colombier 
50634e04225SDavid du Colombier 	vtLock(cbox.alock);
50734e04225SDavid du Colombier 	while(cbox.ahead == nil){
50834e04225SDavid du Colombier 		if(cbox.ncon >= cbox.maxcon){
50934e04225SDavid du Colombier 			cbox.nconstarve++;
51034e04225SDavid du Colombier 			vtSleep(cbox.arendez);
51134e04225SDavid du Colombier 			continue;
5125e96a66cSDavid du Colombier 		}
5135e96a66cSDavid du Colombier 		con = vtMemAllocZ(sizeof(Con));
5145e96a66cSDavid du Colombier 		con->lock = vtLockAlloc();
51534e04225SDavid du Colombier 		con->rendez = vtRendezAlloc(con->lock);
5165e96a66cSDavid du Colombier 		con->data = vtMemAlloc(cbox.msize);
5175e96a66cSDavid du Colombier 		con->msize = cbox.msize;
51834e04225SDavid du Colombier 		con->alock = vtLockAlloc();
51934e04225SDavid du Colombier 		con->mlock = vtLockAlloc();
52034e04225SDavid du Colombier 		con->mrendez = vtRendezAlloc(con->mlock);
52134e04225SDavid du Colombier 		con->wlock = vtLockAlloc();
52234e04225SDavid du Colombier 		con->wrendez = vtRendezAlloc(con->wlock);
5235e96a66cSDavid du Colombier 		con->fidlock = vtLockAlloc();
52434e04225SDavid du Colombier 
52534e04225SDavid du Colombier 		cbox.ncon++;
52634e04225SDavid du Colombier 		cbox.ahead = con;
52734e04225SDavid du Colombier 		break;
5285e96a66cSDavid du Colombier 	}
52934e04225SDavid du Colombier 	con = cbox.ahead;
53034e04225SDavid du Colombier 	cbox.ahead = con->anext;
53134e04225SDavid du Colombier 	con->anext = nil;
53234e04225SDavid du Colombier 
53334e04225SDavid du Colombier 	if(cbox.ctail != nil){
53434e04225SDavid du Colombier 		con->cprev = cbox.ctail;
53534e04225SDavid du Colombier 		cbox.ctail->cnext = con;
53634e04225SDavid du Colombier 	}
53734e04225SDavid du Colombier 	else{
53834e04225SDavid du Colombier 		cbox.chead = con;
53934e04225SDavid du Colombier 		con->cprev = nil;
54034e04225SDavid du Colombier 	}
54134e04225SDavid du Colombier 	cbox.ctail = con;
54234e04225SDavid du Colombier 
5435e96a66cSDavid du Colombier 	assert(con->mhead == nil);
54434e04225SDavid du Colombier 	assert(con->whead == nil);
5455e96a66cSDavid du Colombier 	assert(con->fhead == nil);
5465e96a66cSDavid du Colombier 	assert(con->nfid == 0);
5475e96a66cSDavid du Colombier 
54834e04225SDavid du Colombier 	con->state = ConNew;
5495e96a66cSDavid du Colombier 	con->fd = fd;
5505e96a66cSDavid du Colombier 	if(con->name != nil){
5515e96a66cSDavid du Colombier 		vtMemFree(con->name);
5525e96a66cSDavid du Colombier 		con->name = nil;
5535e96a66cSDavid du Colombier 	}
5545e96a66cSDavid du Colombier 	if(name != nil)
5555e96a66cSDavid du Colombier 		con->name = vtStrDup(name);
55634e04225SDavid du Colombier 	else
55734e04225SDavid du Colombier 		con->name = vtStrDup("unknown");
5585e96a66cSDavid du Colombier 	con->aok = 0;
55934e04225SDavid du Colombier 	vtUnlock(cbox.alock);
5605e96a66cSDavid du Colombier 
56134e04225SDavid du Colombier 	if(vtThread(msgWrite, con) < 0){
5625e96a66cSDavid du Colombier 		conFree(con);
5635e96a66cSDavid du Colombier 		return nil;
5645e96a66cSDavid du Colombier 	}
5655e96a66cSDavid du Colombier 
5665e96a66cSDavid du Colombier 	return con;
5675e96a66cSDavid du Colombier }
5685e96a66cSDavid du Colombier 
5695e96a66cSDavid du Colombier static int
5705e96a66cSDavid du Colombier cmdMsg(int argc, char* argv[])
5715e96a66cSDavid du Colombier {
5725e96a66cSDavid du Colombier 	char *p;
5735e96a66cSDavid du Colombier 	char *usage = "usage: msg [-m nmsg] [-p nproc]";
57434e04225SDavid du Colombier 	int maxmsg, nmsg, nmsgstarve, maxproc, nproc, nprocstarve;
5755e96a66cSDavid du Colombier 
5765e96a66cSDavid du Colombier 	maxmsg = maxproc = 0;
5775e96a66cSDavid du Colombier 
5785e96a66cSDavid du Colombier 	ARGBEGIN{
5795e96a66cSDavid du Colombier 	default:
5805e96a66cSDavid du Colombier 		return cliError(usage);
5815e96a66cSDavid du Colombier 	case 'm':
5825e96a66cSDavid du Colombier 		p = ARGF();
5835e96a66cSDavid du Colombier 		if(p == nil)
5845e96a66cSDavid du Colombier 			return cliError(usage);
5855e96a66cSDavid du Colombier 		maxmsg = strtol(argv[0], &p, 0);
5865e96a66cSDavid du Colombier 		if(maxmsg <= 0 || p == argv[0] || *p != '\0')
5875e96a66cSDavid du Colombier 			return cliError(usage);
5885e96a66cSDavid du Colombier 		break;
5895e96a66cSDavid du Colombier 	case 'p':
5905e96a66cSDavid du Colombier 		p = ARGF();
5915e96a66cSDavid du Colombier 		if(p == nil)
5925e96a66cSDavid du Colombier 			return cliError(usage);
5935e96a66cSDavid du Colombier 		maxproc = strtol(argv[0], &p, 0);
5945e96a66cSDavid du Colombier 		if(maxproc <= 0 || p == argv[0] || *p != '\0')
5955e96a66cSDavid du Colombier 			return cliError(usage);
5965e96a66cSDavid du Colombier 		break;
5975e96a66cSDavid du Colombier 	}ARGEND
5985e96a66cSDavid du Colombier 	if(argc)
5995e96a66cSDavid du Colombier 		return cliError(usage);
6005e96a66cSDavid du Colombier 
60134e04225SDavid du Colombier 	vtLock(mbox.alock);
6025e96a66cSDavid du Colombier 	if(maxmsg)
6035e96a66cSDavid du Colombier 		mbox.maxmsg = maxmsg;
6045e96a66cSDavid du Colombier 	maxmsg = mbox.maxmsg;
60534e04225SDavid du Colombier 	nmsg = mbox.nmsg;
60634e04225SDavid du Colombier 	nmsgstarve = mbox.nmsgstarve;
60734e04225SDavid du Colombier 	vtUnlock(mbox.alock);
60834e04225SDavid du Colombier 
60934e04225SDavid du Colombier 	vtLock(mbox.rlock);
6105e96a66cSDavid du Colombier 	if(maxproc)
6115e96a66cSDavid du Colombier 		mbox.maxproc = maxproc;
6125e96a66cSDavid du Colombier 	maxproc = mbox.maxproc;
61334e04225SDavid du Colombier 	nproc = mbox.nproc;
61434e04225SDavid du Colombier 	nprocstarve = mbox.nprocstarve;
61534e04225SDavid du Colombier 	vtUnlock(mbox.rlock);
6165e96a66cSDavid du Colombier 
6175e96a66cSDavid du Colombier 	consPrint("\tmsg -m %d -p %d\n", maxmsg, maxproc);
61834e04225SDavid du Colombier 	consPrint("\tnmsg %d nmsgstarve %d nproc %d nprocstarve %d\n",
61934e04225SDavid du Colombier 		nmsg, nmsgstarve, nproc, nprocstarve);
6205e96a66cSDavid du Colombier 
6215e96a66cSDavid du Colombier 	return 1;
6225e96a66cSDavid du Colombier }
6235e96a66cSDavid du Colombier 
62481cf8742SDavid du Colombier static int
62581cf8742SDavid du Colombier scmp(Fid *a, Fid *b)
62681cf8742SDavid du Colombier {
62781cf8742SDavid du Colombier 	if(a == 0)
62881cf8742SDavid du Colombier 		return 1;
62981cf8742SDavid du Colombier 	if(b == 0)
63081cf8742SDavid du Colombier 		return -1;
63181cf8742SDavid du Colombier 	return strcmp(a->uname, b->uname);
63281cf8742SDavid du Colombier }
63381cf8742SDavid du Colombier 
63481cf8742SDavid du Colombier static Fid*
63581cf8742SDavid du Colombier fidMerge(Fid *a, Fid *b)
63681cf8742SDavid du Colombier {
63781cf8742SDavid du Colombier 	Fid *s, **l;
63881cf8742SDavid du Colombier 
63981cf8742SDavid du Colombier 	l = &s;
64081cf8742SDavid du Colombier 	while(a || b){
64181cf8742SDavid du Colombier 		if(scmp(a, b) < 0){
64281cf8742SDavid du Colombier 			*l = a;
64381cf8742SDavid du Colombier 			l = &a->sort;
64481cf8742SDavid du Colombier 			a = a->sort;
64581cf8742SDavid du Colombier 		}else{
64681cf8742SDavid du Colombier 			*l = b;
64781cf8742SDavid du Colombier 			l = &b->sort;
64881cf8742SDavid du Colombier 			b = b->sort;
64981cf8742SDavid du Colombier 		}
65081cf8742SDavid du Colombier 	}
65181cf8742SDavid du Colombier 	*l = 0;
65281cf8742SDavid du Colombier 	return s;
65381cf8742SDavid du Colombier }
65481cf8742SDavid du Colombier 
65581cf8742SDavid du Colombier static Fid*
65681cf8742SDavid du Colombier fidMergeSort(Fid *f)
65781cf8742SDavid du Colombier {
65881cf8742SDavid du Colombier 	int delay;
65981cf8742SDavid du Colombier 	Fid *a, *b;
66081cf8742SDavid du Colombier 
66181cf8742SDavid du Colombier 	if(f == nil)
66281cf8742SDavid du Colombier 		return nil;
66381cf8742SDavid du Colombier 	if(f->sort == nil)
66481cf8742SDavid du Colombier 		return f;
66581cf8742SDavid du Colombier 
66681cf8742SDavid du Colombier 	a = b = f;
66781cf8742SDavid du Colombier 	delay = 1;
66881cf8742SDavid du Colombier 	while(a && b){
66981cf8742SDavid du Colombier 		if(delay)	/* easy way to handle 2-element list */
67081cf8742SDavid du Colombier 			delay = 0;
67181cf8742SDavid du Colombier 		else
67281cf8742SDavid du Colombier 			a = a->sort;
67381cf8742SDavid du Colombier 		if(b = b->sort)
67481cf8742SDavid du Colombier 			b = b->sort;
67581cf8742SDavid du Colombier 	}
67681cf8742SDavid du Colombier 
67781cf8742SDavid du Colombier 	b = a->sort;
67881cf8742SDavid du Colombier 	a->sort = nil;
67981cf8742SDavid du Colombier 
68081cf8742SDavid du Colombier 	a = fidMergeSort(f);
68181cf8742SDavid du Colombier 	b = fidMergeSort(b);
68281cf8742SDavid du Colombier 
68381cf8742SDavid du Colombier 	return fidMerge(a, b);
68481cf8742SDavid du Colombier }
68581cf8742SDavid du Colombier 
68681cf8742SDavid du Colombier static int
68781cf8742SDavid du Colombier cmdWho(int argc, char* argv[])
68881cf8742SDavid du Colombier {
68981cf8742SDavid du Colombier 	char *usage = "usage: who";
69081cf8742SDavid du Colombier 	int i;
69181cf8742SDavid du Colombier 	Con *con;
69281cf8742SDavid du Colombier 	Fid *fid, *last;
69381cf8742SDavid du Colombier 
69481cf8742SDavid du Colombier 	ARGBEGIN{
69581cf8742SDavid du Colombier 	default:
69681cf8742SDavid du Colombier 		return cliError(usage);
69781cf8742SDavid du Colombier 	}ARGEND
69881cf8742SDavid du Colombier 
69981cf8742SDavid du Colombier 	if(argc > 0)
70081cf8742SDavid du Colombier 		return cliError(usage);
70181cf8742SDavid du Colombier 
70281cf8742SDavid du Colombier 	vtRLock(cbox.clock);
70381cf8742SDavid du Colombier 	for(con=cbox.chead; con; con=con->cnext){
70481cf8742SDavid du Colombier 		consPrint("\t%q:", con->name);
70581cf8742SDavid du Colombier 		vtLock(con->fidlock);
70681cf8742SDavid du Colombier 		last = nil;
70781cf8742SDavid du Colombier 		for(i=0; i<NFidHash; i++)
70881cf8742SDavid du Colombier 			for(fid=con->fidhash[i]; fid; fid=fid->hash)
70981cf8742SDavid du Colombier 				if(fid->fidno != NOFID && fid->uname){
71081cf8742SDavid du Colombier 					fid->sort = last;
71181cf8742SDavid du Colombier 					last = fid;
71281cf8742SDavid du Colombier 				}
71381cf8742SDavid du Colombier 		fid = fidMergeSort(last);
71481cf8742SDavid du Colombier 		last = nil;
71581cf8742SDavid du Colombier 		for(; fid; last=fid, fid=fid->sort)
71681cf8742SDavid du Colombier 			if(last==nil || strcmp(fid->uname, last->uname) != 0)
71781cf8742SDavid du Colombier 				consPrint(" %q", fid->uname);
71881cf8742SDavid du Colombier 		vtUnlock(con->fidlock);
71981cf8742SDavid du Colombier 		consPrint("\n");
72081cf8742SDavid du Colombier 	}
72181cf8742SDavid du Colombier 	vtRUnlock(cbox.clock);
72281cf8742SDavid du Colombier 	return 1;
72381cf8742SDavid du Colombier }
72481cf8742SDavid du Colombier 
7255e96a66cSDavid du Colombier void
72634e04225SDavid du Colombier msgInit(void)
7275e96a66cSDavid du Colombier {
72834e04225SDavid du Colombier 	mbox.alock = vtLockAlloc();
72934e04225SDavid du Colombier 	mbox.arendez = vtRendezAlloc(mbox.alock);
73034e04225SDavid du Colombier 
73134e04225SDavid du Colombier 	mbox.rlock = vtLockAlloc();
73234e04225SDavid du Colombier 	mbox.rrendez = vtRendezAlloc(mbox.rlock);
7335e96a66cSDavid du Colombier 
7345e96a66cSDavid du Colombier 	mbox.maxmsg = NMsgInit;
7355e96a66cSDavid du Colombier 	mbox.maxproc = NMsgProcInit;
7365e96a66cSDavid du Colombier 	mbox.msize = NMsizeInit;
7375e96a66cSDavid du Colombier 
7385e96a66cSDavid du Colombier 	cliAddCmd("msg", cmdMsg);
73934e04225SDavid du Colombier }
7405e96a66cSDavid du Colombier 
74134e04225SDavid du Colombier static int
74234e04225SDavid du Colombier cmdCon(int argc, char* argv[])
74334e04225SDavid du Colombier {
74434e04225SDavid du Colombier 	char *p;
74534e04225SDavid du Colombier 	Con *con;
74634e04225SDavid du Colombier 	char *usage = "usage: con [-m ncon]";
74734e04225SDavid du Colombier 	int maxcon, ncon, nconstarve;
74834e04225SDavid du Colombier 
74934e04225SDavid du Colombier 	maxcon = 0;
75034e04225SDavid du Colombier 
75134e04225SDavid du Colombier 	ARGBEGIN{
75234e04225SDavid du Colombier 	default:
75334e04225SDavid du Colombier 		return cliError(usage);
75434e04225SDavid du Colombier 	case 'm':
75534e04225SDavid du Colombier 		p = ARGF();
75634e04225SDavid du Colombier 		if(p == nil)
75734e04225SDavid du Colombier 			return cliError(usage);
75834e04225SDavid du Colombier 		maxcon = strtol(argv[0], &p, 0);
75934e04225SDavid du Colombier 		if(maxcon <= 0 || p == argv[0] || *p != '\0')
76034e04225SDavid du Colombier 			return cliError(usage);
76134e04225SDavid du Colombier 		break;
76234e04225SDavid du Colombier 	}ARGEND
76334e04225SDavid du Colombier 	if(argc)
76434e04225SDavid du Colombier 		return cliError(usage);
76534e04225SDavid du Colombier 
76634e04225SDavid du Colombier 	vtLock(cbox.clock);
76734e04225SDavid du Colombier 	if(maxcon)
76834e04225SDavid du Colombier 		cbox.maxcon = maxcon;
76934e04225SDavid du Colombier 	maxcon = cbox.maxcon;
77034e04225SDavid du Colombier 	ncon = cbox.ncon;
77134e04225SDavid du Colombier 	nconstarve = cbox.nconstarve;
77234e04225SDavid du Colombier 	vtUnlock(cbox.clock);
77334e04225SDavid du Colombier 
77434e04225SDavid du Colombier 	consPrint("\tcon -m %d\n", maxcon);
77534e04225SDavid du Colombier 	consPrint("\tncon %d nconstarve %d\n", ncon, nconstarve);
77634e04225SDavid du Colombier 
77734e04225SDavid du Colombier 	vtRLock(cbox.clock);
77834e04225SDavid du Colombier 	for(con = cbox.chead; con != nil; con = con->cnext){
77934e04225SDavid du Colombier 		consPrint("\t%s\n", con->name);
78034e04225SDavid du Colombier 	}
78134e04225SDavid du Colombier 	vtRUnlock(cbox.clock);
78234e04225SDavid du Colombier 
78334e04225SDavid du Colombier 	return 1;
78434e04225SDavid du Colombier }
78534e04225SDavid du Colombier 
78634e04225SDavid du Colombier void
78734e04225SDavid du Colombier conInit(void)
78834e04225SDavid du Colombier {
78934e04225SDavid du Colombier 	cbox.alock = vtLockAlloc();
79034e04225SDavid du Colombier 	cbox.arendez = vtRendezAlloc(cbox.alock);
79134e04225SDavid du Colombier 
79234e04225SDavid du Colombier 	cbox.clock = vtLockAlloc();
79334e04225SDavid du Colombier 
79434e04225SDavid du Colombier 	cbox.maxcon = NConInit;
7955e96a66cSDavid du Colombier 	cbox.msize = NMsizeInit;
79634e04225SDavid du Colombier 
79734e04225SDavid du Colombier 	cliAddCmd("con", cmdCon);
79881cf8742SDavid du Colombier 	cliAddCmd("who", cmdWho);
7995e96a66cSDavid du Colombier }
800