~kris/9p

9hist

cd9ee403cbcd4f83ef8117ac37e17a030e4f0769 — David du Colombier 32 years ago 1849bbb
Plan 9 from Bell Labs 1994-03-21
4 files changed, 109 insertions(+), 189 deletions(-)

M port/portdat.h
M port/proc.c
M port/qio.c
M port/sysfile.c
M port/portdat.h => port/portdat.h +7 -7
@@ 120,13 120,13 @@ struct Path

struct Block
{
	Block	*next;
	Block	*list;

	uchar	*rp;			/* first unconsumed byte */
	uchar	*wp;			/* first empty byte */
	uchar	*lim;			/* 1 past the end of the buffer */
	uchar	*base;			/* start of the buffer */
	Block*	next;
	Block*	list;
	int	size;			/* power of 2 allocation list */
	uchar*	rp;			/* first unconsumed byte */
	uchar*	wp;			/* first empty byte */
	uchar*	lim;			/* 1 past the end of the buffer */
	uchar*	base;			/* start of the buffer */
	uchar	flag;
};
#define BLEN(s)	((s)->wp - (s)->rp)

M port/proc.c => port/proc.c +6 -6
@@ 105,6 105,12 @@ sched(void)
	gotolabel(&up->sched);
}

int
anyready(void)
{
	return m->hiq.head != 0 || m->loq.head != 0;
}

void
newcallback(void (*func)(void))
{


@@ 113,12 119,6 @@ newcallback(void (*func)(void))
		m->cbin = m->calls;
}

int
anyready(void)
{
	return m->hiq.head != 0 || m->loq.head != 0;
}

void
callbacks(void)
{

M port/qio.c => port/qio.c +95 -175
@@ 5,42 5,23 @@
#include	"fns.h"
#include	"../port/error.h"

/*
 *  interrupt level memory allocation
 */
typedef struct Chunk	Chunk;
typedef	struct Chunkl	Chunkl;
typedef	struct Arena	Arena;

enum
{
	Minpow= 7,
	Maxpow=	16,
};

struct Chunk
{
	Chunk	*next;
	Minpow	= 7,
	Maxpow	= 16,
};

struct Chunkl
struct Pool
{
	Lock;
	Chunk	*first;
	Block*	list;
	int	had;
	int	have;
	int	want;
	int	goal;
	int	hist;
	int	wanted;
};

struct Arena
{
	Chunkl	alloc[Maxpow+1];
	Chunkl	freed;
	Rendez r;
};

static Arena arena;
Pool	pool[Maxpow];

/*
 *  IO queues


@@ 51,8 32,8 @@ struct Queue
{
	Lock;

	Block	*bfirst;	/* buffer */
	Block	*blast;
	Block*	bfirst;	/* buffer */
	Block*	blast;

	int	len;		/* bytes in queue */
	int	limit;		/* max bytes in queue */


@@ 60,14 41,14 @@ struct Queue
	int	eof;		/* number of eofs read by user */

	void	(*kick)(void*);	/* restart output */
	void	*arg;		/* argument to kick */
	void*	arg;		/* argument to kick */

	QLock	rlock;		/* mutex for reading processes */
	Rendez	rr;		/* process waiting to read */
	QLock	wlock;		/* mutex for writing processes */
	Rendez	wr;		/* process waiting to write */

	uchar	*syncbuf;	/* synchronous IO buffer */
	uchar*	syncbuf;	/* synchronous IO buffer */
	int	synclen;	/* syncbuf length */
};



@@ 112,190 93,129 @@ poison(Block *b)
 *  Manage interrupt level memory allocation.
 */
static void
iallockproc(void *arg)
iallocmgr(void)
{
	Chunk *p, *first, **l;
	Chunkl *cl;
	int pow, x, i;

	USED(arg);
	for(;;){
		tsleep(&arena.r, return0, 0, 500);
	int pow;

		/* really free what was freed at interrupt level */
		cl = &arena.freed;
		if(cl->first){
			x = splhi();
			lock(cl);
			first = cl->first;
			cl->first = 0;
			unlock(cl);
			splx(x);
	
			while(first != 0) {
				p = first->next;
				free(first);
				first = p;
	attention = 0;
	spllo();
	for(pow = Minpow; pow <= Maxpow; pow++) {
		p = &pool[pow];

		/* Low pass filter */
		delta = 3 * (p->had - p->have);
		delta = (delta/2) + p->want;

		if(delta < 0) {
			lock(p);
			p->have -= delta;
			bp = p->list;
			while(delta--)
				p->list = p->list->next;
			unlock(p);
			spllo();
			while(bp) {
				next = bp->next;
				free(bp);
				bp = next;
			}
			splhi();
		}

		/* make sure we have blocks available for interrupt level */
		for(pow = Minpow; pow <= Maxpow; pow++){
			cl = &arena.alloc[pow];

			/*
			 *  if we've been ahead of the game for a while
			 *  start giving blocks back to the general pool
			 */
			if(cl->have >= cl->goal){
				cl->hist = ((cl->hist<<1) | 1) & 0xffff;
				if(cl->hist == 0xffff && cl->goal > 32)
					cl->goal--;
				continue;
			} else
				cl->hist <<= 1;

			/*
			 *  increase goal if we've been drained.
			 */
			if(cl->have == 0){
				i = cl->goal>>1;
				if(cl->wanted > i)
					cl->goal += 2*cl->wanted;
				else
					cl->goal += i;
				cl->wanted = 0;
				if(cl->goal > 5000)
					cl->goal = 5000;
			}

			first = 0;
			l = &first;
			i = cl->goal - cl->have;
			for(x = i; x > 0; x--){
				p = malloc(1<<pow);
				if(p == 0)
		else {
			spllo();
			n = 0;
			s = sizeof(Block)+(1<<pow)+(BY2V-1);
			while(delta--) {
				b = malloc(s);
				if(b == 0)
					break;

				*l = p;
				l = &p->next;
			}
			i -= x;
			if(first){
				x = splhi();
				lock(cl);
				*l = cl->first;
				cl->first = first;
				cl->have += i;
				unlock(cl);
				splx(x);
				addr = (ulong)b;
				addr = (addr+sizeof(Block)+(BY2V-1)) & ~(BY2V-1);
				b->base = (uchar*)addr;
				b->rp = b->base;
				b->wp = b->base;
				b->lim = ((uchar*)b)+size;
				b->size = pow;
				n++;
			}
			spllo();
			lock(p);
			unlock(p);
			splhi();
		}
		p->had = p->have;
		p->want = 0;		
	}
}

void
qinit(void)
{
	int pow;
	Chunk *p;
	Chunkl *cl;

	/* start with a bunch of initial blocks */
	for(pow = Minpow; pow <= Maxpow; pow++){
		cl = &arena.alloc[pow];
		cl->goal = 4;
		if(pow < 12)
			cl->goal = Maxpow-pow + 32;
		cl->first = 0;
		for(; cl->have < cl->goal; cl->have++){
			p = malloc(1<<pow);
			if(p == 0)
				panic("qinit");
			p->next = cl->first;
			cl->first = p;
		}
	}

}

void
iallocinit(void)
{
	/* start garbage collector/creator */
	kproc("ialloc", iallockproc, 0);
}

void
ixsummary(void)
{
	int pow;
	Chunkl *cl;
	Pool *p;

	print("size	have/goal\n");
	for(pow = Minpow; pow <= Maxpow; pow++){
		cl = &arena.alloc[pow];
		print("%d	%d/%d\n", 1<<pow, cl->have, cl->goal);
		cl = &pool[pow];
		print("%d	%d/%d\n", 1<<pow, p->have, p->goal);
	}
	print("\n");
}

/*
 *  interrupt time allocation (round data base address to 64 bit boundary)
 *  interrupt time allocation
 */
Block*
iallocb(int size)
{
	int pow;
	ulong addr;
	Chunkl *cl;
	Chunk *p;
	Block *b;
	Block *bp;

	size += sizeof(Block) + 7;
	for(pow = Minpow; pow <= Maxpow; pow++){
		if(size <= (1<<pow)){
			cl = &arena.alloc[pow];
			lock(cl);
			p = cl->first;
			if(p == 0){
				cl->wanted++;
				unlock(cl);
				wakeup(&arena.r);
				return 0;
			}
			cl->have--;
			cl->first = p->next;
			unlock(cl);

			b = (Block *)p;
			memset(b, 0, sizeof(Block));
			addr = (ulong)b;
			addr = (addr + sizeof(Block) + 7) & ~7;
			b->base = (uchar*)addr;
			b->wp = b->base;
			b->rp = b->base;
			b->lim = ((uchar*)b) + (1<<pow);
			return b;
	for(pow = Minpow; pow < Maxpow; pow++)
		if(size >= (1<<pow))
			break;

	if(pow == Maxpow)
		return 0;

	p = &pool[pow];
	lock(p);
	bp = p->list;
	if(p == 0) {
		p->want++;
		unlock(p);
		if(attention == 0) {
			attention++;
			newcallback(iallocmgr);
		}
		return 0;
	}

	panic("iallocb %d\n", size);
	return 0;			/* not reached */
	p->have--;
	p->list = bp->next;
	unlock(p);
	bp->wp = b->base;
	bp->rp = b->base;
	bp->list = 0;
	bp->next = 0;
	return bp;
}

void
ifree(void *a)
ifreeb(Block *bp)
{
	Chunk *p;
	Chunkl *cl;

	cl = &arena.freed;
	p = a;
	lock(cl);
	p->next = cl->first;
	cl->first = p;
	unlock(cl);
	Pool *p;

	p = &pool[bp->size];
	lock(p);
	bp->next = p->list;
	p->list = bp;
	p->have++;
	unlock(p);
}

/*

M port/sysfile.c => port/sysfile.c +1 -1
@@ 85,7 85,7 @@ openmode(ulong o)
}

long
syspath(ulong *arg)
sysfd2path(ulong *arg)
{
	Chan *c;