M ip/ip.h => ip/ip.h +1 -1
@@ 237,7 237,7 @@ struct IProuter {
*/
struct Fs
{
- Lock;
+ RWlock;
int np;
Proto* p[Maxproto+1]; /* list of supported protocols */
M ip/ipmux.c => ip/ipmux.c +92 -142
@@ 9,7 9,9 @@
#define DPRINT if(0)print
-typedef struct Iphdr Iphdr;
+typedef struct Iphdr Iphdr;
+typedef struct Ipmuxrock Ipmuxrock;
+typedef struct Ipmux Ipmux;
enum
{
@@ 28,6 30,7 @@ struct Iphdr
uchar cksum[2]; /* Header checksum */
uchar src[4]; /* IP source */
uchar dst[4]; /* IP destination */
+ uchar data[1]; /* start of data */
};
enum
@@ 48,8 51,9 @@ char *ftname[] =
[Tifc] "ifc",
};
-typedef struct Ipmux Ipmux;
-
+/*
+ * a node in the decision tree
+ */
struct Ipmux
{
Ipmux *yes;
@@ 64,6 68,15 @@ struct Ipmux
int ref; /* so we can garbage collect */
};
+/*
+ * someplace to hold per conversation data
+ */
+struct Ipmuxrock
+{
+ Ipmux *chain;
+ int proto;
+};
+
static char*
skipwhite(char *p)
{
@@ 409,7 422,7 @@ ipmuxmerge(Ipmux *a, Ipmux *b)
* remove a chain from a demux tree. This is like merging accept that
* we remove instead of insert.
*/
-int
+static int
ipmuxremove(Ipmux **l, Ipmux *f)
{
int n, rv;
@@ 459,137 472,6 @@ ipmuxremove(Ipmux **l, Ipmux *f)
return ipmuxremove(&ft->yes, f->yes);
}
-void
-printtree(Biobuf *b, Ipmux *f, int level)
-{
- int i, j;
- uchar *p;
-
- if(f == nil) {
- Bprint(b, "\n");
- return;
- }
- for(i = 0; i < level; i++)
- Bprint(b, " ");
- Bprint(b, "%s", ftname[f->type]);
- if(f->type == Tdata)
- Bprint(b, "[%d:%d]", f->off, f->off+f->len-1);
- if(f->mask){
- switch(f->type){
- case Tifc:
- case Tsrc:
- case Tdst:
- Bprint(b, " & %M", f->mask);
- break;
- case Tproto:
- case Tdata:
- Bprint(b, " & ");
- for(j = 0; j < f->len; j++)
- Bprint(b, "%2.2ux", f->mask[j]);
- break;
- }
- }
- p = f->val;
- Bprint(b, " =");
- for(i = 0; i < f->n; i++){
- switch(f->type){
- case Tifc:
- case Tsrc:
- case Tdst:
- Bprint(b, " %I", p);
- break;
- case Tproto:
- case Tdata:
- Bprint(b, " ");
- for(j = 0; j < f->len; j++)
- Bprint(b, "%2.2ux", p[j]);
- break;
- }
- p += f->len;
- }
- Bprint(b, "\n");
- printtree(b, f->yes, level+1);
- printtree(b, f->no, level+1);
-}
-
-void
-main(void)
-{
- Ipmux *f, *f1, *f2, *f1copy, *f2copy;
- Ipmux *root;
- Biobuf out;
-
- Binit(&out, 1, OWRITE);
- fmtinstall('I', eipconv);
- fmtinstall('M', eipconv);
-
- Bprint(&out, "demux 1:\n");
- f1 = parsedemux("data[0:3] = 12345678 23456789 3456789a");
- f = parsedemux("ifc = 135.104.9.2");
- ipmuxchain(&f1, f);
- f = parsedemux("src & 255.255.255.0 = 135.104.9.2");
- ipmuxchain(&f1, f);
- f = parsedemux("proto = 17");
- ipmuxchain(&f1, f);
- printtree(&out, f1, 0);
-
- f1copy = ipmuxcopy(f1);
-
- Bprint(&out, "demux 2:\n");
- f2 = parsedemux("data[0:3] = 12345678 23456789 3456789a");
- f = parsedemux("ifc = 135.104.9.1");
- ipmuxchain(&f2, f);
- f = parsedemux("src & 255.255.255.0 = 135.104.9.3");
- ipmuxchain(&f2, f);
- printtree(&out, f2, 0);
-
- f2copy = ipmuxcopy(f2);
-
- Bprint(&out, "merged demux:\n");
- root = ipmuxmerge(f1, f2);
- printtree(&out, root, 0);
-
- Bprint(&out, "demux 1 removed:\n");
- ipmuxremove(&root, f1copy);
- printtree(&out, root, 0);
-
- Bprint(&out, "demux 2 removed:\n");
- ipmuxremove(&root, f2copy);
- printtree(&out, root, 0);
-}
-
-enum
-{
- Tproto,
- Tdata,
- Tdst,
- Tsrc,
- Tifc,
-};
-
-char *ftname[] =
-{
-[Tdata] "data",
-[Tdst] "dst",
-[Tsrc] "src",
-[Tifc] "ifc",
-};
-
-struct Ipmux
-{
- Ipmux *yes;
- Ipmux *no;
- uchar type;
- ushort len; /* length in bytes of item to compare */
- ushort off; /* offset of comparison */
- int n; /* number of items val points to */
- uchar *val;
- uchar *mask;
-
- Conv *c;
- int ref; /* so we can garbage collect */
-};
-
/*
* connection request is a semi separated list of filters
* e.g. proto=17;dat[0:4]=11aa22bb;ifc=135.104.9.2
@@ 602,6 484,7 @@ ipmuxconnect(Conv *c, char **argv, int argc)
int n, proto;
char *field[10];
Ipmux *mux, *chain;
+ Ipmuxrock *r;
Fs *f;
f = c->p->f;
@@ 636,12 519,14 @@ ipmuxconnect(Conv *c, char **argv, int argc)
/* save a copy of the chain so we can later remove it */
mux->conv = c;
mux = ipmuxcopy(chain);
- *(Ipmux***)(c->ptcl) = chain;
+ r = (Ipmuxrock*)(c->ptcl);
+ r->chain = chain;
+ r->proto = proto;
/* add the chain to the protocol demultiplexor tree */
- qlock(p);
+ wlock(f);
f->t2m[proto] = ipmuxmerge(f->t2m[proto], mux);
- qunlock(p);
+ wunlock(f);
Fsconnected(c, nil);
return nil;
@@ 671,6 556,12 @@ ipmuxannounce(Conv*, char**, int)
static void
ipmuxclose(Conv *c)
{
+ Ipmuxrock *r;
+
+ r = (Ipmuxrock*)(c->ptcl);
+ r->chain = chain;
+ r->proto = proto;
+
qclose(c->rq);
qclose(c->wq);
qclose(c->eq);
@@ 679,6 570,11 @@ ipmuxclose(Conv *c)
c->lport = 0;
c->rport = 0;
+ wlock(f);
+ ipmuxremove(&(f->t2m[r->proto]), r->chain);
+ wunlock(f);
+ ipmuxtreefree(f->chain);
+
unlock(c);
}
@@ 692,12 588,66 @@ ipmuxkick(Conv *c, int l)
}
static void
-ipmuxiput(Proto *ipmux, uchar*, Block *bp)
+ipmuxiput(Proto *p, uchar *ia, Block *bp)
{
+ int len;
+ Iphdr *ip;
+ Fs *f = p->f;
+ uchar *p;
+ Conv *c;
+
+ ip = bp->rptr;
+ rlock(f);
+ mux = f->t2m[ip->proto];
+ if(mux == nil)
+ goto out;
+
+ /* run the v4 filter */
+ len = BLEN(bp);
+ if(len < 64 && bp->next){
+ bp = concatblock(bp);
+ len = BLEN(bp);
+ }
+ c = nil;
+ while(mux != nil){
+ while(mux){
+ switch(mux->type){
+ case Tia:
+ p = ia;
+ break;
+ case Tsrc:
+ p = ip->src;
+ break;
+ case Tdst:
+ p = ip->dst;
+ break;
+ case Tdata:
+ p = ip->data;
+ if(mux->off+mux->len > len)
+ goto no;
+ break;
+ }
+ }
+ if(mux->mask != nil){
+ } else {
+ }
+no:
+ mux = mux->no;
+ continue;
+ }
+out:
+ /* doesn't match any filter, hand it to the specific protocol handler */
+ runlock(f);
+ p = f->t2p[ip->proto];
+ if(p)
+ (*p->rcv)(p, ia, bp);
+ else
+ freeblist(bp);
+ return;
}
int
-ipmuxstats(Proto *ipmux, char *buf, int len)
+ipmuxstats(Proto *p, char *buf, int len)
{
return 0;
}
@@ 708,7 658,7 @@ ipmuxinit(Fs *fs)
Proto *ipmux;
ipmux = smalloc(sizeof(Proto));
- ipmux->priv = smalloc(sizeof(GREpriv));
+ ipmux->priv = nil;
ipmux->name = "ipmux";
ipmux->kick = ipmuxkick;
ipmux->connect = ipmuxconnect;
@@ 722,7 672,7 @@ ipmuxinit(Fs *fs)
ipmux->stats = ipmuxstats;
ipmux->ipproto = -1;
ipmux->nc = 64;
- ipmux->ptclsize = sizeof(Ipmux*);
+ ipmux->ptclsize = sizeof(Ipmuxrock);
Fsproto(fs, ipmux);
}
M pc/etherelnk3.c => pc/etherelnk3.c +154 -16
@@ 1,12 1,13 @@
/*
- * Etherlink III and Fast EtherLink adapters.
+ * Etherlink III, Fast EtherLink and Fast EtherLink XL adapters.
* To do:
* check robustness in the face of errors (e.g. busmaster & rxUnderrun);
* RxEarly and busmaster;
* autoSelect;
* PCI latency timer and master enable;
* errata list;
- * rewrite all initialisation.
+ * rewrite all initialisation;
+ * handle the cyclone adapter.
*
* Product ID:
* 9150 ISA 3C509[B]
@@ 48,6 49,8 @@
#include "etherif.h"
+#define XCVRDEBUG if(1)print
+
enum {
IDport = 0x0110, /* anywhere between 0x0100 and 0x01F0 */
};
@@ 240,6 243,9 @@ enum { /* Window 3 - FIFO management */
deferTimerSelect = 0x001E, /* mask */
fullDuplexEnable = 0x0020,
allowLargePackets = 0x0040,
+ extendAfterCollision = 0x0080, /* 3C90xB */
+ flowControlEnable = 0x0100, /* 3C90xB */
+ vltEnable = 0x0200, /* 3C90xB */
/* ResetOptions bits */
baseT4Available = 0x0001,
baseTXAvailable = 0x0002,
@@ 264,6 270,11 @@ enum { /* Window 4 - diagnostic */
txOverrun = 0x0400,
rxUnderrun = 0x2000,
receiving = 0x8000,
+ /* PhysicalMgmt bits */
+ mgmtClk = 0x0001,
+ mgmtData = 0x0002,
+ mgmtDir = 0x0004,
+ cat5LinkTestDefeat = 0x8000,
/* MediaStatus bits */
dataRate100 = 0x0002,
crcStripDisable = 0x0004,
@@ 413,10 424,12 @@ typedef struct {
long stats[BytesRcvdOk+3];
int upqmax;
+ int upqmaxhw;
long upinterrupts;
long upqueued;
int upstalls;
int dnqmax;
+ int dnqmaxhw;
long dninterrupts;
long dnqueued;
@@ 1124,13 1137,18 @@ ifstat(Ether* ether, void* a, long n, ulong offset)
len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n", ctlr->stats[BytesRcvdOk+1]);
if(ctlr->upenabled){
- len += snprint(p+len, READSTR-len, "up: q %lud i %lud m %d s %lud\n",
- ctlr->upqueued, ctlr->upinterrupts, ctlr->upqmax, ctlr->upstalls);
+ if(ctlr->upqmax > ctlr->upqmaxhw)
+ ctlr->upqmaxhw = ctlr->upqmax;
+ len += snprint(p+len, READSTR-len, "up: q %lud i %lud m %d h %d s %lud\n",
+ ctlr->upqueued, ctlr->upinterrupts,
+ ctlr->upqmax, ctlr->upqmaxhw, ctlr->upstalls);
ctlr->upqmax = 0;
}
if(ctlr->dnenabled){
- len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d\n",
- ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax);
+ if(ctlr->dnqmax > ctlr->dnqmaxhw)
+ ctlr->dnqmaxhw = ctlr->dnqmax;
+ len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d h %d\n",
+ ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax, ctlr->dnqmaxhw);
ctlr->dnqmax = 0;
}
@@ 1399,6 1417,117 @@ setxcvr(int port, int xcvr, int is9)
;
}
+static void
+setfullduplex(int port)
+{
+ int x;
+
+ COMMAND(port, SelectRegisterWindow, Wfifo);
+ x = ins(port+MacControl);
+ outs(port+MacControl, fullDuplexEnable|x);
+
+ COMMAND(port, TxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+ COMMAND(port, RxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+}
+
+static int
+miir(Ether* ether, int phyad, int regad)
+{
+ int data, i, port, w, x;
+
+ port = ether->port+PhysicalMgmt;
+
+ w = (STATUS(port)>>13) & 0x07;
+ COMMAND(ether->port, SelectRegisterWindow, Wdiagnostic);
+
+ /*
+ * Taken from the Cyclone manual appendix describing
+ * how to programme the MII Management Interface.
+ */
+ /*
+ * Preamble
+ */
+ for(i = 0; i < 32; i++){
+ outs(port, mgmtDir|mgmtData);
+ microdelay(1);
+ outs(port, mgmtDir|mgmtData|mgmtClk);
+ microdelay(1);
+ }
+
+ /*
+ * ST+OP+PHYAD+REGAD
+ */
+ x = 0x1800|(phyad<<5)|regad;
+ for(i = 14-1; i >= 0; i--){
+ if(x & (1<<i))
+ data = mgmtDir|mgmtData;
+ else
+ data = mgmtDir;
+ outs(port, data);
+ microdelay(1);
+ outs(port, data|mgmtClk);
+ microdelay(1);
+ }
+
+ /*
+ * "Z" cycle (turnaround) + one read (0 means there's a PHY responding).
+ */
+ data = 0;
+ outs(port, 0);
+ microdelay(1);
+ outs(port, mgmtClk);
+ x = ins(port);
+ if(x & mgmtData)
+ data |= (1<<16);
+
+ /*
+ * 16 data read cycles.
+ */
+ for(i = 16-1; i >= 0; i--){
+ outs(port, 0);
+ microdelay(1);
+ outs(port, mgmtClk);
+ microdelay(1);
+ x = ins(port);
+ if(x & mgmtData)
+ data |= (1<<i);
+ microdelay(1);
+ }
+
+ /*
+ * "Z" cycle (turnaround).
+ */
+ outs(port, 0);
+ microdelay(1);
+ outs(port, mgmtClk);
+
+ COMMAND(ether->port, SelectRegisterWindow, w);
+
+ if(data & 0x10000)
+ return -1;
+print("%d/%d: data=%uX\n", phyad, regad, data);
+
+ return data & 0xFFFF;
+}
+
+static void
+scanphy(Ether* ether)
+{
+ int i, x;
+
+ for(i = 0; i < 32; i++){
+ if((x = miir(ether, i, 2)) == -1)
+ continue;
+ x <<= 6;
+ x |= miir(ether, i, 3)>>10;
+ print("phy%d: oui %uX reg1 %uX\n", i, x, miir(ether, i, 1));
+ }
+}
+
#ifdef notdef
static struct xxx {
int available;
@@ 1416,10 1545,12 @@ static struct xxx {
#endif /* notdef */
static int
-autoselect(int port, int , int is9)
+autoselect(int port, int xcvr, int is9)
{
int media, x;
+ USED(xcvr);
+
/*
* Pathetic attempt at automatic media selection.
* Really just to get the Fast Etherlink 10BASE-T/100BASE-TX
@@ 1441,13 1572,13 @@ autoselect(int port, int , int is9)
COMMAND(port, SelectRegisterWindow, Wfifo);
media = ins(port+ResetOptions);
}
-//print("autoselect: media %uX\n", media);
+ XCVRDEBUG("autoselect: media %uX\n", media);
if(media & miiConnector)
return xcvrMii;
-//COMMAND(port, SelectRegisterWindow, Wdiagnostic);
-//print("autoselect: media status %uX\n", ins(port+MediaStatus));
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ XCVRDEBUG("autoselect: media status %uX\n", ins(port+MediaStatus));
if(media & baseTXAvailable){
/*
@@ 1469,7 1600,7 @@ autoselect(int port, int , int is9)
}
delay(1);
}
-//print("count %d v %uX\n", i, ins(port+MediaStatus));
+ XCVRDEBUG("count %d v %uX\n", i, ins(port+MediaStatus));
}
if(ins(port+MediaStatus) & linkBeatDetect)
@@ 1485,6 1616,7 @@ autoselect(int port, int , int is9)
outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x);
delay(100);
+ XCVRDEBUG("autoselect: 10BaseT media status %uX\n", ins(port+MediaStatus));
if(ins(port+MediaStatus) & linkBeatDetect)
return xcvr10BaseT;
outs(port+MediaStatus, x);
@@ 1511,7 1643,7 @@ eepromdata(int port, int offset)
int
etherelnk3reset(Ether* ether)
{
- int busmaster, did, i, port, rxearly, rxstatus9, x, xcvr;
+ int an, busmaster, did, i, phyaddr, port, rxearly, rxstatus9, x, xcvr;
Block *bp, **bpp;
Adapter *ap;
uchar ea[Eaddrlen];
@@ 1617,18 1749,24 @@ etherelnk3reset(Ether* ether)
* busmastering can be used. Due to bugs in the first revision
* of the 3C59[05], don't use busmastering at 10Mbps.
*/
-//print("reset: xcvr %uX\n", xcvr);
+ XCVRDEBUG("reset: xcvr %uX\n", xcvr);
if(xcvr & autoSelect)
xcvr = autoselect(port, xcvr, rxstatus9);
+ XCVRDEBUG("autoselect returns: xcvr %uX\n", xcvr);
switch(xcvr){
case xcvrMii:
/*
- * Bug? the 3c905 always seems to have dataRate100 set.
+ * Quick hack.
*/
- COMMAND(port, SelectRegisterWindow, Wdiagnostic);
- if(ins(port+MediaStatus) & dataRate100)
+ phyaddr = 24;
+ an = miir(ether, phyaddr, 0x04);
+ an &= miir(ether, phyaddr, 0x05) & 0x03E0;
+ XCVRDEBUG("mii an: %uX\n", an);
+ if(an & 0x380)
ether->mbps = 100;
+ if(an & 0x0140)
+ setfullduplex(port);
break;
case xcvr100BaseTX:
M pc/segment.h => pc/segment.h +1 -0
@@ 8,5 8,6 @@ Physseg physseg[] =
{ SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 },
{ SG_PHYSICAL, "dseg", 0xd0000, 64*1024, 0, 0 },
{ SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 },
+ { SG_PHYSICAL, "pcivctl", 0, 16*1024, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
A pc/vgamga2164w.c => pc/vgamga2164w.c +88 -0
@@ 0,0 1,88 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include "screen.h"
+
+static void
+mga2164wenable(VGAscr*)
+{
+ Pcidev *p;
+ Physseg *s;
+/*
+ ulong mmio;
+ uchar *rp;
+ int i;
+*/
+
+ if((p = pcimatch(nil, 0x102B, 0x051B)) == nil)
+ return;
+
+ for(s = physseg; s->name; s++)
+ if(strcmp("pcivctl", s->name) == 0)
+ s->pa = p->mem[1].bar & ~0x0F;
+
+/*
+ mmio = p->mem[1].bar & ~0x0F;
+ mmio = upamalloc(mmio, 16*1024, 0);
+ if(mmio == 0){
+ print("mmio == 0\n");
+ return;
+ }
+
+ rp = (uchar*)(mmio+0x3C00);
+ for(i = 0; i < 16; i++){
+ print("%2.2uX ", *rp);
+ rp++;
+ }
+ print("\n");
+*/
+}
+
+static ulong
+mga2164wlinear(VGAscr* scr, int* size, int* align)
+{
+ ulong aperture, oaperture;
+ int oapsize, wasupamem;
+ Pcidev *p;
+
+ oaperture = scr->aperture;
+ oapsize = scr->apsize;
+ wasupamem = scr->isupamem;
+ if(wasupamem)
+ upafree(oaperture, oapsize);
+ scr->isupamem = 0;
+
+ if(p = pcimatch(nil, 0x102B, 0x051B)){
+ aperture = p->mem[0].bar & ~0x0F;
+ *size = p->mem[0].size;
+ }
+ else
+ aperture = 0;
+
+ aperture = upamalloc(aperture, *size, *align);
+ if(aperture == 0){
+ if(wasupamem && upamalloc(oaperture, oapsize, 0))
+ scr->isupamem = 1;
+ }
+ else
+ scr->isupamem = 1;
+
+ return aperture;
+}
+
+VGAdev vgamga2164wdev = {
+ "mga2164w",
+
+ mga2164wenable, /* enable */
+ 0, /* disable */
+ 0, /* page */
+ mga2164wlinear, /* linear */
+};
M port/devsd.c => port/devsd.c +5 -6
@@ 60,7 60,7 @@ int ndisk;
Disk disk[Ndisk];
static int sdrdpart(Disk*);
-static long sdio(Chan*, int, char*, ulong, ulong);
+static long sdio(Chan*, int, char*, ulong, vlong);
static int types[] =
{
@@ 231,9 231,8 @@ sdclose(Chan *c)
}
static long
-sdread(Chan *c, void *a, long n, vlong off)
+sdread(Chan *c, void *a, long n, vlong offset)
{
- ulong offset = off;
if(c->qid.path & CHDIR)
return devdirread(c, a, n, 0, 0, sdgen);
@@ 242,10 241,9 @@ sdread(Chan *c, void *a, long n, vlong off)
}
static long
-sdwrite(Chan *c, char *a, long n, vlong off)
+sdwrite(Chan *c, char *a, long n, vlong offset)
{
Disk *d;
- ulong offset = off;
d = &disk[DRIVE(c->qid)];
@@ 350,12 348,13 @@ sdrdpart(Disk *d)
}
static long
-sdio(Chan *c, int write, char *a, ulong len, ulong offset)
+sdio(Chan *c, int write, char *a, ulong len, vlong off)
{
Disk *d;
Part *p;
uchar *b;
ulong block, n, max, x;
+ ulong offset = off;
d = &disk[DRIVE(c->qid)];
p = &d->table[PART(c->qid)];
M port/netif.c => port/netif.c +19 -0
@@ 473,6 473,16 @@ matchtoken(char *p, char *token)
}
void
+hnputv(void *p, vlong v)
+{
+ uchar *a;
+
+ a = p;
+ hnputl(a, v>>32);
+ hnputl(a+8, v);
+}
+
+void
hnputl(void *p, ulong v)
{
uchar *a;
@@ 494,6 504,15 @@ hnputs(void *p, ushort v)
a[1] = v;
}
+vlong
+nhgetv(void *p)
+{
+ uchar *a;
+
+ a = p;
+ return ((vlong)nhgetl(a) << 32) | nhgetl(a+8);
+}
+
ulong
nhgetl(void *p)
{
M port/portdat.h => port/portdat.h +6 -4
@@ 63,10 63,11 @@ struct QLock
struct RWlock
{
- Lock; /* Lock modify lock */
- QLock x; /* Mutual exclusion lock */
- QLock k; /* Lock for waiting writers */
- int readers; /* Count of readers in lock */
+ Lock use;
+ Proc *head; /* list of waiting processes */
+ Proc *tail;
+ int readers; /* number of readers */
+ int writer; /* number of writers */
};
struct Talarm
@@ 495,6 496,7 @@ enum
Scheding,
Running,
Queueing,
+ QueueingW,
Wakeme,
Broken,
Stopped,
M port/portfns.h => port/portfns.h +2 -0
@@ 311,7 311,9 @@ Segment* data2txt(Segment*);
Segment* dupseg(Segment**, int, int);
Segment* newseg(int, ulong, ulong);
Segment* seg(Proc*, ulong, int);
+void hnputv(void*, vlong);
void hnputl(void*, ulong);
void hnputs(void*, ushort);
+vlong nhgetv(void*);
ulong nhgetl(void*);
ushort nhgets(void*);
M port/proc.c => port/proc.c +1 -0
@@ 41,6 41,7 @@ char *statename[] =
"Scheding",
"Running",
"Queueing",
+ "QueueingW",
"Wakeme",
"Broken",
"Stopped",
M port/qlock.c => port/qlock.c +114 -18
@@ 4,17 4,28 @@
#include "dat.h"
#include "fns.h"
+struct {
+ ulong rlock;
+ ulong rlockq;
+ ulong wlock;
+ ulong wlockq;
+ ulong qlock;
+ ulong qlockq;
+} rwstats;
+
void
qlock(QLock *q)
{
Proc *p, *mp;
lock(&q->use);
+rwstats.qlock++;
if(!q->locked) {
q->locked = 1;
unlock(&q->use);
return;
}
+rwstats.qlockq++;
p = q->tail;
mp = up;
if(p == 0)
@@ 62,35 73,120 @@ qunlock(QLock *q)
}
void
-rlock(RWlock *l)
+rlock(RWlock *q)
{
- qlock(&l->x); /* wait here for writers and exclusion */
- lock(l);
- l->readers++;
- canqlock(&l->k); /* block writers if we are the first reader */
- unlock(l);
- qunlock(&l->x);
+ Proc *p, *mp;
+
+ lock(&q->use);
+rwstats.rlock++;
+ if(q->writer == 0 && q->head == nil){
+ /* no writer, go for it */
+ q->readers++;
+ unlock(&q->use);
+ return;
+ }
+
+rwstats.rlockq++;
+ p = q->tail;
+ mp = up;
+ if(p == 0)
+ q->head = mp;
+ else
+ p->qnext = mp;
+ q->tail = mp;
+ mp->qnext = 0;
+ mp->state = Queueing;
+ unlock(&q->use);
+ sched();
}
void
-runlock(RWlock *l)
+runlock(RWlock *q)
{
- lock(l);
- if(--l->readers == 0) /* last reader out allows writers */
- qunlock(&l->k);
- unlock(l);
+ Proc *p;
+
+ lock(&q->use);
+ p = q->head;
+ if(--(q->readers) > 0 || p == nil){
+ unlock(&q->use);
+ return;
+ }
+
+ /* start waiting writer */
+ if(p->state != QueueingW)
+ panic("runlock");
+ q->head = p->qnext;
+ if(q->head == 0)
+ q->tail = 0;
+ q->writer = 1;
+ unlock(&q->use);
+ ready(p);
}
void
-wlock(RWlock *l)
+wlock(RWlock *q)
{
- qlock(&l->x); /* wait here for writers and exclusion */
- qlock(&l->k); /* wait here for last reader */
+ Proc *p, *mp;
+
+ lock(&q->use);
+rwstats.wlock++;
+ if(q->readers == 0 && q->writer == 0){
+ /* noone waiting, go for it */
+ q->writer = 1;
+ unlock(&q->use);
+ return;
+ }
+
+ /* wait */
+rwstats.wlockq++;
+ p = q->tail;
+ mp = up;
+ if(p == nil)
+ q->head = mp;
+ else
+ p->qnext = mp;
+ q->tail = mp;
+ mp->qnext = 0;
+ mp->state = QueueingW;
+ unlock(&q->use);
+ sched();
}
void
-wunlock(RWlock *l)
+wunlock(RWlock *q)
{
- qunlock(&l->k);
- qunlock(&l->x);
+ Proc *p;
+
+ lock(&q->use);
+ p = q->head;
+ if(p == nil){
+ q->writer = 0;
+ unlock(&q->use);
+ return;
+ }
+
+ if(p->state == QueueingW){
+ /* start waiting writer */
+ q->head = p->qnext;
+ if(q->head == nil)
+ q->tail = nil;
+ unlock(&q->use);
+ ready(p);
+ return;
+ }
+
+ if(p->state != Queueing)
+ panic("wunlock");
+
+ /* waken waiting readers */
+ while(q->head != nil && q->head->state == Queueing){
+ p = q->head;
+ q->head = p->qnext;
+ q->readers++;
+ ready(p);
+ }
+ if(q->head == nil)
+ q->tail = nil;
+ q->writer = 0;
+ unlock(&q->use);
}