From 17dd2cf113bef1c53c47f29940e331ed6980b631 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 25 Mar 1998 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1998-03-25 --- ip/ip.h | 2 +- ip/ipmux.c | 234 +++++++++++++++++++---------------------------- pc/etherelnk3.c | 170 ++++++++++++++++++++++++++++++---- pc/segment.h | 1 + pc/vgamga2164w.c | 88 ++++++++++++++++++ port/devsd.c | 11 +-- port/netif.c | 19 ++++ port/portdat.h | 10 +- port/portfns.h | 2 + port/proc.c | 1 + port/qlock.c | 132 ++++++++++++++++++++++---- 11 files changed, 483 insertions(+), 187 deletions(-) create mode 100644 pc/vgamga2164w.c diff --git a/ip/ip.h b/ip/ip.h index 13033aea786f75841e648ce73099e72459b25b02..50186c35382946d44fbb30f176b1fc7faabd1503 100644 --- a/ip/ip.h +++ b/ip/ip.h @@ -237,7 +237,7 @@ struct IProuter { */ struct Fs { - Lock; + RWlock; int np; Proto* p[Maxproto+1]; /* list of supported protocols */ diff --git a/ip/ipmux.c b/ip/ipmux.c index c4659fff29533862eabb667ecd34e1ba92275a9a..5e2e49fc0617a3301b30ca9573156171b723623d 100644 --- a/ip/ipmux.c +++ b/ip/ipmux.c @@ -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); } diff --git a/pc/etherelnk3.c b/pc/etherelnk3.c index 1412ae85bba8da3282b940162f2eb8be58fe56bb..9f98cfc8508f87f75c37b0e8ce8bed9fbb124fcb 100644 --- a/pc/etherelnk3.c +++ b/pc/etherelnk3.c @@ -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<= 0; i--){ + outs(port, 0); + microdelay(1); + outs(port, mgmtClk); + microdelay(1); + x = ins(port); + if(x & mgmtData) + data |= (1<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: diff --git a/pc/segment.h b/pc/segment.h index cfedf03a14688592a4758ddabc4002679021207c..e15b9f543929e30530af76e77e78e56b95a6d8c0 100644 --- a/pc/segment.h +++ b/pc/segment.h @@ -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 }, }; diff --git a/pc/vgamga2164w.c b/pc/vgamga2164w.c new file mode 100644 index 0000000000000000000000000000000000000000..4fdc172922d64da4e0cca80faebf93d458c7f66d --- /dev/null +++ b/pc/vgamga2164w.c @@ -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 +#include +#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 */ +}; diff --git a/port/devsd.c b/port/devsd.c index b8e3204f6b41f96795fb22d423fcec84723240ee..26649204dc3126a1d9b36927090c5cd67ae03d25 100644 --- a/port/devsd.c +++ b/port/devsd.c @@ -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)]; diff --git a/port/netif.c b/port/netif.c index 75e65aff7f256a5e078a3fd9b26f496737bf312c..20455aa4772013f61555bed339b30199d470f318 100644 --- a/port/netif.c +++ b/port/netif.c @@ -472,6 +472,16 @@ matchtoken(char *p, char *token) return p; } +void +hnputv(void *p, vlong v) +{ + uchar *a; + + a = p; + hnputl(a, v>>32); + hnputl(a+8, v); +} + void hnputl(void *p, ulong v) { @@ -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) { diff --git a/port/portdat.h b/port/portdat.h index f6093a75d75a96e96c32939286ff05de8e871e08..ebfb79e6111df963e222bb30f8d5b3c537b67fc3 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -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, diff --git a/port/portfns.h b/port/portfns.h index 69b603ea5b4a3318af670f955092c7f68e95b199..0979fd46940558802964c3413c15d42205470014 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -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*); diff --git a/port/proc.c b/port/proc.c index 512c269b8c8ddcc3f816b6f5d13fa0060358f109..4203f6c831f9524d4111a8291f3e9ed1418dee90 100644 --- a/port/proc.c +++ b/port/proc.c @@ -41,6 +41,7 @@ char *statename[] = "Scheding", "Running", "Queueing", + "QueueingW", "Wakeme", "Broken", "Stopped", diff --git a/port/qlock.c b/port/qlock.c index 0c664f773c38ed740e9111ee221333c2384cc04d..27b091d089f702522d0ac0e61caa17d9b21cb656 100644 --- a/port/qlock.c +++ b/port/qlock.c @@ -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); }