## 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
|