plan 9 kernel history: overview | file list | diff list

1991/1117/port/devmux.c (diff list | history)

1991/1114/sys/src/9/port/devmux.c:15,271991/1115/sys/src/9/port/devmux.c:15,30 (short | long)
1991/1114    
enum 
{ 
	Qdir	= 0, 
	Qhead, 
1991/1115    
	Qhead	= 0, 
1991/1114    
	Qclone, 
1991/1115    
	Qoffset, 
1991/1114    
}; 
 
enum 
{ 
	Nmux	=	20, 
1991/1115    
	Maxmsg	=	(32*1024), 
	Flowctl	=	Maxmsg/2, 
1991/1114    
}; 
 
struct Dtq 
1991/1114/sys/src/9/port/devmux.c:31,361991/1115/sys/src/9/port/devmux.c:34,42
1991/1114    
	Lock	listlk; 
	Block	*list; 
	int	ndelim; 
1991/1115    
	int	nb; 
	QLock	flow; 
	Rendez	flowr; 
1991/1114    
}; 
 
struct Con 
1991/1114/sys/src/9/port/devmux.c:44,491991/1115/sys/src/9/port/devmux.c:50,56
1991/1114    
struct Mux 
{ 
	Ref; 
1991/1115    
	int	type; 
1991/1114    
	char	name[NAMELEN]; 
	char	user[NAMELEN]; 
	ulong	perm; 
1991/1114/sys/src/9/port/devmux.c:56,641991/1115/sys/src/9/port/devmux.c:63,74
1991/1114    
 
ulong	muxreadq(Mux *m, Dtq*, char*, ulong); 
void	muxwriteq(Dtq*, char*, long, int, int); 
1991/1115    
void	muxflow(Dtq*); 
Block  *muxclq(Dtq *q); 
1991/1114    
 
#define NMUX(c)		(((c->qid.path>>8)&0xffff)-1) 
#define NQID(m, c)	(Qid){(m)<<8|(c)&0xff, 0} 
1991/1115    
#define NQID(m, c)	(Qid){(m+1)<<8|(c)&0xff, 0} 
#define DQID(m)		(Qid){(m+1)<<8|CHDIR, 0} 
1991/1114    
#define NCON(c)		(c->qid.path&0xff) 
 
int 
1991/1114/sys/src/9/port/devmux.c:68,731991/1115/sys/src/9/port/devmux.c:78,84
1991/1114    
	int mux; 
	Con *cm; 
	char buf[10]; 
1991/1115    
	int nq; 
1991/1114    
 
	if(c->qid.path == CHDIR) { 
		if(s >= conf.nmux) 
1991/1114/sys/src/9/port/devmux.c:76,821991/1115/sys/src/9/port/devmux.c:87,93
1991/1114    
		m = &muxes[s]; 
		if(m->name[0] == '\0') 
			return 0; 
		devdir(c, (Qid){CHDIR|((s+1)<<8), 0}, m->name, 0, m->user, m->perm, dp); 
1991/1115    
		devdir(c, DQID(s), m->name, 0, m->user, m->perm, dp); 
1991/1114    
		return 1; 
	} 
 
1991/1114/sys/src/9/port/devmux.c:85,1031991/1115/sys/src/9/port/devmux.c:96,116
1991/1114    
 
	mux = NMUX(c); 
	m = &muxes[mux]; 
1991/1115    
 
1991/1114    
	switch(s) { 
	case Qhead: 
		devdir(c, NQID(mux, Qhead), "head", m->headq.ndelim, m->user, m->perm, dp); 
1991/1115    
		devdir(c, NQID(mux, Qhead), "head", m->headq.nb, m->user, m->perm, dp); 
1991/1114    
		break; 
	case Qclone: 
		devdir(c, NQID(mux, Qclone), "clone", 0, m->user, m->perm, dp); 
		break; 
	default: 
		cm = &m->connects[s-Qclone]; 
1991/1115    
		nq = s-Qoffset; 
		cm = &m->connects[nq]; 
1991/1114    
		if(cm->ref == 0) 
			return 0; 
		sprint(buf, "%d", s-Qclone); 
		devdir(c, NQID(mux, Qclone+s), buf, cm->conq.ndelim, cm->user, cm->perm, dp); 
1991/1115    
		sprint(buf, "%d", nq); 
		devdir(c, NQID(mux, Qoffset+s), buf, cm->conq.nb, cm->user, cm->perm, dp); 
1991/1114    
		break; 
	} 
	return 1; 
1991/1114/sys/src/9/port/devmux.c:120,1261991/1115/sys/src/9/port/devmux.c:133,138
1991/1114    
	Chan *c; 
 
	c = devattach('m', spec); 
                 
	c->qid.path = CHDIR|Qdir; 
	return c; 
} 
1991/1114/sys/src/9/port/devmux.c:136,1431991/1115/sys/src/9/port/devmux.c:148,158
1991/1114    
 
	m = &muxes[NMUX(c)]; 
	ncon = NCON(c); 
                 
	c = devclone(c, nc); 
1991/1115    
 
	if((c->flag&COPEN) == 0) 
		return c; 
 
1991/1114    
	switch(ncon) { 
	case Qhead: 
		incref(m); 
1991/1114/sys/src/9/port/devmux.c:146,1521991/1115/sys/src/9/port/devmux.c:161,167
1991/1114    
		break; 
	default: 
		lock(m); 
		m->connects[ncon].ref++; 
1991/1115    
		m->connects[ncon-Qoffset].ref++; 
1991/1114    
		m->ref++; 
		unlock(m); 
	} 
1991/1114/sys/src/9/port/devmux.c:175,1931991/1115/sys/src/9/port/devmux.c:190,218
1991/1114    
{ 
	Mux *m; 
	Con *cm, *e; 
1991/1115    
	int mux, ok; 
1991/1114    
 
	if(c->qid.path & CHDIR) 
		return devopen(c, omode, 0, 0, muxgen); 
 
	m = &muxes[NMUX(c)]; 
1991/1115    
	mux = NMUX(c); 
	m = &muxes[mux]; 
1991/1114    
	switch(NCON(c)) { 
	case Qhead: 
1991/1115    
		c = devopen(c, omode, 0, 0, muxgen); 
		lock(m); 
1991/1114    
		if(m->headopen) 
1991/1115    
			ok = 0; 
		else { 
			ok = 1; 
			m->headopen = 1; 
			m->ref++; 
		} 
		unlock(m); 
		if(!ok) { 
			c->flag &= ~COPEN; 
1991/1114    
			errors("server channel busy"); 
                 
		c = devopen(c, omode, 0, 0,muxgen); 
		m->headopen = 1; 
		incref(m); 
1991/1115    
		} 
1991/1114    
		break; 
	case Qclone: 
		if(m->headopen == 0) 
1991/1114/sys/src/9/port/devmux.c:203,2201991/1115/sys/src/9/port/devmux.c:228,247
1991/1114    
			unlock(m); 
			errors("all cannels busy"); 
		} 
		cm->ref++; 
1991/1115    
		cm->ref = 1; 
1991/1114    
		m->ref++; 
		unlock(m); 
		strncpy(cm->user, u->p->user, NAMELEN); 
		cm->perm = 0600; 
		c->qid = NQID(NMUX(c), cm-m->connects); 
1991/1115    
		c->qid = NQID(mux, (cm-m->connects)+Qoffset); 
1991/1114    
		break; 
	default: 
		c = devopen(c, omode, 0, 0,muxgen); 
		cm = &m->connects[NCON(c)]; 
1991/1115    
		c = devopen(c, omode, 0, 0, muxgen); 
		cm = &m->connects[NCON(c)-Qoffset]; 
		lock(m); 
1991/1114    
		cm->ref++; 
		incref(m); 
1991/1115    
		m->ref++; 
		unlock(m); 
1991/1114    
		break; 
	} 
 
1991/1114/sys/src/9/port/devmux.c:234,2401991/1115/sys/src/9/port/devmux.c:261,267
1991/1114    
 
	m = muxes; 
	for(e = &m[conf.nmux]; m < e; m++) { 
		if(m->ref == 0 && canlock(m)) { 
1991/1115    
		if(m->name[0] == '\0' && m->ref == 0 && canlock(m)) { 
1991/1114    
			if(m->ref != 0) { 
				unlock(m); 
				continue; 
1991/1114/sys/src/9/port/devmux.c:291,2971991/1115/sys/src/9/port/devmux.c:318,323
1991/1114    
	d.mode &= 0777; 
	if(c->qid.path&CHDIR) { 
		strcpy(m->name, d.name); 
		strcpy(m->user, d.uid); 
		m->perm = d.mode; 
		return; 
	} 
1991/1114/sys/src/9/port/devmux.c:303,3091991/1115/sys/src/9/port/devmux.c:329,335
1991/1114    
		m->perm = d.mode; 
		break; 
	default: 
		m->connects[nc].perm = d.mode; 
1991/1115    
		m->connects[nc-Qoffset].perm = d.mode; 
1991/1114    
		break; 
	} 
} 
1991/1114/sys/src/9/port/devmux.c:316,3241991/1115/sys/src/9/port/devmux.c:342,353
1991/1114    
	Mux *m; 
	int nc; 
 
	if(c->qid.path == CHDIR) 
1991/1115    
	if(c->qid.path&CHDIR) 
1991/1114    
		return; 
 
1991/1115    
	if((c->flag&COPEN) == 0) 
		return; 
 
1991/1114    
	m = &muxes[NMUX(c)]; 
	nc = NCON(c); 
	f1 = 0; 
1991/1114/sys/src/9/port/devmux.c:331,3561991/1115/sys/src/9/port/devmux.c:360,378
1991/1114    
			if(cm->ref) 
				wakeup(&cm->conq.r); 
		lock(m); 
		if(--m->ref == 0) { 
			f1 = m->headq.list; 
			m->headq.list = 0; 
		} 
1991/1115    
		if(--m->ref == 0) 
			f1 = muxclq(&m->headq); 
1991/1114    
		unlock(m); 
		break; 
	case Qclone: 
		panic("muxclose"); 
1991/1115    
		break; 
1991/1114    
	default: 
		lock(m); 
		cm = &m->connects[nc]; 
		if(--cm->ref == 0) { 
			f1 = cm->conq.list; 
			cm->conq.list = 0;		 
		} 
		if(--m->ref == 0) { 
			m->name[0] = '\0'; 
			f2 = m->headq.list; 
			m->headq.list = 0; 
		} 
1991/1115    
		cm = &m->connects[nc-Qoffset]; 
		if(--cm->ref == 0) 
			f1 = muxclq(&cm->conq); 
		if(--m->ref == 0) 
			f1 = muxclq(&m->headq); 
1991/1114    
		unlock(m); 
	} 
	if(f1) 
1991/1114/sys/src/9/port/devmux.c:377,3831991/1115/sys/src/9/port/devmux.c:399,405
1991/1114    
	case Qclone: 
		error(Eperm); 
	default: 
		cm = &m->connects[NCON(c)]; 
1991/1115    
		cm = &m->connects[NCON(c)-Qoffset]; 
1991/1114    
		bread = muxreadq(m, &cm->conq, va, n); 
		break; 
	} 
1991/1114/sys/src/9/port/devmux.c:390,3961991/1115/sys/src/9/port/devmux.c:412,418
1991/1114    
{ 
	Con *c; 
 
	if(h[0] != Tmux) 
1991/1115    
	if(h[0] != Tmux || h[2] != 0) 
1991/1114    
		error(Ebadmsg); 
 
	c = &m->connects[h[1]]; 
1991/1114/sys/src/9/port/devmux.c:410,4201991/1115/sys/src/9/port/devmux.c:432,445
1991/1114    
	Con *cm; 
	int muxid; 
	Block *f, *bp; 
	char *a, hdr[2]; 
1991/1115    
	char *a, hdr[3]; 
1991/1114    
 
	if(c->qid.path & CHDIR) 
1991/1115    
	if(c->qid.path&CHDIR) 
1991/1114    
		error(Eisdir); 
 
1991/1115    
	if(n > Maxmsg) 
		error(Etoobig); 
 
1991/1114    
	m = &muxes[NMUX(c)]; 
	switch(NCON(c)) { 
	case Qclone: 
1991/1114/sys/src/9/port/devmux.c:435,4411991/1115/sys/src/9/port/devmux.c:460,466
1991/1114    
		if(m->headopen == 0) 
			error(Ehungup); 
 
		muxid = NCON(c); 
1991/1115    
		muxid = NCON(c)-Qoffset; 
1991/1114    
		muxwriteq(&m->headq, va, n, 1, muxid); 
		break; 
	} 
1991/1114/sys/src/9/port/devmux.c:447,4531991/1115/sys/src/9/port/devmux.c:472,478
1991/1114    
muxwriteq(Dtq *q, char *va, long n, int addid, int muxid) 
{ 
	Block *head, *tail, *bp; 
	ulong l; 
1991/1115    
	ulong l, bwrite; 
1991/1114    
 
	head = 0; 
	SET(tail); 
1991/1114/sys/src/9/port/devmux.c:457,4691991/1115/sys/src/9/port/devmux.c:482,507
1991/1114    
		nexterror(); 
	} 
 
1991/1115    
	bwrite = 0; 
1991/1114    
	while(n) { 
		bp = allocb(n); 
		bp->type = M_DATA; 
1991/1115    
		if(addid) { 
			bp = allocb(n+3); 
			bp->wptr[0] = Tmux; 
			bp->wptr[1] = muxid; 
			bp->wptr[2] = 0; 
			bp->wptr += 3; 
			bwrite += 3; 
			addid = 0; 
		} 
		else 
			bp = allocb(n); 
1991/1114    
		l = bp->lim - bp->wptr; 
1991/1115    
		if(l > n) 
			l = n; 
1991/1114    
		memmove(bp->wptr, va, l);	/* Interruptable thru fault */ 
		va += l; 
		bp->wptr += l; 
1991/1115    
		bwrite += l; 
1991/1114    
		n -= l; 
		if(head == 0) 
			head = bp; 
1991/1114/sys/src/9/port/devmux.c:473,4891991/1115/sys/src/9/port/devmux.c:511,556
1991/1114    
	} 
	poperror(); 
	tail->flags |= S_DELIM; 
1991/1115    
 
	if(q->nb > Flowctl) 
		muxflow(q); 
 
1991/1114    
	lock(&q->listlk); 
	for(tail = q->list; tail->next; tail = tail->next) 
		; 
	tail->next = head; 
1991/1115    
	if(q->list == 0) 
		q->list = head; 
	else { 
		for(tail = q->list; tail->next; tail = tail->next) 
			; 
		tail->next = head; 
	} 
1991/1114    
	q->ndelim++; 
1991/1115    
	q->nb += bwrite; 
1991/1114    
	unlock(&q->listlk); 
1991/1115    
	wakeup(&q->r); 
1991/1114    
} 
 
int 
nodata(Dtq *q) 
1991/1115    
muxflw(Dtq *q) 
1991/1114    
{ 
1991/1115    
	return q->nb < Flowctl; 
} 
 
void 
muxflow(Dtq *q) 
{ 
	qlock(&q->flow); 
	if(waserror()) { 
		qunlock(&q->flow); 
		nexterror(); 
	} 
	sleep(&q->flowr, muxflw, q); 
	poperror(); 
	qunlock(&q->flow); 
} 
 
int 
havedata(Dtq *q) 
{ 
1991/1114    
	int n; 
 
	lock(&q->listlk); 
1991/1114/sys/src/9/port/devmux.c:496,5021991/1115/sys/src/9/port/devmux.c:563,569
1991/1114    
muxreadq(Mux *m, Dtq *q, char *va, ulong n) 
{ 
	int l, nread, gotdelim; 
	Block *bp; 
1991/1115    
	Block *bp, *f1; 
1991/1114    
 
	qlock(&q->rd); 
	bp = 0; 
1991/1114/sys/src/9/port/devmux.c:510,5501991/1115/sys/src/9/port/devmux.c:577,639
1991/1114    
		unlock(&q->listlk); 
		nexterror(); 
	} 
	while(nodata(q)) 
		sleep(&q->r, nodata, q); 
1991/1115    
	while(!havedata(q)) { 
		sleep(&q->r, havedata, q); 
		if(m->headopen == 0) 
			errors("server shutdown"); 
	} 
1991/1114    
 
	if(m->headopen == 0) 
		errors("server shutdown"); 
                 
	nread = 0; 
1991/1115    
	f1 = 0; 
	lock(&q->listlk); 
1991/1114    
	while(n) { 
		lock(&q->listlk); 
		bp = q->list; 
		q->list = bp->next; 
		bp->next = 0; 
		unlock(&q->listlk); 
                 
1991/1115    
		if(f1) { 
			freeb(f1); 
			f1 = 0; 
		} 
1991/1114    
		l = BLEN(bp); 
		if(n < l) 
			n = l; 
1991/1115    
		if(l > n) 
			l = n; 
1991/1114    
		memmove(va, bp->rptr, l);	/* Interruptable thru fault */ 
		va += l; 
		bp->rptr += l; 
		n -= l; 
		gotdelim = bp->flags&S_DELIM; 
1991/1115    
		nread += l; 
1991/1114    
		lock(&q->listlk); 
		if(bp->rptr != bp->wptr) { 
1991/1115    
		if(bp->rptr == bp->wptr) 
			f1 = bp; 
		else { 
1991/1114    
			bp->next = q->list; 
			q->list = bp; 
		} 
		else if(gotdelim) 
1991/1115    
		if(bp->flags&S_DELIM) { 
1991/1114    
			q->ndelim--; 
		unlock(&q->listlk); 
		if(bp->rptr == bp->wptr) 
			freeb(bp); 
		if(gotdelim) 
			break; 
1991/1115    
		} 
1991/1114    
	} 
1991/1115    
	q->nb -= nread; 
	unlock(&q->listlk); 
	if(f1) 
		freeb(f1); 
1991/1114    
	qunlock(&q->rd); 
1991/1115    
	poperror(); 
	if(q->nb < Flowctl) 
		wakeup(&q->flowr); 
1991/1114    
	return nread; 
1991/1115    
} 
 
Block * 
muxclq(Dtq *q) 
{ 
	Block *f; 
 
	f = q->list; 
	q->list = 0; 
	q->nb = 0; 
	q->ndelim = 0; 
	return f; 
1991/1114    
} 
1991/1115/sys/src/9/port/devmux.c:22,281991/1117/sys/src/9/port/devmux.c:22,28 (short | long)
1991/1114    
 
enum 
{ 
	Nmux	=	20, 
1991/1117    
	Nmux	=	32, 
1991/1115    
	Maxmsg	=	(32*1024), 
	Flowctl	=	Maxmsg/2, 
1991/1114    
}; 
1991/1115/sys/src/9/port/devmux.c:50,561991/1117/sys/src/9/port/devmux.c:50,56
1991/1114    
struct Mux 
{ 
	Ref; 
1991/1115    
	int	type; 
1991/1117    
	int	srv; 
1991/1114    
	char	name[NAMELEN]; 
	char	user[NAMELEN]; 
	ulong	perm; 
1991/1115/sys/src/9/port/devmux.c:57,661991/1117/sys/src/9/port/devmux.c:57,66
1991/1114    
	int	headopen; 
	Dtq	headq; 
	Con	connects[Nmux]; 
1991/1117    
	Chan	*c; 
1991/1114    
}; 
 
Mux	*muxes; 
                 
ulong	muxreadq(Mux *m, Dtq*, char*, ulong); 
void	muxwriteq(Dtq*, char*, long, int, int); 
1991/1115    
void	muxflow(Dtq*); 
1991/1115/sys/src/9/port/devmux.c:87,931991/1117/sys/src/9/port/devmux.c:87,96
1991/1114    
		m = &muxes[s]; 
		if(m->name[0] == '\0') 
			return 0; 
1991/1115    
		devdir(c, DQID(s), m->name, 0, m->user, m->perm, dp); 
1991/1117    
		if(m->srv) 
			devdir(c, NQID(s, 0), m->name, 0, m->user, m->perm, dp); 
		else 
			devdir(c, DQID(s), m->name, 0, m->user, m->perm, dp); 
1991/1114    
		return 1; 
	} 
 
1991/1115/sys/src/9/port/devmux.c:191,2501991/1117/sys/src/9/port/devmux.c:194,254
1991/1114    
	Mux *m; 
	Con *cm, *e; 
1991/1115    
	int mux, ok; 
1991/1117    
	Chan *new; 
1991/1114    
 
1991/1117    
	c = devopen(c, omode, 0, 0, muxgen); 
1991/1114    
	if(c->qid.path & CHDIR) 
		return devopen(c, omode, 0, 0, muxgen); 
1991/1117    
		return c; 
1991/1114    
 
1991/1115    
	mux = NMUX(c); 
	m = &muxes[mux]; 
1991/1117    
	lock(m); 
	if(waserror()) { 
		c->flag &= ~COPEN; 
		unlock(m); 
		nexterror(); 
	} 
	if(m->srv) { 
		if(m->c == 0) 
			error(Eshutdown); 
		new = m->c; 
		incref(new); 
		unlock(m); 
		poperror(); 
		close(c); 
		return new; 
	} 
1991/1114    
	switch(NCON(c)) { 
	case Qhead: 
1991/1115    
		c = devopen(c, omode, 0, 0, muxgen); 
		lock(m); 
1991/1114    
		if(m->headopen) 
1991/1115    
			ok = 0; 
		else { 
			ok = 1; 
			m->headopen = 1; 
			m->ref++; 
		} 
		unlock(m); 
		if(!ok) { 
			c->flag &= ~COPEN; 
1991/1114    
			errors("server channel busy"); 
1991/1115    
		} 
1991/1117    
		m->headopen = 1; 
		m->ref++; 
1991/1114    
		break; 
	case Qclone: 
		if(m->headopen == 0) 
			errors("server shutdown"); 
 
		c = devopen(c, omode, 0, 0, muxgen); 
		lock(m); 
		cm = m->connects; 
		for(e = &cm[Nmux]; cm < e; cm++) 
			if(cm->ref == 0) 
				break; 
		if(cm == e) { 
			unlock(m); 
1991/1117    
		if(cm == e) 
1991/1114    
			errors("all cannels busy"); 
		} 
1991/1115    
		cm->ref = 1; 
1991/1114    
		m->ref++; 
		unlock(m); 
		strncpy(cm->user, u->p->user, NAMELEN); 
		cm->perm = 0600; 
1991/1115    
		c->qid = NQID(mux, (cm-m->connects)+Qoffset); 
1991/1114    
		break; 
	default: 
1991/1115    
		c = devopen(c, omode, 0, 0, muxgen); 
		cm = &m->connects[NCON(c)-Qoffset]; 
		lock(m); 
1991/1114    
		cm->ref++; 
1991/1115    
		m->ref++; 
		unlock(m); 
1991/1114    
		break; 
	} 
                 
1991/1117    
	unlock(m); 
	poperror(); 
1991/1114    
	return c; 
} 
 
1991/1115/sys/src/9/port/devmux.c:266,2721991/1117/sys/src/9/port/devmux.c:270,275
1991/1114    
				unlock(m); 
				continue; 
			} 
			m->ref++; 
			break; 
		}	 
	} 
1991/1115/sys/src/9/port/devmux.c:277,2861991/1117/sys/src/9/port/devmux.c:280,292
1991/1114    
	strncpy(m->name, name, NAMELEN); 
	strncpy(m->user, u->p->user, NAMELEN); 
	m->perm = perm&~CHDIR; 
1991/1117    
	m->srv = 1; 
	if(perm&CHDIR) 
		m->srv = 0; 
1991/1114    
	unlock(m); 
 
	n = m - muxes; 
	c->qid = (Qid){CHDIR|(n+1)<<8, 0}; 
1991/1117    
	c->qid = (Qid){(CHDIR&perm)|(n+1)<<8, 0}; 
1991/1114    
	c->flag |= COPEN; 
	c->mode = omode; 
} 
1991/1115/sys/src/9/port/devmux.c:289,3031991/1117/sys/src/9/port/devmux.c:295,324
1991/1114    
muxremove(Chan *c) 
{ 
	Mux *m; 
1991/1117    
	Chan *srv; 
1991/1114    
 
	if(c->qid.path == CHDIR || (c->qid.path&CHDIR) == 0) 
1991/1117    
	if(c->qid.path == CHDIR)  
1991/1114    
		error(Eperm); 
 
	m = &muxes[NMUX(c)]; 
1991/1117    
	if((c->qid.path&CHDIR) == 0 && m->srv == 0) 
		error(Eperm); 
		 
1991/1114    
	if(strcmp(u->p->user, m->user) != 0) 
		errors("not owner"); 
 
1991/1117    
	srv = 0; 
	lock(m); 
	if(m->srv) { 
		srv = m->c; 
		m->c = 0; 
	} 
1991/1114    
	m->name[0] = '\0'; 
1991/1117    
	unlock(m); 
	if(srv) 
		close(srv); 
 
	muxclose(c); 
1991/1114    
} 
 
void 
1991/1115/sys/src/9/port/devmux.c:316,3221991/1117/sys/src/9/port/devmux.c:337,343
1991/1114    
 
	convM2D(db, &d); 
	d.mode &= 0777; 
	if(c->qid.path&CHDIR) { 
1991/1117    
	if(c->qid.path&CHDIR || m->srv) { 
1991/1114    
		strcpy(m->name, d.name); 
		m->perm = d.mode; 
		return; 
1991/1115/sys/src/9/port/devmux.c:345,3541991/1117/sys/src/9/port/devmux.c:366,375
1991/1115    
	if(c->qid.path&CHDIR) 
1991/1114    
		return; 
 
1991/1115    
	if((c->flag&COPEN) == 0) 
1991/1117    
	m = &muxes[NMUX(c)]; 
	if(!(c->flag&COPEN) || m->srv) 
1991/1115    
		return; 
 
1991/1114    
	m = &muxes[NMUX(c)]; 
	nc = NCON(c); 
	f1 = 0; 
	f2 = 0; 
1991/1115/sys/src/9/port/devmux.c:430,4461991/1117/sys/src/9/port/devmux.c:451,476
1991/1114    
{ 
	Mux *m; 
	Con *cm; 
	int muxid; 
1991/1117    
	int muxid, fd; 
1991/1114    
	Block *f, *bp; 
1991/1115    
	char *a, hdr[3]; 
1991/1117    
	char *a, hdr[3], buf[10]; 
1991/1114    
 
1991/1115    
	if(c->qid.path&CHDIR) 
1991/1114    
		error(Eisdir); 
 
1991/1115    
	if(n > Maxmsg) 
1991/1117    
	m = &muxes[NMUX(c)]; 
	if(n > Maxmsg || (m->srv && n >= sizeof(buf))) 
1991/1115    
		error(Etoobig); 
 
1991/1114    
	m = &muxes[NMUX(c)]; 
1991/1117    
	if(m->srv) { 
		memmove(buf, va, n);		/* so we can NUL-terminate */ 
		buf[n] = 0; 
		fd = strtoul(buf, 0, 0); 
		fdtochan(fd, -1, 0);		/* error check */ 
		m->c = u->p->fgrp->fd[fd]; 
		incref(m->c); 
		return n; 
	} 
1991/1114    
	switch(NCON(c)) { 
	case Qclone: 
		error(Eperm); 
1991/1115/sys/src/9/port/devmux.c:475,4811991/1117/sys/src/9/port/devmux.c:505,511
1991/1115    
	ulong l, bwrite; 
1991/1114    
 
	head = 0; 
	SET(tail); 
1991/1117    
	tail = 0; 
1991/1114    
	if(waserror()) { 
		if(head) 
			freeb(head); 
1991/1115/sys/src/9/port/devmux.c:568,5741991/1117/sys/src/9/port/devmux.c:598,603
1991/1114    
	qlock(&q->rd); 
	bp = 0; 
	if(waserror()) { 
		qunlock(&q->rd); 
		lock(&q->listlk); 
		if(bp) { 
			bp->next = q->list; 
1991/1115/sys/src/9/port/devmux.c:575,5801991/1117/sys/src/9/port/devmux.c:604,610
1991/1114    
			q->list = bp; 
		} 
		unlock(&q->listlk); 
1991/1117    
		qunlock(&q->rd); 
1991/1114    
		nexterror(); 
	} 
1991/1115    
	while(!havedata(q)) { 
1991/1117/sys/src/9/port/devmux.c:3,91992/0111/sys/src/9/port/devmux.c:3,9 (short | long)
Move error.h to ../port. Change errors to actual strings.
rsc Fri Mar 4 12:44:25 2005
1991/1114    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"errno.h" 
1992/0111    
#include	"../port/error.h" 
1991/1114    
#include	"fcall.h" 
 
#include	"devtab.h" 
1992/0111/sys/src/9/port/devmux.c:221,2331992/0113/sys/src/9/port/devmux.c:221,233 (short | long)
1991/1114    
	switch(NCON(c)) { 
	case Qhead: 
		if(m->headopen) 
			errors("server channel busy"); 
1992/0113    
			error(Einuse); 
1991/1117    
		m->headopen = 1; 
		m->ref++; 
1991/1114    
		break; 
	case Qclone: 
		if(m->headopen == 0) 
			errors("server shutdown"); 
1992/0113    
			error(Emuxshutdown); 
1991/1114    
 
		cm = m->connects; 
		for(e = &cm[Nmux]; cm < e; cm++) 
1992/0111/sys/src/9/port/devmux.c:234,2401992/0113/sys/src/9/port/devmux.c:234,240
1991/1114    
			if(cm->ref == 0) 
				break; 
1991/1117    
		if(cm == e) 
1991/1114    
			errors("all cannels busy"); 
1992/0113    
			error(Emuxbusy); 
1991/1115    
		cm->ref = 1; 
1991/1114    
		m->ref++; 
		strncpy(cm->user, u->p->user, NAMELEN); 
1992/0111/sys/src/9/port/devmux.c:275,2811992/0113/sys/src/9/port/devmux.c:275,281
1991/1114    
	} 
 
	if(m == e) 
		errors("no multiplexors"); 
1992/0113    
		error(Enomux); 
1991/1114    
 
	strncpy(m->name, name, NAMELEN); 
	strncpy(m->user, u->p->user, NAMELEN); 
1992/0111/sys/src/9/port/devmux.c:304,3111992/0113/sys/src/9/port/devmux.c:304,311
1991/1117    
	if((c->qid.path&CHDIR) == 0 && m->srv == 0) 
		error(Eperm); 
		 
1991/1114    
	if(strcmp(u->p->user, m->user) != 0) 
		errors("not owner"); 
1992/0113    
	if(strncmp(u->p->user, m->user, NAMELEN)) 
		error(Eperm); 
1991/1114    
 
1991/1117    
	srv = 0; 
	lock(m); 
1992/0111/sys/src/9/port/devmux.c:332,3391992/0113/sys/src/9/port/devmux.c:332,339
1991/1114    
		error(Eperm); 
 
	m = &muxes[NMUX(c)]; 
	if(strcmp(u->p->user, m->user) != 0) 
		errors("not owner"); 
1992/0113    
	if(strncmp(u->p->user, m->user, NAMELEN)) 
		error(Eperm); 
1991/1114    
 
	convM2D(db, &d); 
	d.mode &= 0777; 
1992/0111/sys/src/9/port/devmux.c:434,4441992/0113/sys/src/9/port/devmux.c:434,444
1991/1114    
	Con *c; 
 
1991/1115    
	if(h[0] != Tmux || h[2] != 0) 
1991/1114    
		error(Ebadmsg); 
1992/0113    
		error(Emuxmsg); 
1991/1114    
 
	c = &m->connects[h[1]]; 
	if(c < m->connects || c > &m->connects[Nmux])	 
		error(Ebadmsg); 
1992/0113    
		error(Emuxmsg); 
1991/1114    
 
	if(c->ref == 0) 
		return 0; 
1992/0111/sys/src/9/port/devmux.c:476,4821992/0113/sys/src/9/port/devmux.c:476,482
1991/1114    
		error(Eperm); 
	case Qhead: 
		if(n < 2) 
			error(Ebadmsg); 
1992/0113    
			error(Emuxmsg); 
1991/1114    
 
		a = (char*)va; 
		memmove(hdr, a, sizeof(hdr)); 
1992/0111/sys/src/9/port/devmux.c:610,6161992/0113/sys/src/9/port/devmux.c:610,616
1991/1115    
	while(!havedata(q)) { 
		sleep(&q->r, havedata, q); 
		if(m->headopen == 0) 
			errors("server shutdown"); 
1992/0113    
			errors(Emuxshutdown); 
1991/1115    
	} 
1991/1114    
 
	nread = 0; 
1992/0113/sys/src/9/port/devmux.c:275,2811992/0114/sys/src/9/port/devmux.c:275,281 (short | long)
1991/1114    
	} 
 
	if(m == e) 
1992/0113    
		error(Enomux); 
1992/0114    
		exhausted("multiplexers"); 
1991/1114    
 
	strncpy(m->name, name, NAMELEN); 
	strncpy(m->user, u->p->user, NAMELEN); 
1992/0113/sys/src/9/port/devmux.c:610,6161992/0114/sys/src/9/port/devmux.c:610,616
1991/1115    
	while(!havedata(q)) { 
		sleep(&q->r, havedata, q); 
		if(m->headopen == 0) 
1992/0113    
			errors(Emuxshutdown); 
1992/0114    
			error(Emuxshutdown); 
1991/1115    
	} 
1991/1114    
 
	nread = 0; 
1992/0114/sys/src/9/port/devmux.c:135,1411992/0201/sys/src/9/port/devmux.c:135,141 (short | long)
1991/1114    
{ 
	Chan *c; 
 
	c = devattach('m', spec); 
1992/0201    
	c = devattach('s', spec); 
1991/1114    
	c->qid.path = CHDIR|Qdir; 
	return c; 
} 
1992/0201/sys/src/9/port/devmux.c:292,2971992/0303/sys/src/9/port/devmux.c:292,344 (short | long)
1991/1114    
} 
 
void 
1992/0303    
muxclose(Chan *c) 
{ 
	Block *f1, *f2; 
	Con *cm, *e; 
	Mux *m; 
	int nc; 
 
	if(c->qid.path&CHDIR) 
		return; 
 
	m = &muxes[NMUX(c)]; 
	if(!(c->flag&COPEN) || m->srv) 
		return; 
 
	nc = NCON(c); 
	f1 = 0; 
	f2 = 0; 
	switch(nc) { 
	case Qhead: 
		m->headopen = 0; 
		cm = m->connects; 
		for(e = &cm[Nmux]; cm < e; cm++) 
			if(cm->ref) 
				wakeup(&cm->conq.r); 
		lock(m); 
		if(--m->ref == 0) 
			f1 = muxclq(&m->headq); 
		unlock(m); 
		break; 
	case Qclone: 
		break; 
	default: 
		lock(m); 
		cm = &m->connects[nc-Qoffset]; 
		if(--cm->ref == 0) 
			f1 = muxclq(&cm->conq); 
		if(--m->ref == 0) 
			f1 = muxclq(&m->headq); 
		unlock(m); 
	} 
	if(f1) 
		freeb(f1); 
	if(f2) 
		freeb(f2); 
} 
 
void 
1991/1114    
muxremove(Chan *c) 
{ 
	Mux *m; 
1992/0201/sys/src/9/port/devmux.c:353,4051992/0303/sys/src/9/port/devmux.c:400,405
1991/1115    
		m->connects[nc-Qoffset].perm = d.mode; 
1991/1114    
		break; 
	} 
} 
                 
void 
muxclose(Chan *c) 
{ 
	Block *f1, *f2; 
	Con *cm, *e; 
	Mux *m; 
	int nc; 
                 
1991/1115    
	if(c->qid.path&CHDIR) 
1991/1114    
		return; 
                 
1991/1117    
	m = &muxes[NMUX(c)]; 
	if(!(c->flag&COPEN) || m->srv) 
1991/1115    
		return; 
                 
1991/1114    
	nc = NCON(c); 
	f1 = 0; 
	f2 = 0; 
	switch(nc) { 
	case Qhead: 
		m->headopen = 0; 
		cm = m->connects; 
		for(e = &cm[Nmux]; cm < e; cm++) 
			if(cm->ref) 
				wakeup(&cm->conq.r); 
		lock(m); 
1991/1115    
		if(--m->ref == 0) 
			f1 = muxclq(&m->headq); 
1991/1114    
		unlock(m); 
		break; 
	case Qclone: 
1991/1115    
		break; 
1991/1114    
	default: 
		lock(m); 
1991/1115    
		cm = &m->connects[nc-Qoffset]; 
		if(--cm->ref == 0) 
			f1 = muxclq(&cm->conq); 
		if(--m->ref == 0) 
			f1 = muxclq(&m->headq); 
1991/1114    
		unlock(m); 
	} 
	if(f1) 
		freeb(f1); 
	if(f2) 
		freeb(f2); 
} 
 
long 
1992/0303/sys/src/9/port/devmux.c:1,51992/0321/sys/src/9/port/devmux.c:1,5 (short | long)
Move lib.h to ../port.
rsc Fri Mar 4 12:44:25 2005
1991/1114    
#include	"u.h" 
#include	"lib.h" 
1992/0321    
#include	"../port/lib.h" 
1991/1114    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0321/sys/src/9/port/devmux.c:127,1331992/0622/sys/src/9/port/devmux.c:127,133 (short | long)
1991/1114    
void 
muxreset(void) 
{ 
	muxes = ialloc(conf.nmux*sizeof(Mux), 0); 
1992/0622    
	muxes = xalloc(conf.nmux*sizeof(Mux)); 
1991/1114    
} 
 
Chan * 
1992/0622/sys/src/9/port/devmux.c:4,101992/0630/sys/src/9/port/devmux.c:4,9 (short | long)
1991/1114    
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1991/1114    
#include	"fcall.h" 
 
#include	"devtab.h" 
 
1992/0622/sys/src/9/port/devmux.c:18,271992/0630/sys/src/9/port/devmux.c:17,24
1991/1115    
	Qhead	= 0, 
1991/1114    
	Qclone, 
1991/1115    
	Qoffset, 
1991/1114    
}; 
 
enum 
{ 
1992/0630    
	Nmuxchan=	64, 
1991/1117    
	Nmux	=	32, 
1991/1115    
	Maxmsg	=	(32*1024), 
	Flowctl	=	Maxmsg/2, 
1992/0622/sys/src/9/port/devmux.c:81,871992/0630/sys/src/9/port/devmux.c:78,84
1991/1115    
	int nq; 
1991/1114    
 
	if(c->qid.path == CHDIR) { 
		if(s >= conf.nmux) 
1992/0630    
		if(s >= Nmuxchan) 
1991/1114    
			return -1; 
 
		m = &muxes[s]; 
1992/0622/sys/src/9/port/devmux.c:127,1331992/0630/sys/src/9/port/devmux.c:124,130
1991/1114    
void 
muxreset(void) 
{ 
1992/0622    
	muxes = xalloc(conf.nmux*sizeof(Mux)); 
1992/0630    
	muxes = xalloc(Nmuxchan*sizeof(Mux)); 
1991/1114    
} 
 
Chan * 
1992/0622/sys/src/9/port/devmux.c:264,2701992/0630/sys/src/9/port/devmux.c:261,267
1991/1114    
	omode = openmode(omode); 
 
	m = muxes; 
	for(e = &m[conf.nmux]; m < e; m++) { 
1992/0630    
	for(e = &m[Nmuxchan]; m < e; m++) { 
1991/1115    
		if(m->name[0] == '\0' && m->ref == 0 && canlock(m)) { 
1991/1114    
			if(m->ref != 0) { 
				unlock(m); 
1992/0630/sys/src/9/port/devmux.c:77,821992/0711/sys/src/9/port/devmux.c:77,83 (short | long)
1991/1114    
	char buf[10]; 
1991/1115    
	int nq; 
1991/1114    
 
1992/0711    
	USED(tab, ntab); 
1991/1114    
	if(c->qid.path == CHDIR) { 
1992/0630    
		if(s >= Nmuxchan) 
1991/1114    
			return -1; 
1992/0630/sys/src/9/port/devmux.c:190,1961992/0711/sys/src/9/port/devmux.c:191,197
1991/1114    
{ 
	Mux *m; 
	Con *cm, *e; 
1991/1115    
	int mux, ok; 
1992/0711    
	int mux; 
1991/1117    
	Chan *new; 
1991/1114    
 
1991/1117    
	c = devopen(c, omode, 0, 0, muxgen); 
1992/0630/sys/src/9/port/devmux.c:406,4111992/0711/sys/src/9/port/devmux.c:407,413
1991/1114    
	Con *cm; 
	int bread; 
 
1992/0711    
	USED(offset); 
1991/1114    
	if(c->qid.path & CHDIR) 
		return devdirread(c, va, n, 0, 0, muxgen); 
 
1992/0630/sys/src/9/port/devmux.c:449,4571992/0711/sys/src/9/port/devmux.c:451,459
1991/1114    
	Mux *m; 
	Con *cm; 
1991/1117    
	int muxid, fd; 
1991/1114    
	Block *f, *bp; 
1991/1117    
	char *a, hdr[3], buf[10]; 
1991/1114    
 
1992/0711    
	USED(offset); 
1991/1115    
	if(c->qid.path&CHDIR) 
1991/1114    
		error(Eisdir); 
 
1992/0630/sys/src/9/port/devmux.c:589,5951992/0711/sys/src/9/port/devmux.c:591,597
1991/1114    
ulong 
muxreadq(Mux *m, Dtq *q, char *va, ulong n) 
{ 
	int l, nread, gotdelim; 
1992/0711    
	int l, nread; 
1991/1115    
	Block *bp, *f1; 
1991/1114    
 
	qlock(&q->rd); 
1992/0711/sys/src/9/port/devmux.c:465,4711992/0825/sys/src/9/port/devmux.c:465,471 (short | long)
1991/1117    
		memmove(buf, va, n);		/* so we can NUL-terminate */ 
		buf[n] = 0; 
		fd = strtoul(buf, 0, 0); 
		fdtochan(fd, -1, 0);		/* error check */ 
1992/0825    
		fdtochan(fd, -1, 0, 0);		/* error check */ 
1991/1117    
		m->c = u->p->fgrp->fd[fd]; 
		incref(m->c); 
		return n; 
1992/0825/sys/src/9/port/devmux.c:1,6681993/0501/sys/src/9/port/devmux.c:0 (short | long)
Deleted.
rsc Mon Mar 7 10:30:54 2005
1991/1114    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1991/1114    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1991/1114    
                 
#include	"devtab.h" 
                 
typedef struct Mux Mux; 
typedef struct Con Con; 
typedef struct Dtq Dtq; 
                 
enum 
{ 
	Qdir	= 0, 
1991/1115    
	Qhead	= 0, 
1991/1114    
	Qclone, 
1991/1115    
	Qoffset, 
1991/1114    
                 
1992/0630    
	Nmuxchan=	64, 
1991/1117    
	Nmux	=	32, 
1991/1115    
	Maxmsg	=	(32*1024), 
	Flowctl	=	Maxmsg/2, 
1991/1114    
}; 
                 
struct Dtq 
{ 
	QLock	rd; 
	Rendez	r; 
	Lock	listlk; 
	Block	*list; 
	int	ndelim; 
1991/1115    
	int	nb; 
	QLock	flow; 
	Rendez	flowr; 
1991/1114    
}; 
                 
struct Con 
{ 
	int	ref; 
	char	user[NAMELEN]; 
	ulong	perm; 
	Dtq	conq; 
}; 
                 
struct Mux 
{ 
	Ref; 
1991/1117    
	int	srv; 
1991/1114    
	char	name[NAMELEN]; 
	char	user[NAMELEN]; 
	ulong	perm; 
	int	headopen; 
	Dtq	headq; 
	Con	connects[Nmux]; 
1991/1117    
	Chan	*c; 
1991/1114    
}; 
                 
Mux	*muxes; 
ulong	muxreadq(Mux *m, Dtq*, char*, ulong); 
void	muxwriteq(Dtq*, char*, long, int, int); 
1991/1115    
void	muxflow(Dtq*); 
Block  *muxclq(Dtq *q); 
1991/1114    
                 
#define NMUX(c)		(((c->qid.path>>8)&0xffff)-1) 
1991/1115    
#define NQID(m, c)	(Qid){(m+1)<<8|(c)&0xff, 0} 
#define DQID(m)		(Qid){(m+1)<<8|CHDIR, 0} 
1991/1114    
#define NCON(c)		(c->qid.path&0xff) 
                 
int 
muxgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) 
{ 
	Mux *m; 
	int mux; 
	Con *cm; 
	char buf[10]; 
1991/1115    
	int nq; 
1991/1114    
                 
1992/0711    
	USED(tab, ntab); 
1991/1114    
	if(c->qid.path == CHDIR) { 
1992/0630    
		if(s >= Nmuxchan) 
1991/1114    
			return -1; 
                 
		m = &muxes[s]; 
		if(m->name[0] == '\0') 
			return 0; 
1991/1117    
		if(m->srv) 
			devdir(c, NQID(s, 0), m->name, 0, m->user, m->perm, dp); 
		else 
			devdir(c, DQID(s), m->name, 0, m->user, m->perm, dp); 
1991/1114    
		return 1; 
	} 
                 
	if(s >= Nmux+2) 
		return -1; 
                 
	mux = NMUX(c); 
	m = &muxes[mux]; 
1991/1115    
                 
1991/1114    
	switch(s) { 
	case Qhead: 
1991/1115    
		devdir(c, NQID(mux, Qhead), "head", m->headq.nb, m->user, m->perm, dp); 
1991/1114    
		break; 
	case Qclone: 
		devdir(c, NQID(mux, Qclone), "clone", 0, m->user, m->perm, dp); 
		break; 
	default: 
1991/1115    
		nq = s-Qoffset; 
		cm = &m->connects[nq]; 
1991/1114    
		if(cm->ref == 0) 
			return 0; 
1991/1115    
		sprint(buf, "%d", nq); 
		devdir(c, NQID(mux, Qoffset+s), buf, cm->conq.nb, cm->user, cm->perm, dp); 
1991/1114    
		break; 
	} 
	return 1; 
} 
                 
void 
muxinit(void) 
{ 
} 
                 
void 
muxreset(void) 
{ 
1992/0630    
	muxes = xalloc(Nmuxchan*sizeof(Mux)); 
1991/1114    
} 
                 
Chan * 
muxattach(char *spec) 
{ 
	Chan *c; 
                 
1992/0201    
	c = devattach('s', spec); 
1991/1114    
	c->qid.path = CHDIR|Qdir; 
	return c; 
} 
                 
Chan * 
muxclone(Chan *c, Chan *nc) 
{ 
	int ncon; 
	Mux *m; 
                 
	if(c->qid.path == CHDIR) 
		return devclone(c, nc);; 
                 
	m = &muxes[NMUX(c)]; 
	ncon = NCON(c); 
	c = devclone(c, nc); 
1991/1115    
                 
	if((c->flag&COPEN) == 0) 
		return c; 
                 
1991/1114    
	switch(ncon) { 
	case Qhead: 
		incref(m); 
		break; 
	case Qclone: 
		break; 
	default: 
		lock(m); 
1991/1115    
		m->connects[ncon-Qoffset].ref++; 
1991/1114    
		m->ref++; 
		unlock(m); 
	} 
	return c; 
} 
                 
int 
muxwalk(Chan *c, char *name) 
{ 
	if(strcmp(name, "..") == 0) { 
		c->qid.path = CHDIR|Qdir; 
		return 1; 
	} 
                 
	return devwalk(c, name, 0, 0, muxgen); 
} 
                 
void 
muxstat(Chan *c, char *db) 
{ 
	devstat(c, db, 0, 0, muxgen); 
} 
                 
Chan * 
muxopen(Chan *c, int omode) 
{ 
	Mux *m; 
	Con *cm, *e; 
1992/0711    
	int mux; 
1991/1117    
	Chan *new; 
1991/1114    
                 
1991/1117    
	c = devopen(c, omode, 0, 0, muxgen); 
1991/1114    
	if(c->qid.path & CHDIR) 
1991/1117    
		return c; 
1991/1114    
                 
1991/1115    
	mux = NMUX(c); 
	m = &muxes[mux]; 
1991/1117    
	lock(m); 
	if(waserror()) { 
		c->flag &= ~COPEN; 
		unlock(m); 
		nexterror(); 
	} 
	if(m->srv) { 
		if(m->c == 0) 
			error(Eshutdown); 
		new = m->c; 
		incref(new); 
		unlock(m); 
		poperror(); 
		close(c); 
		return new; 
	} 
1991/1114    
	switch(NCON(c)) { 
	case Qhead: 
		if(m->headopen) 
1992/0113    
			error(Einuse); 
1991/1117    
		m->headopen = 1; 
		m->ref++; 
1991/1114    
		break; 
	case Qclone: 
		if(m->headopen == 0) 
1992/0113    
			error(Emuxshutdown); 
1991/1114    
                 
		cm = m->connects; 
		for(e = &cm[Nmux]; cm < e; cm++) 
			if(cm->ref == 0) 
				break; 
1991/1117    
		if(cm == e) 
1992/0113    
			error(Emuxbusy); 
1991/1115    
		cm->ref = 1; 
1991/1114    
		m->ref++; 
		strncpy(cm->user, u->p->user, NAMELEN); 
		cm->perm = 0600; 
1991/1115    
		c->qid = NQID(mux, (cm-m->connects)+Qoffset); 
1991/1114    
		break; 
	default: 
1991/1115    
		cm = &m->connects[NCON(c)-Qoffset]; 
1991/1114    
		cm->ref++; 
1991/1115    
		m->ref++; 
1991/1114    
		break; 
	} 
1991/1117    
	unlock(m); 
	poperror(); 
1991/1114    
	return c; 
} 
                 
void 
muxcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	int n; 
	Mux *m, *e; 
                 
	if(c->qid.path != CHDIR) 
		error(Eperm); 
                 
	omode = openmode(omode); 
                 
	m = muxes; 
1992/0630    
	for(e = &m[Nmuxchan]; m < e; m++) { 
1991/1115    
		if(m->name[0] == '\0' && m->ref == 0 && canlock(m)) { 
1991/1114    
			if(m->ref != 0) { 
				unlock(m); 
				continue; 
			} 
			break; 
		}	 
	} 
                 
	if(m == e) 
1992/0114    
		exhausted("multiplexers"); 
1991/1114    
                 
	strncpy(m->name, name, NAMELEN); 
	strncpy(m->user, u->p->user, NAMELEN); 
	m->perm = perm&~CHDIR; 
1991/1117    
	m->srv = 1; 
	if(perm&CHDIR) 
		m->srv = 0; 
1991/1114    
	unlock(m); 
                 
	n = m - muxes; 
1991/1117    
	c->qid = (Qid){(CHDIR&perm)|(n+1)<<8, 0}; 
1991/1114    
	c->flag |= COPEN; 
	c->mode = omode; 
} 
                 
void 
1992/0303    
muxclose(Chan *c) 
{ 
	Block *f1, *f2; 
	Con *cm, *e; 
	Mux *m; 
	int nc; 
                 
	if(c->qid.path&CHDIR) 
		return; 
                 
	m = &muxes[NMUX(c)]; 
	if(!(c->flag&COPEN) || m->srv) 
		return; 
                 
	nc = NCON(c); 
	f1 = 0; 
	f2 = 0; 
	switch(nc) { 
	case Qhead: 
		m->headopen = 0; 
		cm = m->connects; 
		for(e = &cm[Nmux]; cm < e; cm++) 
			if(cm->ref) 
				wakeup(&cm->conq.r); 
		lock(m); 
		if(--m->ref == 0) 
			f1 = muxclq(&m->headq); 
		unlock(m); 
		break; 
	case Qclone: 
		break; 
	default: 
		lock(m); 
		cm = &m->connects[nc-Qoffset]; 
		if(--cm->ref == 0) 
			f1 = muxclq(&cm->conq); 
		if(--m->ref == 0) 
			f1 = muxclq(&m->headq); 
		unlock(m); 
	} 
	if(f1) 
		freeb(f1); 
	if(f2) 
		freeb(f2); 
} 
                 
void 
1991/1114    
muxremove(Chan *c) 
{ 
	Mux *m; 
1991/1117    
	Chan *srv; 
1991/1114    
                 
1991/1117    
	if(c->qid.path == CHDIR)  
1991/1114    
		error(Eperm); 
                 
	m = &muxes[NMUX(c)]; 
1991/1117    
	if((c->qid.path&CHDIR) == 0 && m->srv == 0) 
		error(Eperm); 
		                 
1992/0113    
	if(strncmp(u->p->user, m->user, NAMELEN)) 
		error(Eperm); 
1991/1114    
                 
1991/1117    
	srv = 0; 
	lock(m); 
	if(m->srv) { 
		srv = m->c; 
		m->c = 0; 
	} 
1991/1114    
	m->name[0] = '\0'; 
1991/1117    
	unlock(m); 
	if(srv) 
		close(srv); 
                 
	muxclose(c); 
1991/1114    
} 
                 
void 
muxwstat(Chan *c, char *db) 
{ 
	Mux *m; 
	Dir d; 
	int nc; 
                 
	if(c->qid.path == CHDIR) 
		error(Eperm); 
                 
	m = &muxes[NMUX(c)]; 
1992/0113    
	if(strncmp(u->p->user, m->user, NAMELEN)) 
		error(Eperm); 
1991/1114    
                 
	convM2D(db, &d); 
	d.mode &= 0777; 
1991/1117    
	if(c->qid.path&CHDIR || m->srv) { 
1991/1114    
		strcpy(m->name, d.name); 
		m->perm = d.mode; 
		return; 
	} 
	nc = NCON(c); 
	switch(nc) { 
	case Qclone: 
		error(Eperm); 
	case Qhead: 
		m->perm = d.mode; 
		break; 
	default: 
1991/1115    
		m->connects[nc-Qoffset].perm = d.mode; 
1991/1114    
		break; 
	} 
} 
                 
long 
muxread(Chan *c, void *va, long n, ulong offset) 
{ 
	Mux *m; 
	Con *cm; 
	int bread; 
                 
1992/0711    
	USED(offset); 
1991/1114    
	if(c->qid.path & CHDIR) 
		return devdirread(c, va, n, 0, 0, muxgen); 
                 
	m = &muxes[NMUX(c)]; 
	switch(NCON(c)) { 
	case Qhead: 
		bread = muxreadq(m, &m->headq, va, n); 
		break; 
	case Qclone: 
		error(Eperm); 
	default: 
1991/1115    
		cm = &m->connects[NCON(c)-Qoffset]; 
1991/1114    
		bread = muxreadq(m, &cm->conq, va, n); 
		break; 
	} 
                 
	return bread; 
} 
                 
Con * 
muxhdr(Mux *m, char *h) 
{ 
	Con *c; 
                 
1991/1115    
	if(h[0] != Tmux || h[2] != 0) 
1992/0113    
		error(Emuxmsg); 
1991/1114    
                 
	c = &m->connects[h[1]]; 
	if(c < m->connects || c > &m->connects[Nmux])	 
1992/0113    
		error(Emuxmsg); 
1991/1114    
                 
	if(c->ref == 0) 
		return 0; 
                 
	return c; 
} 
                 
long 
muxwrite(Chan *c, void *va, long n, ulong offset) 
{ 
	Mux *m; 
	Con *cm; 
1991/1117    
	int muxid, fd; 
	char *a, hdr[3], buf[10]; 
1991/1114    
                 
1992/0711    
	USED(offset); 
1991/1115    
	if(c->qid.path&CHDIR) 
1991/1114    
		error(Eisdir); 
                 
1991/1117    
	m = &muxes[NMUX(c)]; 
	if(n > Maxmsg || (m->srv && n >= sizeof(buf))) 
1991/1115    
		error(Etoobig); 
                 
1991/1117    
	if(m->srv) { 
		memmove(buf, va, n);		/* so we can NUL-terminate */ 
		buf[n] = 0; 
		fd = strtoul(buf, 0, 0); 
1992/0825    
		fdtochan(fd, -1, 0, 0);		/* error check */ 
1991/1117    
		m->c = u->p->fgrp->fd[fd]; 
		incref(m->c); 
		return n; 
	} 
1991/1114    
	switch(NCON(c)) { 
	case Qclone: 
		error(Eperm); 
	case Qhead: 
		if(n < 2) 
1992/0113    
			error(Emuxmsg); 
1991/1114    
                 
		a = (char*)va; 
		memmove(hdr, a, sizeof(hdr)); 
		cm = muxhdr(m, hdr); 
		if(cm == 0) 
			error(Ehungup); 
                 
		muxwriteq(&cm->conq, a+sizeof(hdr), n-sizeof(hdr), 0, 0); 
		break; 
	default: 
		if(m->headopen == 0) 
			error(Ehungup); 
                 
1991/1115    
		muxid = NCON(c)-Qoffset; 
1991/1114    
		muxwriteq(&m->headq, va, n, 1, muxid); 
		break; 
	} 
                 
	return n; 
} 
                 
void 
muxwriteq(Dtq *q, char *va, long n, int addid, int muxid) 
{ 
	Block *head, *tail, *bp; 
1991/1115    
	ulong l, bwrite; 
1991/1114    
                 
	head = 0; 
1991/1117    
	tail = 0; 
1991/1114    
	if(waserror()) { 
		if(head) 
			freeb(head); 
		nexterror(); 
	} 
                 
1991/1115    
	bwrite = 0; 
1991/1114    
	while(n) { 
1991/1115    
		if(addid) { 
			bp = allocb(n+3); 
			bp->wptr[0] = Tmux; 
			bp->wptr[1] = muxid; 
			bp->wptr[2] = 0; 
			bp->wptr += 3; 
			bwrite += 3; 
			addid = 0; 
		} 
		else 
			bp = allocb(n); 
1991/1114    
		l = bp->lim - bp->wptr; 
1991/1115    
		if(l > n) 
			l = n; 
1991/1114    
		memmove(bp->wptr, va, l);	/* Interruptable thru fault */ 
		va += l; 
		bp->wptr += l; 
1991/1115    
		bwrite += l; 
1991/1114    
		n -= l; 
		if(head == 0) 
			head = bp; 
		else 
			tail->next = bp; 
		tail = bp; 
	} 
	poperror(); 
	tail->flags |= S_DELIM; 
1991/1115    
                 
	if(q->nb > Flowctl) 
		muxflow(q); 
                 
1991/1114    
	lock(&q->listlk); 
1991/1115    
	if(q->list == 0) 
		q->list = head; 
	else { 
		for(tail = q->list; tail->next; tail = tail->next) 
			; 
		tail->next = head; 
	} 
1991/1114    
	q->ndelim++; 
1991/1115    
	q->nb += bwrite; 
1991/1114    
	unlock(&q->listlk); 
1991/1115    
	wakeup(&q->r); 
1991/1114    
} 
                 
int 
1991/1115    
muxflw(Dtq *q) 
1991/1114    
{ 
1991/1115    
	return q->nb < Flowctl; 
} 
                 
void 
muxflow(Dtq *q) 
{ 
	qlock(&q->flow); 
	if(waserror()) { 
		qunlock(&q->flow); 
		nexterror(); 
	} 
	sleep(&q->flowr, muxflw, q); 
	poperror(); 
	qunlock(&q->flow); 
} 
                 
int 
havedata(Dtq *q) 
{ 
1991/1114    
	int n; 
                 
	lock(&q->listlk); 
	n = q->ndelim; 
	unlock(&q->listlk); 
	return n; 
} 
                 
ulong 
muxreadq(Mux *m, Dtq *q, char *va, ulong n) 
{ 
1992/0711    
	int l, nread; 
1991/1115    
	Block *bp, *f1; 
1991/1114    
                 
	qlock(&q->rd); 
	bp = 0; 
	if(waserror()) { 
		lock(&q->listlk); 
		if(bp) { 
			bp->next = q->list; 
			q->list = bp; 
		} 
		unlock(&q->listlk); 
1991/1117    
		qunlock(&q->rd); 
1991/1114    
		nexterror(); 
	} 
1991/1115    
	while(!havedata(q)) { 
		sleep(&q->r, havedata, q); 
		if(m->headopen == 0) 
1992/0114    
			error(Emuxshutdown); 
1991/1115    
	} 
1991/1114    
                 
	nread = 0; 
1991/1115    
	f1 = 0; 
	lock(&q->listlk); 
1991/1114    
	while(n) { 
		bp = q->list; 
		q->list = bp->next; 
		bp->next = 0; 
		unlock(&q->listlk); 
1991/1115    
		if(f1) { 
			freeb(f1); 
			f1 = 0; 
		} 
1991/1114    
		l = BLEN(bp); 
1991/1115    
		if(l > n) 
			l = n; 
1991/1114    
		memmove(va, bp->rptr, l);	/* Interruptable thru fault */ 
		va += l; 
		bp->rptr += l; 
		n -= l; 
1991/1115    
		nread += l; 
1991/1114    
		lock(&q->listlk); 
1991/1115    
		if(bp->rptr == bp->wptr) 
			f1 = bp; 
		else { 
1991/1114    
			bp->next = q->list; 
			q->list = bp; 
		} 
1991/1115    
		if(bp->flags&S_DELIM) { 
1991/1114    
			q->ndelim--; 
			break; 
1991/1115    
		} 
1991/1114    
	} 
1991/1115    
	q->nb -= nread; 
	unlock(&q->listlk); 
	if(f1) 
		freeb(f1); 
1991/1114    
	qunlock(&q->rd); 
1991/1115    
	poperror(); 
	if(q->nb < Flowctl) 
		wakeup(&q->flowr); 
1991/1114    
	return nread; 
1991/1115    
} 
                 
Block * 
muxclq(Dtq *q) 
{ 
	Block *f; 
                 
	f = q->list; 
	q->list = 0; 
	q->nb = 0; 
	q->ndelim = 0; 
	return f; 
1991/1114    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)