~kris/9p

9hist

3a9c013eb85824df9678f4e603394c536dd7aa6d — David du Colombier 33 years ago fbcfb82
Plan 9 from Bell Labs 1993-05-12
2 files changed, 147 insertions(+), 42 deletions(-)

M port/portdat.h
M port/stream.c
M port/portdat.h => port/portdat.h +1 -1
@@ 669,7 669,7 @@ struct Queue

enum
{
	Qcsleep=1,	/* consumer sleeping */
	Qstarve=1,	/* consumer starved */
};

/*

M port/stream.c => port/stream.c +146 -41
@@ 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<<pow);
				if(p == 0)
					break;
				*l = p;
				l = &p->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<<pow)){
			cl = &arena.alloc[pow];
			lock(cl);
			p = cl->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)
}