Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devloopback.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/devloopback.c 2000/0617
## diff -e /dev/null /n/emeliedump/2000/0617/sys/src/9/port/devloopback.c
0a
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"

#include	"netif.h"

typedef struct Link	Link;
typedef struct Loop	Loop;

struct Link
{
	Lock;

	int	ref;

	int	nodrop;		/* disable dropping on iq overflow */
	int	soverflows;	/* packets dropped because iq overflowed */
	int	drops;		/* packets deliberately dropped */

	long	delay0;		/* fastticks of delay in the link */
	long	delayn;		/* fastticks of delay per byte */

	Block	*tq;		/* transmission queue */
	Block	*tqtail;
	vlong	tout;		/* time the last packet in tq is really out */
	vlong	tin;		/* time the head packet in tq enters the remote side  */

	Queue	*oq;		/* output queue from other side & packets in the link */
	Queue	*iq;
};

struct Loop
{
	QLock;
	int	ref;
	int	minmtu;		/* smallest block transmittable */
	Loop	*next;
	ulong	path;
	long	limit;		/* queue buffering limit */
	Link	link[2];
};

static struct
{
	Lock;
	ulong	path;
} loopbackalloc;

enum
{
	Qdir,
	Qctl,
	Qstatus,
	Qstats,
	Qdata0,
	Qdata1,

	TMSIZE		= 8,

	NLOOPBACKS	= 1,
	LOOPBACKSIZE	= 32*1024,		/*ZZZ change to settable; size of queues */
};

Dirtab loopbackdir[] =
{
	"ctl",		{Qctl},		0,			0222,
	"status",	{Qstatus},	0,			0222,
	"stats",	{Qstats},	0,			0444,
	"data",		{Qdata0},	0,			0666,
	"data1",	{Qdata1},	0,			0666,
};

static Loop	loopbacks[NLOOPBACKS];

static void	looper(Loop *lb);
static long	loopoput(Loop *lb, Link *link, Block *bp);
static void	ptime(uchar *p, vlong t);
static vlong	gtime(uchar *p);
static void	closelink(Link *link, int dofree);
static vlong	pushlink(Link *link, vlong now);
static void	freelb(Loop *lb);

static void
loopbackinit(void)
{
	int i;

	for(i = 0; i < NLOOPBACKS; i++)
		loopbacks[i].path = i;
}

static Chan*
loopbackattach(char *spec)
{
	Loop *lb;
	Queue *q;
	Chan *c;
	int chan;

	c = devattach('X', spec);
	lb = &loopbacks[0];

	qlock(lb);
	if(waserror()){
		qunlock(lb);
		nexterror();
	}

	lb->ref++;
	if(lb->ref == 1){
		lb->limit = LOOPBACKSIZE;
		for(chan = 0; chan < 2; chan++){
			q = qopen(lb->limit, 0, 0, 0);
			lb->link[chan].iq = q;
			if(q == nil){
				freelb(lb);
				exhausted("memory");
			}
			q = qopen(lb->limit, 0, 0, 0);
			lb->link[chan].oq = q;
			if(q == nil){
				freelb(lb);
				exhausted("memory");
			}
			lb->link[chan].nodrop = 1;
		}
	}
	poperror();
	qunlock(lb);

	c->qid = (Qid){CHDIR|NETQID(2*lb->path, Qdir), 0};
	c->aux = lb;
	c->dev = 0;
	return c;
}

static Chan*
loopbackclone(Chan *c, Chan *nc)
{
	Loop *lb;
	int chan;

	lb = c->aux;
	nc = devclone(c, nc);
	qlock(lb);
	lb->ref++;
	if(c->flag & COPEN){
		switch(chan = NETTYPE(c->qid.path)){
		case Qdata0:
		case Qdata1:
			chan -= Qdata0;
			lb->link[chan].ref++;
			break;
		}
	}
	qunlock(lb);
	return nc;
}

static int
loopbackgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
{
	Loop *lb;
	int id, len, chan;

	if(i == DEVDOTDOT){
		devdir(c, c->qid, "#X", 0, eve, CHDIR|0555, dp);
		return 1;
	}

	id = NETID(c->qid.path);
	if(i > 1)
		id++;
	if(tab==nil || i>=ntab)
		return -1;
	tab += i;
	lb = c->aux;
	switch(chan = tab->qid.path){
	case Qdata0:
	case Qdata1:
		chan -= Qdata0;
		len = qlen(lb->link[chan].iq);
		break;
	default:
		len = tab->length;
		break;
	}
	devdir(c, (Qid){NETQID(id, tab->qid.path),0}, tab->name, len, eve, tab->perm, dp);
	return 1;
}


static int
loopbackwalk(Chan *c, char *name)
{
	return devwalk(c, name, loopbackdir, nelem(loopbackdir), loopbackgen);
}

static void
loopbackstat(Chan *c, char *db)
{
	Loop *lb;
	Dir dir;
	int chan;

	lb = c->aux;
	switch(chan = NETTYPE(c->qid.path)){
	case Qdir:
		devdir(c, c->qid, ".", nelem(loopbackdir)*DIRLEN, eve, CHDIR|0555, &dir);
		break;
	case Qdata0:
	case Qdata1:
		chan -= Qdata0;
		devdir(c, c->qid, "data", qlen(lb->link[chan].iq), eve, 0660, &dir);
		break;
	default:
		panic("loopbackstat");
	}
	convD2M(&dir, db);
}

/*
 *  if the stream doesn't exist, create it
 */
static Chan*
loopbackopen(Chan *c, int omode)
{
	Loop *lb;
	int chan;

	if(c->qid.path & CHDIR){
		if(omode != OREAD)
			error(Ebadarg);
		c->mode = omode;
		c->flag |= COPEN;
		c->offset = 0;
		return c;
	}

	lb = c->aux;
	qlock(lb);
	switch(chan = NETTYPE(c->qid.path)){
	case Qdata0:
	case Qdata1:
		chan -= Qdata0;
		lb->link[chan].ref++;
		break;
	}
	qunlock(lb);

	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

static void
loopbackclose(Chan *c)
{
	Loop *lb;
	int ref, chan;

	lb = c->aux;

	qlock(lb);
	if(c->flag & COPEN){
		/*
		 *  closing either side hangs up the stream
		 */
		switch(chan = NETTYPE(c->qid.path)){
		case Qdata0:
		case Qdata1:
			chan -= Qdata0;
			if(--lb->link[chan].ref == 0){
				qhangup(lb->link[chan ^ 1].oq, nil);
				looper(lb);
			}
			break;
		}
	}


	/*
	 *  if both sides are closed, they are reusable
	 */
	if(lb->link[0].ref == 0 && lb->link[1].ref == 0){
		for(chan = 0; chan < 2; chan++){
			closelink(&lb->link[chan], 0);
			qreopen(lb->link[chan].iq);
			qreopen(lb->link[chan].oq);
		}
	}
	ref = --lb->ref;
	if(ref == 0)
		freelb(lb);
	qunlock(lb);
}

static void
freelb(Loop *lb)
{
	int chan;

	for(chan = 0; chan < 2; chan++)
		closelink(&lb->link[chan], 1);
}

/*
 * called with the Loop qlocked,
 * so only pushlink can mess with the queues
 */
static void
closelink(Link *link, int dofree)
{
	Queue *iq, *oq;
	Block *bp;

	ilock(link);
	iq = link->iq;
	oq = link->oq;
	bp = link->tq;
	link->tq = nil;
	link->tqtail = nil;
	link->tout = 0;
	link->tin = 0;
	iunlock(link);
	if(iq != nil){
		qclose(iq);
		if(dofree){
			ilock(link);
			free(iq);
			link->iq = nil;
			iunlock(link);
		}
	}
	if(oq != nil){
		qclose(oq);
		if(dofree){
			ilock(link);
			free(oq);
			link->oq = nil;
			iunlock(link);
		}
	}
	freeblist(bp);
}

static long
loopbackread(Chan *c, void *va, long n, vlong)
{
	Loop *lb;
	int chan;

	lb = c->aux;
//ZZZ ctl message to set q limit -- qsetlimit(q, limit)
//ZZZ ctl message to set blocking/dropping	qnoblock(q, dropit)
//ZZZ ctl message for delays
	switch(chan = NETTYPE(c->qid.path)){
	case Qdir:
		return devdirread(c, va, n, loopbackdir, nelem(loopbackdir), loopbackgen);
	case Qdata0:
	case Qdata1:
		chan -= Qdata0;
		return qread(lb->link[chan].iq, va, n);
	default:
		panic("loopbackread");
	}
	return -1;	/* not reached */
}

static Block*
loopbackbread(Chan *c, long n, ulong offset)
{
	Loop *lb;
	int chan;

	lb = c->aux;
	switch(chan = NETTYPE(c->qid.path)){
	case Qdata0:
	case Qdata1:
		chan -= Qdata0;
		return qbread(lb->link[chan].iq, n);
	}

	return devbread(c, n, offset);
}

static long
loopbackbwrite(Chan *c, Block *bp, ulong off)
{
	Loop *lb;
	int chan;

	lb = c->aux;
	switch(chan = NETTYPE(c->qid.path)){
	case Qdata0:
	case Qdata1:
		chan -= Qdata0;
		return loopoput(lb, &lb->link[chan ^ 1], bp);
	default:
		return devbwrite(c, bp, off);
	}
}

static long
loopbackwrite(Chan *c, void *va, long n, vlong off)
{
	Block *bp;

	if(!islo())
		print("loopbackwrite hi %lux\n", getcallerpc(&c));

	switch(NETTYPE(c->qid.path)){
	case Qdata0:
	case Qdata1:
		bp = allocb(n);
		if(waserror()){
			freeb(bp);
			nexterror();
		}
		memmove(bp->wp, va, n);
		poperror();
		bp->wp += n;
		return loopbackbwrite(c, bp, off);
	case Qctl:
	default:
		panic("loopbackwrite");
	}

	return n;
}

static long
loopoput(Loop *lb, Link *link, Block *bp)
{
	long n;

	n = BLEN(bp);

	/* make it a single block with space for the loopback header */
	bp = padblock(bp, TMSIZE);
	if(bp->next)
		bp = concatblock(bp);
	if(BLEN(bp) < lb->minmtu)
		bp = adjustblock(bp, lb->minmtu);

	qbwrite(link->oq, bp);
	looper(lb);
	return n;
}

/*
 * move blocks between queues if they are ready.
 * schedule an interrupt for the next interesting time
 */
static void
looper(Loop *lb)
{
	vlong t, tt;

	tt = fastticks(nil);
again:;
	t = pushlink(&lb->link[0], tt);
	tt = pushlink(&lb->link[1], tt);
	if(t > tt && tt)
		t = tt;
	if(t){
		tt = fastticks(nil);
		if(tt <= t)
			goto again;
		//schedule an intr at tt-t fastticks
	}
}

static vlong
pushlink(Link *link, vlong now)
{
	Block *bp;
	vlong t;

	/*
	 * put another block in the link queue
	 */
	ilock(link);
	if(link->iq == nil || link->oq == nil){
		iunlock(link);
		return 0;
	}
	t = link->tout;
	if(!t || t < now){
		bp = qget(link->oq);
		if(bp != nil){
			if(!t)
				t = now;
			link->tout = t + BLEN(bp) * link->delayn;
			ptime(bp->rp, t + link->delay0);
//ZZZ drop or introduce errors here
			if(link->tq == nil)
				link->tq = bp;
			else
				link->tqtail->next = bp;
			link->tqtail = bp;
		}else
			link->tout = 0;
	}

	/*
	 * put more blocks into the receive queue
	 */
	t = 0;
	while(bp = link->tq){
		t = gtime(bp->rp);
		if(t > now)
			break;
		bp->rp += TMSIZE;
		link->tq = bp->next;
		bp->next = nil;
		if(link->nodrop)
			qpassnolim(link->iq, bp);
		else if(qpass(link->iq, bp) < 0)
			link->soverflows++;
		t = 0;
	}
	if(bp == nil && qisclosed(link->oq) && !qcanread(link->oq) && !qisclosed(link->iq))
		qhangup(link->iq, nil);
	link->tin = t;
	if(!t || t < link->tout)
		t = link->tout;
	iunlock(link);
	return t;
}

static void
ptime(uchar *p, vlong t)
{
	ulong tt;

	tt = t >> 32;
	p[0] = tt >> 24;
	p[1] = tt >> 16;
	p[2] = tt >> 8;
	p[3] = tt;
	tt = t;
	p[4] = tt >> 24;
	p[5] = tt >> 16;
	p[6] = tt >> 8;
	p[7] = tt;
}

static vlong
gtime(uchar *p)
{
	ulong t1, t2;

	t1 = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
	t2 = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
	return ((vlong)t1 << 32) | t2;
}

Dev loopbackdevtab = {
	'X',
	"loopback",

	devreset,
	loopbackinit,
	loopbackattach,
	loopbackclone,
	loopbackwalk,
	loopbackstat,
	loopbackopen,
	devcreate,
	loopbackclose,
	loopbackread,
	loopbackbread,
	loopbackwrite,
	loopbackbwrite,
	devremove,
	devwstat,
};
.
## diffname port/devloopback.c 2000/0708
## diff -e /n/emeliedump/2000/0617/sys/src/9/port/devloopback.c /n/emeliedump/2000/0708/sys/src/9/port/devloopback.c
533d
529,531c
	link->tin = tin;
	if(!tin || tin > tout && tout)
		tin = tout;

	link->ci.when = tin;
	if(tin){
		if(tin < now)
			panic("loopback unfinished business");
		cycintradd(&link->ci);
	}
.
525c
		tin = 0;
.
521c
		if(!link->indrop)
.
518c
		bp->rp += Tmsize;
.
515,516c
		tin = gtime(bp->rp);
		if(tin > now)
.
513c
	tin = 0;
.
510a
	 * record the next time a packet can be sent,
	 * but don't schedule an interrupt if none is waiting
	 */
	link->tout = tout;
	if(!qcanread(link->oq))
		tout = 0;

	/*
.
506,507c
		}
.
495,500c
		if(bp == nil){
			tout = 0;
			break;
		}

		/*
		 * can't send the packet before it gets queued
		 */
		tin = gtime(bp->rp);
		if(tin > tout)
			tout = tin;
		tout = tout + (BLEN(bp) - Tmsize) * link->delayn;

		/*
		 * drop packets
		 */
		if(link->droprate && nrand(link->droprate) == 0)
			link->drops++;
		else{
			ptime(bp->rp, tout + link->delay0);
.
492,493c
	cycintrdel(&link->ci);

	/*
	 * put more blocks into the xmit queue
	 * use the time the last packet was supposed to go out
	 * as the start time for the next packet, rather than
	 * the current time.  this more closely models a network
	 * device which can queue multiple output packets.
	 */
	tout = link->tout;
	if(!tout)
		tout = now;
	while(tout <= now){
.
490c
		return;

.
482c
	vlong tout, tin;
.
478c
static void
linkintr(Ureg*, Cycintr *ci)
{
	Link *link;

	link = ci->a;
	pushlink(link, ci->when);
}

/*
 * move blocks between queues if they are ready.
 * schedule an interrupt for the next interesting time.
 *
 * must be called with the link ilocked.
 */
static void
.
464,475c
	t = fastticks(nil);
	for(chan = 0; chan < 2; chan++)
		pushlink(&lb->link[chan], t);
	clockintrsched();
.
462c
	vlong t;
	int chan;
.
455,458d
450a

.
449a
	link->packets++;
	link->bytes += n;

.
448a
	ptime(bp->rp, fastticks(nil));
.
443,444c
	/* make it a single block with space for the loopback timing header */
	bp = padblock(bp, Tmsize);
.
430c
		error(Eperm);
.
428a
		lb = c->aux;
		link = &lb->link[ID(c->qid.path)];
		cb = parsecmd(va, n);
		if(cb->nf < 1)
			error("short control request");
		if(strcmp(cb->f[0], "delay") == 0){
			if(cb->nf != 3)
				error("usage: delay latency bytedelay");
			d0ns = strtol(cb->f[1], nil, 10);
			dnns = strtol(cb->f[2], nil, 10);

			/*
			 * it takes about 20000 cycles on a pentium ii
			 * to run pushlink; perhaps this should be accounted.
			 */
			d0 = NS2FASTHZ(d0ns);
			dn = NS2FASTHZ(dnns);

			ilock(link);
			link->delay0 = d0;
			link->delayn = dn;
			link->delay0ns = d0ns;
			link->delaynns = dnns;
			iunlock(link);
		}else if(strcmp(cb->f[0], "indrop") == 0){
			if(cb->nf != 2)
				error("usage: indrop [01]");
			ilock(link);
			link->indrop = strtol(cb->f[1], nil, 0) != 0;
			iunlock(link);
		}else if(strcmp(cb->f[0], "droprate") == 0){
			if(cb->nf != 2)
				error("usage: droprate ofn");
			ilock(link);
			link->droprate = strtol(cb->f[1], nil, 0);
			iunlock(link);
		}else if(strcmp(cb->f[0], "limit") == 0){
			if(cb->nf != 2)
				error("usage: droprate ofn");
			ilock(link);
			link->limit = strtol(cb->f[1], nil, 0);
			qsetlimit(link->oq, link->limit);
			qsetlimit(link->iq, link->limit);
			iunlock(link);
		}else if(strcmp(cb->f[0], "reset") == 0){
			if(cb->nf != 1)
				error("usage: reset");
			ilock(link);
			link->packets = 0;
			link->bytes = 0;
			link->indrop = 0;
			link->soverflows = 0;
			link->drops = 0;
			iunlock(link);
		}else
			error("unknown control request");
		break;
.
413,418c
	switch(TYPE(c->qid.path)){
	case Qdata:
.
411a
	long d0, dn, d0ns, dnns;
.
410a
	Loop *lb;
	Link *link;
	Cmdbuf *cb;
.
398,405c
	if(TYPE(c->qid.path) == Qdata)
		return loopoput(lb, &lb->link[ID(c->qid.path) ^ 1], bp);
	return devbwrite(c, bp, off);
.
395d
381,386c
	if(TYPE(c->qid.path) == Qdata)
		return qbread(lb->link[ID(c->qid.path)].iq, n);
.
378d
371c
	return rv;
.
369c
		error(Eperm);
		return -1;	/* not reached */
	case Qtopdir:
	case Qloopdir:
	case Qportdir:
		return devdirread(c, va, n, nil, 0, loopbackgen);
	case Qdata:
		return qread(lb->link[ID(c->qid.path)].iq, va, n);
	case Qstatus:
		link = &lb->link[ID(c->qid.path)];
		buf = smalloc(Statelen);
		rv = snprint(buf, Statelen, "delay %ld %ld\n", link->delay0ns, link->delaynns);
		rv += snprint(buf+rv, Statelen-rv, "limit %ld\n", link->limit);
		rv += snprint(buf+rv, Statelen-rv, "indrop %d\n", link->indrop);
		snprint(buf+rv, Statelen-rv, "droprate %ld\n", link->droprate);
		rv = readstr(offset, va, n, buf);
		free(buf);
		break;
	case Qstats:
		link = &lb->link[ID(c->qid.path)];
		buf = smalloc(Statelen);
		rv = snprint(buf, Statelen, "packets: %ld\n", link->packets);
		rv += snprint(buf+rv, Statelen-rv, "bytes: %ld\n", link->bytes);
		rv += snprint(buf+rv, Statelen-rv, "dropped: %ld\n", link->drops);
		snprint(buf+rv, Statelen-rv, "soft overflows: %ld\n", link->soverflows);
		rv = readstr(offset, va, n, buf);
		free(buf);
		break;
.
358,367c
	switch(TYPE(c->qid.path)){
.
355c
	Link *link;
	char *buf;
	long rv;
.
352c
loopbackread(Chan *c, void *va, long n, vlong offset)
.
328a
	cycintrdel(&link->ci);
.
293a
			qsetlimit(lb->link[chan].oq, lb->link[chan].limit);
			qsetlimit(lb->link[chan].iq, lb->link[chan].limit);
.
269,281c

	/*
	 * closing either side hangs up the stream
	 */
	if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata){
		chan = ID(c->qid.path);
		if(--lb->link[chan].ref == 0){
			qhangup(lb->link[chan ^ 1].oq, nil);
			looper(lb);
.
245,251c
	if(TYPE(c->qid.path) == Qdata)
		lb->link[ID(c->qid.path)].ref++;
.
232d
205,222c
	devstat(c, db, nil, 0, loopbackgen);
.
199c
	return devwalk(c, name, nil, 0, loopbackgen);
.
191,192d
189c
		if(type == Qdata){
			lb = c->aux;
			len = qlen(lb->link[ID(c->qid.path)].iq);
		}
		devdir(c, c->qid, tab->name, len, eve, tab->perm, dp);
		return 1;
.
187a
		/* non directory entries end up here; must be in lowest level */
		if(c->qid.path & CHDIR)
			panic("loopbackgen: unexpected directory");	
		if(i != 0)
			return -1;
		tab = &loopdirs[type];
		if(tab == nil)
			panic("loopbackgen: unknown type: %d", type);
.
174,186c
	switch(type){
	case Qtopdir:
		if(i != 0)
			return -1;
		snprint(buf, sizeof(buf), "loopback%ld", c->dev);
		devdir(c, (Qid){QID(0, Qloopdir) | CHDIR, 0}, buf, 0, eve, 0555, dp);
		return 1;
	case Qloopdir:
		if(i >= 2)
			return -1;
		snprint(buf, sizeof(buf), "%d", i);
		devdir(c, (Qid){QID(i, QID(0, Qportdir)) | CHDIR, 0}, buf, 0, eve, 0555, dp);
		return 1;
	case Qportdir:
		if(i >= nelem(loopportdir))
			return -1;
		tab = &loopportdir[i];
		devdir(c, (Qid){QID(ID(c->qid.path), tab->qid.path), 0}, tab->name, tab->length, eve, tab->perm, dp);
		return 1;
.
170c
		switch(type){
		case Qtopdir:
		case Qloopdir:
			snprint(buf, sizeof(buf), "#X%ld", c->dev);
			devdir(c, (Qid){CHDIR|QID(0, Qtopdir), 0}, buf, 0, eve, 0555, dp);
			break;
		case Qportdir:
			snprint(buf, sizeof(buf), "loopback%ld", c->dev);
			devdir(c, (Qid){CHDIR|QID(0, Qloopdir), 0}, buf, 0, eve, 0555, dp);
			break;
		default:
			panic("loopbackgen %lux", c->qid.path);
		}
.
168a
	type = TYPE(c->qid.path);
.
167c
	Dirtab *tab;
	char buf[NAMELEN];
	int len, type;
.
164c
loopbackgen(Chan *c, Dirtab*, int, int i, Dir *dp)
.
150,158c
	if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata)
		lb->link[ID(c->qid.path)].ref++;
.
144d
134c
	c->qid = (Qid){CHDIR|QID(0, Qtopdir), 0};
.
128c
			lb->link[chan].indrop = 1;

			lb->link[chan].delayn = NS2FASTHZ(Delayn);
			lb->link[chan].delaynns = Delayn;
			lb->link[chan].delay0 = NS2FASTHZ(Delay0);
			lb->link[chan].delay0ns = Delay0;
.
122c
			q = qopen(lb->link[chan].limit, 0, 0, 0);
.
116c
			lb->link[chan].ci.a = &lb->link[chan];
			lb->link[chan].ci.f = linkintr;
			lb->link[chan].limit = Loopqlim;
			q = qopen(lb->link[chan].limit, 0, 0, 0);
.
114c
		fastticks(&fasthz);
.
107a
		lb->ref--;
.
104c
	lb = &loopbacks[dev];
.
102a
	if(!havecycintr())
		error("can't time packets");

	dev = 0;
	if(spec != nil){
		dev = atoi(spec);
		if(dev >= Nloopbacks)
			error(Ebadspec);
	}

.
101a
	int dev;
.
92a

	/* invert directory tables for non-directory entries */
	for(i=0; i<nelem(loopportdir); i++)
		loopdirs[loopportdir[i].qid.path] = loopportdir[i];
.
91c
	for(i = 0; i < Nloopbacks; i++)
.
84a
static void	linkintr(Ureg*, Cycintr *ci);
.
83c
static void	pushlink(Link *link, vlong now);
.
77a
static uvlong	fasthz;

#define TYPE(x) 	((x)&0xff)
#define ID(x) 		(((x)&~CHDIR)>>8)
#define QID(x,y) 	(((x)<<8)|(y))

#define NS2FASTHZ(t)	((fasthz*(t))/1000000000);

.
76c
static Loop	loopbacks[Nloopbacks];
.
74a
static Dirtab loopdirs[MaxQ];
.
72,73c
	"data",		{Qdata},	0,			0666,
.
70c
	"status",	{Qstatus},	0,			0444,
.
67c
static Dirtab loopportdir[] =
.
63,64c
	Nloopbacks	= 1,

	Statelen	= 23*1024,	/* status buffer size */

	Tmsize		= 8,
	Delayn 		= 10000,	/* default delays */
	Delay0 		= 2500000,

	Loopqlim	= 32*1024,	/* default size of queues */
.
61c
	MaxQ,
.
58,59c
	Qdata,
.
54c
	Qtopdir=	1,		/* top level directory */

	Qloopdir,			/* loopback* directory */

	Qportdir,			/* directory each end of the loop */
.
42d
32a

	Cycintr	ci;		/* time to move packets from  next packet from oq */
.
30a
	long	limit;		/* queue buffering limit */
.
23,24c
	long	delay0ns;	/* nanosec of delay in the link */
	long	delaynns;	/* nanosec of delay per byte */
	long	delay0;		/* fastticks of delay */
	long	delayn;
.
19,21c
	long	packets;	/* total number of packets sent */
	long	bytes;		/* total number of bytes sent */
	int	indrop;		/* enable dropping on iq overflow */
	long	soverflows;	/* packets dropped because iq overflowed */
	long	droprate;	/* drop 1/droprate packets in tq */
	long	drops;		/* packets deliberately dropped */
.
8,9d
## diffname port/devloopback.c 2000/0726
## diff -e /n/emeliedump/2000/0708/sys/src/9/port/devloopback.c /n/emeliedump/2000/0726/sys/src/9/port/devloopback.c
524c
				error("usage: limit maxqsize");
.
## diffname port/devloopback.c 2000/0727
## diff -e /n/emeliedump/2000/0726/sys/src/9/port/devloopback.c /n/emeliedump/2000/0727/sys/src/9/port/devloopback.c
300a
	}
.
299c
	if(TYPE(c->qid.path) == Qdata){
		if(lb->link[ID(c->qid.path)].ref){
			qunlock(lb);
			error(Einuse);
		}
.
## diffname port/devloopback.c 2000/0912
## diff -e /n/emeliedump/2000/0727/sys/src/9/port/devloopback.c /n/emeliedump/2000/0912/sys/src/9/port/devloopback.c
499c
			d0ns = strtoll(cb->f[1], nil, 10);
.
477c
	vlong d0, d0ns;
	long dn, dnns;
.
426c
		rv = snprint(buf, Statelen, "delay %lld %ld\n", link->delay0ns, link->delaynns);
.
71c
	Nloopbacks	= 5,
.
26c
	vlong	delay0;		/* fastticks of delay */
.
24c
	vlong	delay0ns;	/* nanosec of delay in the link */
.
## diffname port/devloopback.c 2000/0913
## diff -e /n/emeliedump/2000/0912/sys/src/9/port/devloopback.c /n/emeliedump/2000/0913/sys/src/9/port/devloopback.c
184c
	c->dev = dev;
.
## diffname port/devloopback.c 2001/0331
## diff -e /n/emeliedump/2000/0913/sys/src/9/port/devloopback.c /n/emeliedump/2001/0331/sys/src/9/port/devloopback.c
547a
		free(cb);
.
494a
		if(waserror()){
			free(cb);
			nexterror();
		}
.
475,476c
	Cmdbuf *volatile cb;
	Block *volatile bp;
.
126c
	Loop *volatile lb;
.
## diffname port/devloopback.c 2001/0504
## diff -e /n/emeliedump/2001/0331/sys/src/9/port/devloopback.c /n/emeliedump/2001/0504/sys/src/9/port/devloopback.c
573a
	poperror();
.
568a
	if(waserror()){
		freeb(bp);
		nexterror();
	}
.
562c
loopoput(Loop *lb, Link *link, Block *volatile bp)
.
## diffname port/devloopback.c 2001/0530
## diff -e /n/emeliedump/2001/0504/sys/src/9/port/devloopback.c /n/emeliedump/2001/0530/sys/src/9/port/devloopback.c
748d
288c
	if(c->qid.type & QTDIR){
.
277c
	return devstat(c, db, n, nil, 0, loopbackgen);
.
274,275c
static int
loopbackstat(Chan *c, uchar *db, int n)
.
271c
	return devwalk(c, nc, name, nname, nil, 0, loopbackgen);
.
268,269c
static Walkqid*
loopbackwalk(Chan *c, Chan *nc, char **name, int nname)
.
250c
		if(c->qid.type & QTDIR)
.
246c
		mkqid(&qid, QID(ID(c->qid.path), tab->qid.path), 0, QTDIR);
		devdir(c, qid, tab->name, tab->length, eve, tab->perm, dp);
.
239,240c
		snprint(up->genbuf, sizeof(up->genbuf), "%d", i);
		mkqid(&qid, QID(i, QID(0, Qportdir)), 0, QTDIR);
		devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
233,234c
		snprint(up->genbuf, sizeof(up->genbuf), "loopback%ld", c->dev);
		mkqid(&qid, QID(0, Qloopdir), 0, QTDIR);
		devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
220,221c
			snprint(up->genbuf, sizeof(up->genbuf), "loopback%ld", c->dev);
			mkqid(&qid, QID(0, Qloopdir), 0, QTDIR);
			devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
216,217c
			snprint(up->genbuf, sizeof(up->genbuf), "#X%ld", c->dev);
			mkqid(&qid, QID(0, Qtopdir), 0, QTDIR);
			devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
209a
	Qid qid;
.
208d
204c
loopbackgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
.
182c
	mkqid(&c->qid, QID(0, Qtopdir), 0, QTDIR);
.
95,97c
#define TYPE(x) 	(((ulong)(x))&0xff)
#define ID(x) 		(((ulong)(x))>>8)
#define QID(x,y) 	((((ulong)(x))<<8)|((ulong)(y)))
.
## diffname port/devloopback.c 2001/0601
## diff -e /n/emeliedump/2001/0530/sys/src/9/port/devloopback.c /n/emeliedump/2001/0601/sys/src/9/port/devloopback.c
276c
	Walkqid *wq;
	Loop *lb;

	wq = devwalk(c, nc, name, nname, nil, 0, loopbackgen);
	if(wq != nil && wq->clone != nil && wq->clone != c){
		lb = c->aux;
		qlock(lb);
		lb->ref++;
		if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata)
			lb->link[ID(c->qid.path)].ref++;
		qunlock(lb);
	}
	return wq;
.
250c
		mkqid(&qid, QID(ID(c->qid.path), tab->qid.path), 0, QTFILE);
.
188,202d
## diffname port/devloopback.c 2001/0609
## diff -e /n/emeliedump/2001/0601/sys/src/9/port/devloopback.c /n/emeliedump/2001/0609/sys/src/9/port/devloopback.c
553a
		poperror();
.
## diffname port/devloopback.c 2001/1207
## diff -e /n/emeliedump/2001/0609/sys/src/9/port/devloopback.c /n/emeliedump/2001/1207/sys/src/9/port/devloopback.c
312a
	c->iounit = qiomaxatomic;
.
## diffname port/devloopback.c 2002/0109
## diff -e /n/emeliedump/2001/1207/sys/src/9/port/devloopback.c /n/emeliedump/2002/0109/sys/src/9/port/devloopback.c
750a
	devshutdown,
.
## diffname port/devloopback.c 2002/0125
## diff -e /n/emeliedump/2002/0109/sys/src/9/port/devloopback.c /n/emeliedump/2002/0125/sys/src/9/port/devloopback.c
211c
			panic("loopbackgen %llux", c->qid.path);
.
## diffname port/devloopback.c 2002/0405
## diff -e /n/emeliedump/2002/0125/sys/src/9/port/devloopback.c /n/emeliedump/2002/0405/sys/src/9/port/devloopback.c
713c
		timeradd(&link->ci);
.
636c
	timerdel(&link->ci);
.
607c
linkintr(Ureg*, Timer *ci)
.
384c
	timerdel(&link->ci);
.
132c
	if(!havetimer())
.
108c
static void	linkintr(Ureg*, Timer *ci);
.
38c
	Timer	ci;		/* time to move packets from  next packet from oq */
.
## diffname port/devloopback.c 2002/0410
## diff -e /n/emeliedump/2002/0405/sys/src/9/port/devloopback.c /n/emeliedump/2002/0410/sys/src/9/port/devloopback.c
132,134d
## diffname port/devloopback.c 2002/0413
## diff -e /n/emeliedump/2002/0410/sys/src/9/port/devloopback.c /n/emeliedump/2002/0413/sys/src/9/port/devloopback.c
600d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.