From 3256d08c2e17a90b29e3aa142a717b462ff3218d Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 8 Feb 1994 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1994-02-08 --- port/alloc.c | 3 + port/devcons.c | 33 +++++-- port/portfns.h | 1 + port/qio.c | 241 +++++++++++++++++++++++++++++++++++++------------ power/mem.h | 1 + 5 files changed, 212 insertions(+), 67 deletions(-) diff --git a/port/alloc.c b/port/alloc.c index 0da2a1a0d312db62fc237af47084499e02892e20..ae8975f42e2405ceb109a082b9e991dad7df059b 100644 --- a/port/alloc.c +++ b/port/alloc.c @@ -118,6 +118,9 @@ xinit(void) conf.base1 = (ulong)KADDR(conf.base1); conf.npage0 = (ulong)KADDR(conf.npage0); conf.npage1 = (ulong)KADDR(conf.npage1); + + /* setup initial memory allocations for interrupt time */ + qinit(); } /* diff --git a/port/devcons.c b/port/devcons.c index a6f9ce82e89644d83bbb33f5adfb73a9f062df0f..7d2b94e78296b65fd896bd6220c8169518b9150c 100644 --- a/port/devcons.c +++ b/port/devcons.c @@ -44,10 +44,10 @@ printinit(void) * or uart code. Multi-line messages to serial consoles may get * interspersed with other messages. */ -void -putstrn(char *str, int n) +static void +putstrn0(char *str, int n, int usewrite) { - int m; + int m, x; char *t; char buf[PRINTSIZE+2]; @@ -73,17 +73,34 @@ putstrn(char *str, int n) memmove(buf, str, m); buf[m] = '\r'; buf[m+1] = '\n'; - qwrite(printq, buf, m+2, 1); + if(usewrite) + qwrite(printq, buf, m+2, 0); + else { + x = splhi(); + qproduce(printq, buf, m+2); + splx(x); + } str = t + 1; n -= m + 1; - } - else { - qwrite(printq, str, n, 1); + } else { + if(usewrite) + qwrite(printq, str, n, 0); + else { + x = splhi(); + qproduce(printq, str, n); + splx(x); + } break; } } } +void +putstrn(char *str, int n) +{ + putstrn0(str, n, 0); +} + int sprint(char *s, char *fmt, ...) { @@ -734,7 +751,7 @@ conswrite(Chan *c, void *va, long n, ulong offset) if(bp > sizeof buf) bp = sizeof buf; memmove(buf, a, bp); - putstrn(a, bp); + putstrn0(a, bp, 1); a += bp; l -= bp; } diff --git a/port/portfns.h b/port/portfns.h index b83fb79b9ac4971a1557fc90e8b81f54465f1e9d..e41df9408d3bb4deebb0a29a9449b6431a4eaef5 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -183,6 +183,7 @@ int qcanread(Queue*); void qclose(Queue*); int qconsume(Queue*, void*, int); void qhangup(Queue*); +void qinit(void); int qlen(Queue*); void qlock(QLock*); Queue* qopen(int, int, void (*)(void*), void*); diff --git a/port/qio.c b/port/qio.c index 51068ca2e664de8af48ecb63e49cd0cb72c24860..20e468cd6ec9d0c6b93e3e457a2161c9a5102b8e 100644 --- a/port/qio.c +++ b/port/qio.c @@ -79,6 +79,9 @@ struct Queue Rendez rr; /* process waiting to read */ QLock wlock; /* mutex for writing processes */ Rendez wr; /* process waiting to write */ + + uchar *syncbuf; /* synchronous IO buffer */ + int synclen; /* syncbuf length */ }; enum @@ -188,17 +191,30 @@ iallockproc(void *arg) } void -iallocinit(void) +qinit(void) { int pow; Chunkl *cl; + Chunk *p; + /* start with a bunch of initial blocks */ for(pow = Minpow; pow <= Maxpow; pow++){ cl = &arena.alloc[pow]; - cl->goal = Maxpow-pow + 16; + cl->goal = Maxpow-pow + 32; + cl->first = 0; + for(; cl->have < cl->goal; cl->have++){ + p = malloc(1<next = cl->first; + cl->first = p; + } } - /* start garbage collector */ +} + +void +iallocinit(void) +{ + /* start garbage collector/creator */ kproc("ialloc", iallockproc, 0); } @@ -216,15 +232,19 @@ ixsummary(void) print("\n"); } +/* + * interrupt time allocation (round data base address to 64 bit boundary) + */ Block* iallocb(int size) { int pow; + ulong addr; Chunkl *cl; Chunk *p; Block *b; - size += sizeof(Block); + size += sizeof(Block) + 7; for(pow = Minpow; pow <= Maxpow; pow++){ if(size <= (1<have--; cl->first = p->next; unlock(cl); + b = (Block *)p; memset(b, 0, sizeof(Block)); - b->base = (uchar*)(b+1); + addr = (ulong)b; + addr = (addr + sizeof(Block) + 7) & ~7; + b->base = (uchar*)addr; b->wp = b->base; b->rp = b->base; - b->lim = b->base + (1<lim = ((uchar*)b) + (1<base = (uchar*)(b+1); + addr = (ulong)b; + addr = (addr + sizeof(Block) + 7) & ~7; + b->base = (uchar*)addr; b->rp = b->base; b->wp = b->base; - b->lim = b->base + size; + b->lim = ((uchar*)b) + size; b->flag = 0; return b; @@ -343,12 +370,32 @@ int qproduce(Queue *q, void *vp, int len) { Block *b; - int dowakeup; + int i, dowakeup; uchar *p = vp; /* sync with qread */ + dowakeup = 0; lock(q); + if(q->syncbuf){ + /* synchronous communications, just copy into buffer */ + if(len < q->synclen) + q->synclen = len; + i = q->synclen; + memmove(q->syncbuf, p, i); + q->syncbuf = 0; /* tell reader buffer is full */ + len -= i; + if(len <= 0 || (q->state & Qmsg)){ + unlock(q); + wakeup(&q->rr); + return i; + } + + /* queue anything that's left */ + dowakeup = 1; + p += i; + } + /* no waiting receivers, room in buffer? */ if(q->len >= q->limit){ unlock(q); @@ -379,8 +426,7 @@ qproduce(Queue *q, void *vp, int len) if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; - } else - dowakeup = 0; + } unlock(q); if(dowakeup){ @@ -415,6 +461,14 @@ qopen(int limit, int msg, void (*kick)(void*), void *arg) return q; } +static int +filled(void *a) +{ + Queue *q = a; + + return q->syncbuf == 0; +} + static int notempty(void *a) { @@ -436,6 +490,16 @@ qread(Queue *q, void *vp, int len) qlock(&q->rlock); if(waserror()){ + /* can't let go if the buffer is in use */ + if(q->syncbuf){ + qlock(&q->wlock); + x = splhi(); + lock(q); + q->syncbuf = 0; + unlock(q); + splx(x); + qunlock(&q->wlock); + } qunlock(&q->rlock); nexterror(); } @@ -460,10 +524,23 @@ qread(Queue *q, void *vp, int len) return 0; } - q->state |= Qstarve; - unlock(q); - splx(x); - sleep(&q->rr, notempty, q); + if(globalmem(vp)){ + /* just let the writer fill the buffer directly */ + q->synclen = len; + q->syncbuf = vp; + unlock(q); + splx(x); + sleep(&q->rr, filled, q); + len = q->synclen; + poperror(); + qunlock(&q->rlock); + return len; + } else { + q->state |= Qstarve; + unlock(q); + splx(x); + sleep(&q->rr, notempty, q); + } } /* remove a buffered block */ @@ -490,8 +567,7 @@ qread(Queue *q, void *vp, int len) if(b->rp >= b->wp || (q->state&Qmsg)) { poison(b); free(b); - } - else { + } else { x = splhi(); lock(q); b->next = q->bfirst; @@ -521,64 +597,111 @@ qnotfull(void *a) /* * write to a queue. if no reader blocks are posted * queue the data. + * + * all copies should be outside of spl since they can fault. */ long qwrite(Queue *q, void *vp, int len, int nowait) { - int x, dowakeup; + int n, sofar, x, dowakeup; Block *b; uchar *p = vp; - b = allocb(len); - memmove(b->wp, p, len); - b->wp += len; + dowakeup = 0; - /* flow control */ - while(!qnotfull(q)){ - if(nowait) - return len; - qlock(&q->wlock); - if(waserror()) { + if(waserror()){ + qunlock(&q->wlock); + nexterror(); + }; + qlock(&q->wlock); + + sofar = 0; + if(q->syncbuf){ + if(len < q->synclen) + sofar = len; + else + sofar = q->synclen; + + memmove(q->syncbuf, p, sofar); + q->synclen = sofar; + q->syncbuf = 0; + wakeup(&q->rr); + + if(len == sofar || (q->state & Qmsg)){ qunlock(&q->wlock); - nexterror(); + poperror(); + return len; } - q->state |= Qflow; - sleep(&q->wr, qnotfull, q); - qunlock(&q->wlock); - poperror(); } - x = splhi(); - lock(q); + do { + n = len-sofar; + if(n > 128*1024) + n = 128*1024; + + b = allocb(n); + memmove(b->wp, p+sofar, n); + b->wp += n; + + /* flow control */ + while(!qnotfull(q)){ + if(nowait){ + free(b); + qunlock(&q->wlock); + poperror(); + return len; + } + q->state |= Qflow; + sleep(&q->wr, qnotfull, q); + } + + x = splhi(); + lock(q); + + if(q->state & Qclosed){ + unlock(q); + splx(x); + error(Ehungup); + } + + if(q->syncbuf){ + /* we guessed wrong and did an extra copy */ + if(n > q->synclen) + n = q->synclen; + memmove(q->syncbuf, b->rp, n); + q->synclen = n; + q->syncbuf = 0; + dowakeup = 1; + free(b); + } else { + /* we guessed right, queue it */ + if(q->bfirst) + q->blast->next = b; + else + q->bfirst = b; + q->blast = b; + q->len += n; + + if(q->state & Qstarve){ + q->state &= ~Qstarve; + dowakeup = 1; + } + } - if(q->state & Qclosed){ unlock(q); splx(x); - error(Ehungup); - } - - if(q->bfirst) - q->blast->next = b; - else - q->bfirst = b; - q->blast = b; - q->len += len; - if(q->state & Qstarve){ - q->state &= ~Qstarve; - dowakeup = 1; - } else - dowakeup = 0; + if(dowakeup){ + if(q->kick) + (*q->kick)(q->arg); + wakeup(&q->rr); + } - unlock(q); - splx(x); - - if(dowakeup){ - if(q->kick) - (*q->kick)(q->arg); - wakeup(&q->rr); - } + sofar += n; + } while(sofar < len && (q->state & Qmsg) == 0); + qunlock(&q->wlock); + poperror(); return len; } diff --git a/power/mem.h b/power/mem.h index 5b459ef89030601fe7b835d7a9d5294eb9392920..c6251e4f5d7bfc87e3cec30d862f8dffa3232eb3 100644 --- a/power/mem.h +++ b/power/mem.h @@ -130,6 +130,7 @@ #define USTKSIZE (4*1024*1024) /* size of user stack */ #define LKSEGSIZE (25*BY2PG) #define LKSEGBASE (USTKTOP-USTKSIZE-LKSEGSIZE) +#define globalmem(x) (((ulong)x)&KZERO) /* addresses valid in all contexts */ /* * Exception codes */