From 3a9c013eb85824df9678f4e603394c536dd7aa6d Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 12 May 1993 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1993-05-12 --- port/portdat.h | 2 +- port/stream.c | 187 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 147 insertions(+), 42 deletions(-) diff --git a/port/portdat.h b/port/portdat.h index 53996e3b54c55fb2d97db3761dc97462f9242040..3054b10378ea86bfeb9ab179b61decc46c05f2cb 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -669,7 +669,7 @@ struct Queue enum { - Qcsleep=1, /* consumer sleeping */ + Qstarve=1, /* consumer starved */ }; /* diff --git a/port/stream.c b/port/stream.c index 60d969257628d9e0017d54f3a30ad90c430c44b4..9ee632b76ef15bc8665310c605c6661bec193be3 100644 --- a/port/stream.c +++ b/port/stream.c @@ -4,65 +4,155 @@ #include "fns.h" #include "../port/error.h" -static Queue *freed; +typedef struct Chunk Chunk; +typedef struct Chunkl Chunkl; +typedef struct Arena Arena; + +enum +{ + Minpow= 7, + Maxpow= 12, +}; + +struct Chunk +{ + Chunk *next; +}; + +struct Alloc +{ + Lock; + Chunk *first; + int had; + int goal; + int last; +}; + +struct Arena +{ + Chunkl alloc[Maxpow-Minpow+1]; + Chunkl freed; +}; + +static Arena arena; /* - * Interrupt handlers use freeb() to release blocks. They are - * garbage collected by the kproc running bgc(). + * Manage interrupt level memory allocation. */ static void -bgc(void *arg) +iallockproc(void *arg) { - Block *b, *nb; + Chunk *p, *first, **l; + Chunkl *cl; + int pow, x, i; USED(arg); for(;;){ tsleep(&freed->r, return0, 0, 500); - if(freed->first == 0) - continue; - - x = slphi(); - lock(&freed); - b = freed->first; - freed->first = freed->last = 0;; - unlock(&freed); - spllo(); - - for(; b; b = nb){ - nb = b->next; - free(b); + + /* really free what was freed at interrupt level */ + cl = &arena.freed; + if(cl->first){ + x = slphi(); + lock(cl); + first = cl->first; + cl->first = 0; + unlock(cl); + spllo(); + + for(; first; first = p){ + p = first->next; + free(first); + } + } + + /* make sure we have blocks available for interrupt level */ + for(pow = Minpow; pow <= Maxpow; pow++){ + cl = &arena.alloc[pow]; + if(cl->have >= cl->goal){ + cl->had = cl->have; + continue; + } + + /* increase goal if we've been drained twice in a row */ + if(cl->have == 0 && cl->had == 0) + cl->goal += cl->goal>>2; + cl->had = cl->have; + l = &first; + for(i = x = cl->goal - cl->have; x > 0; x--){ + p = alloc(1<next; + } + if(first){ + x = splhi(); + lock(cl); + *l = cl->first; + cl->first = first; + cl->have += i; + unlock(cl); + spllo(x); + } } } } void -freeb(Block *b) +iallocinit(void) +{ + int pow; + Chunkl *cl; + + for(pow = Minpow; pow <= Maxpow; pow++){ + cl = &arena.alloc[pow]; + cl->goal = Maxpow-pow + 4; + } + + /* start garbage collector */ + kproc("iallockproc", iallockproc, 0); +} + +void* +ialloc(int size) { - lock(&freed); - b->next = freed->first; - freed->first = b; - unlock(&freed); + int pow; + Chunkl *cl; + Chunk *p; + + for(pow = Min; pow <= Maxpow; pow++) + if(size <= (1<first; + if(p){ + cl->have--; + cl->first = p->next; + } + unlock(cl); + return (void*)p; + } + panic("ialloc %d\n", size); } void -blockinit(void) +ifree(void *a) { - /* start garbage collector */ - kproc("buffer", bgc, 0); + Chunk *p; + Chunkl *cl; + + cl = &arena.freed; + p = a; + lock(cl); + p->next = cl->first; + cl->first = p; + unlock(cl); } /* * allocate queues and blocks */ -Queue* -allocq(int limit) -{ - Queue *q; - - q = smalloc(sizeof(Queue)); - q->limit = limit; -} - Block* allocb(int size) { @@ -80,7 +170,8 @@ allocb(int size) } /* - * copy out of a queue, returns # bytes copied + * Interrupt level copy out of a queue, return # bytes copied. If drop is + * set, any bytes left in a block afer a consume are discarded. */ int consume(Queue *q, uchar *p, int len, int drop) @@ -91,13 +182,27 @@ consume(Queue *q, uchar *p, int len, int drop) lock(q); b = q->first; if(b == 0){ - q->state |= Qcsleep; + q->state |= Qstarve; unlock(q); return -1; } n = BLEN(b); - if(n < len){ - memmove(p, b->rp, n); - } else { - memmove(p, b->rp, len); + if(n < len) + len = n; + memmove(p, b->rp, len); + if(len == n || drop){ + q->first = b->next; + ifree(b); + } else + b->rp += len; + unlock(q); + return len; +} + +int +produce(Queue *q, uchar *p, int len) +{ + Block *b; + + b = ialloc(sizeof(Block) }