~kris/9p

9hist

0f159a0b4666fa40f2a4a9827aabb1528a24d92e — David du Colombier 34 years ago 742b4de
Plan 9 from Bell Labs 1992-06-19
M port/alloc.c => port/alloc.c +205 -43
@@ 3,18 3,25 @@
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#define	nil	((void*)0)
#define datoff	((int)&((Xhdr*)0)->data)

#define	nil		((void*)0)
#define datoff		((ulong)&((Xhdr*)0)->data)
#define bdatoff		((ulong)&((Bucket*)0)->data)

enum
{
	Nhole	= 128,
	Magic	= 0xDeadBabe,
	Maxpow		= 16,
	Nhole		= 128,
	Magichole	= 0xDeadBabe,
	Magic2n		= 0xBadC0c0a,
};

typedef struct Hole Hole;
typedef struct Xalloc Xalloc;
typedef struct Xhdr Xhdr;
typedef struct Bucket Bucket;
typedef struct Arena Arena;

struct Hole
{
	ulong	addr;


@@ 38,62 45,95 @@ struct Xalloc
	Hole	*table;
};

Xalloc	xlists;
struct Bucket
{
	int	size;
	int	magic;
	Bucket	*next;
	char	data[1];
};

struct Arena
{
	Lock;
	Bucket	*btab[Maxpow];	
};

static Arena	arena;
static Xalloc	xlists;

void*
ialloc(ulong size, int align)
{
	ulong p;

	if(align) {
		size += BY2PG;
		p = (ulong)xalloc(size);
		p += BY2PG;
		p &= ~(BY2PG-1);
		return (void*)p;
	}

	return xalloc(size);
}

void*
iallocspan(ulong size, int quanta, ulong span)
{
	return ialloc(size, quanta);
}

void
xinit(void)
{
	ulong ktop;
	Hole *h, *eh;
	int up, np0, np1;

	eh = &xlists.hole[Nhole-1];
	for(h = xlists.hole; h < eh; h++)
		h->link = h+1;

	xlists.flist = h;
}
	xlists.flist = xlists.hole;

void
xhole(ulong addr, ulong size)
{
	Hole *h, **l;
	ktop = PGROUND((ulong)end);
	ktop = PADDR(ktop);
	conf.npage0 -= ktop/BY2PG;
	conf.base0 += ktop;

	lock(&xlists);
	l = &xlists.table;
	for(h = *l; h; h = h->link) {
		if(h->top == addr) {
			h->size += size;
			h->top = h->addr+h->size;
			unlock(&xlists);
			return;
		}
		if(h->addr > addr)
			break;
		l = &h->link;
	}
	up = conf.upages;
	np1 = up;
	if(np1 > conf.npage1)
		np1 = conf.npage1;

	if(xlists.flist == nil) {
		print("xfree: no free holes, leaked %d bytes\n", size);
		unlock(&xlists);
		return;
	}
	palloc.p1 = conf.base1;
	conf.base1 += np1*BY2PG;
	conf.npage1 -= np1;
	xhole(conf.base1, conf.npage1*BY2PG);
	up -= np1;

	h = xlists.flist;
	xlists.flist = h->link;
	h->addr = addr;
	h->top = addr+size;
	h->size = size;
	h->link = *l;
	*l = h;
	unlock(&xlists);
	np0 = up;
	if(np0 > conf.npage0)
		np0 = conf.npage0;

	palloc.p0 = conf.base0;
	conf.base0 += np0*BY2PG;
	conf.npage0 -= np0;
	xhole(conf.base0, conf.npage0*BY2PG);

	palloc.np0 = np0;
	palloc.np1 = np1;
}

void*
xalloc(ulong size)
{
	Hole *h, **l;
	Xhdr *p;
	Hole *h, **l;

	size += sizeof(Xhdr);
	size += BY2WD + sizeof(Xhdr);
	size &= ~(BY2WD-1);

	lock(&xlists);
	l = &xlists.table;


@@ 107,7 147,9 @@ xalloc(ulong size)
				h->link = xlists.flist;
				xlists.flist = h;
			}
			p->magix = Magic;
			p = KADDR(p);
			memset(p, 0, size);
			p->magix = Magichole;
			p->size = size;
			unlock(&xlists);
			return p->data;


@@ 124,10 166,64 @@ xfree(void *p)
	Xhdr *x;

	x = (Xhdr*)((ulong)p - datoff);
	if(x->magix != Magic)
	if(x->magix != Magichole)
		panic("xfree");

	xhole((ulong)x, x->size);
	xhole(PADDR(x), x->size);
}

void
xhole(ulong addr, ulong size)
{
	ulong top;
	Hole *h, *c, **l;

	if(size == 0)
		return;

	top = addr + size;
	lock(&xlists);
	l = &xlists.table;
	for(h = *l; h; h = h->link) {
		if(h->top == addr) {
			h->size += size;
			h->top = h->addr+h->size;
			c = h->link;
			if(c && h->top == c->addr) {
				h->top += c->size;
				h->size += c->size;
				h->link = c->link;
				c->link = xlists.flist;
				xlists.flist = c;
			}
			unlock(&xlists);
			return;
		}
		if(h->addr > addr)
			break;
		l = &h->link;
	}
	if(h && top == h->addr) {
		h->addr -= size;
		h->size += size;
		unlock(&xlists);
		return;
	}

	if(xlists.flist == nil) {
		unlock(&xlists);
		print("xfree: no free holes, leaked %d bytes\n", size);
		return;
	}

	h = xlists.flist;
	xlists.flist = h->link;
	h->addr = addr;
	h->top = top;
	h->size = size;
	h->link = *l;
	*l = h;
	unlock(&xlists);
}

void


@@ 143,8 239,74 @@ xsummary(void)
	print("%d holes free\n", i);
	i = 0;
	for(h = xlists.table; h; h = h->link) {
		print("%lux %lux %d\n", h->addr, h->top, h->size);
		print("%.8lux %.8lux %d\n", h->addr, h->top, h->size);
		i += h->size;
	}
	print("%d bytes free\n", i);
}

void*
malloc(ulong size)
{
	int pow;
	Bucket *bp;

	for(pow = 1; pow < Maxpow; pow++)
		if(size <= (1<<pow))
			goto good;

	return nil;
good:
	/* Allocate off this list */
	lock(&arena);
	bp = arena.btab[pow];
	if(bp) {
		arena.btab[pow] = bp->next;
		unlock(&arena);

		if(bp->magic != 0)
			panic("malloc");

		bp->magic = Magic2n;

		memset(bp->data, 0,  size);
		return  bp->data;
	}
	unlock(&arena);
	size = sizeof(Bucket)+(1<<pow);
	bp = xalloc(size);
	if(bp == nil)
		return nil;

	bp->size = pow;
	bp->magic = Magic2n;
	return bp->data;
}

void*
smalloc(ulong size)
{
	void *p;

	p = malloc(size);
	if(p == nil)
		panic("smalloc should sleep");
	return p;
}

void
free(void *ptr)
{
	Bucket *bp, **l;

	bp = (Bucket*)((ulong)ptr - bdatoff);
	if(bp->magic != Magic2n)
		panic("free");

	bp->magic = 0;
	lock(&arena);
	l = &arena.btab[bp->size];
	bp->next = *l;
	*l = bp;
	unlock(&arena);
}

M port/chan.c => port/chan.c +3 -4
@@ 91,7 91,6 @@ newchan(void)
			c->mnt = 0;
			c->stream = 0;
			c->aux = 0;
			c->mntindex = 0;
			c->mchan = 0;
			c->mqid = (Qid){0, 0};
			return c;


@@ 178,7 177,7 @@ mount(Chan *new, Chan *old, int flag)
	}

	if(m == 0) {
		m = newmnthead();
		m = smalloc(sizeof(Mhead));
		m->from = old;
		incref(old);
		m->hash = *l;


@@ 238,7 237,7 @@ unmount(Chan *mnt, Chan *mounted)
		wunlock(&pg->ns);
		mountfree(m->mount);
		close(m->from);
		mntheadfree(m);
		free(m);
		return;
	}



@@ 252,7 251,7 @@ unmount(Chan *mnt, Chan *mounted)
				*l = m->hash;
				wunlock(&pg->ns);
				close(m->from);
				mntheadfree(m);
				free(m);
				return;
			}
			wunlock(&pg->ns);

M port/dev.c => port/dev.c +0 -2
@@ 7,8 7,6 @@
#define	DEVTAB
#include	"devtab.h"

#include	"fcall.h"

extern ulong	kerndate;

int

M port/devarp.c => port/devarp.c +1 -1
@@ 332,7 332,7 @@ arpoput(Queue *q, Block *bp)

	/* if ip broadcast, use ether bcast address */
	addr = nhgetl(eh->dst);
	if(addr == Myip[Mybcast] || addr == Myip[Mynet]
	if(Myip[Myself] == 0 || addr == Myip[Mybcast] || addr == Myip[Mynet]
	|| ((addr & Mymask) == Myip[Mynet+1] && (addr & ~Mynetmask) == ~Mynetmask)){
		memset(eh->d, 0xff, sizeof(eh->d));
		PUTNEXT(q, bp);

M port/devcons.c => port/devcons.c +3 -0
@@ 228,6 228,9 @@ echo(Rune r, char *buf, int n)
		switch(r){
		case 0x14:
			break;	/* pass it on */
		case 'x':
			xsummary();
			break;
		case 'd':
			consdebug();
			return;

M port/devip.c => port/devip.c +0 -1
@@ 93,7 93,6 @@ ipreset(void)
	}

	initfrag(conf.frag);
	tcpinit();
}

void

M port/devmnt.c => port/devmnt.c +0 -1
@@ 5,7 5,6 @@
#include	"fns.h"
#include	"../port/error.h"
#include	"devtab.h"
#include	"fcall.h"

typedef struct Mntrpc Mntrpc;
typedef struct Mnt Mnt;

M port/devpipe.c => port/devpipe.c +0 -1
@@ 6,7 6,6 @@
#include	"../port/error.h"

#include	"devtab.h"
#include	"fcall.h"

typedef struct Pipe	Pipe;


M port/devproc.c => port/devproc.c +0 -5
@@ 4,7 4,6 @@
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"fcall.h"
#include	"ureg.h"

#include	"devtab.h"


@@ 264,10 263,6 @@ procread(Chan *c, void *va, long n, ulong offset)
		}

		if(offset >= KZERO) {
			/* prevent users reading authentication crypt keys */
			if(offset >= pgrpalloc.cryptbase)
			if(offset < pgrpalloc.crypttop)
				error(Eperm);
			/* validate physical kernel addresses */
			if(offset < KZERO+conf.npage0*BY2PG){
				if(offset+n > KZERO+conf.npage0*BY2PG)

M port/fcall.c => port/fcall.c +1 -1
@@ 1,6 1,6 @@
#include	<u.h>
#include	<libc.h>
#include	<fcall.h>
#include	"fcall.h"

#define	CHAR(x)		*p++ = f->x
#define	SHORT(x)	p[0] = f->x; p[1] = f->x>>8; p += 2

D port/malloc.c => port/malloc.c +0 -85
@@ 1,85 0,0 @@
#include <u.h>
#include <libc.h>

enum
{
	MAGIC		= 0xDEADBABE,
	MAXPOW		= 20
};

typedef struct Bucket Bucket;
struct Bucket
{
	int	size;
	int	magic;
	Bucket	*next;
	char	data[1];
};

typedef struct Arena Arena;
struct Arena
{
	Lock;
	Bucket	*btab[MAXPOW];
};
static Arena arena;
#define datoff		((int)&((Bucket*)0)->data)

void*
malloc(uint size)
{
	int pow;
	Bucket *bp;

	size += sizeof(Bucket);

	for(pow = 1; pow < MAXPOW; pow++)
		if(size <= (1<<pow))
			goto good;

	return 0;

good:
	lock(&arena);
	bp = arena.btab[pow];
	if(bp) {
		arena.btab[pow] = bp->next;
		arena.unlock();

		if(bp->magic != 0)
			panic("malloc");

		bp->magic = MAGIC;

		memset(bp->data, 0,  size);
		return  bp->data;
	}
	unlock(&arena);

	size = sizeof(Bucket)+(1<<pow);
	bp = xbrk(size);
	if((int)bp < 0)
		return nil;

	memset(bp->data, 0,  size);
	return bp->data;
}

void
free(void *ptr)
{
	Bucket *bp, **l;

	/* Find the start of the structure */
	bp = (Bucket*)((uint)ptr - datoff);

	if(bp->magic != MAGIC)
		panic("free");

	bp->magic = 0;
	lock(&arena);
	l = &arena.btab[bp->size];
	bp->next = *l;
	*l = bp;
	unlock(&arena);
}

M port/net.c => port/net.c +0 -2
@@ 5,8 5,6 @@
#include	"fns.h"
#include	"../port/error.h"

#include	"fcall.h"

enum
{
	Qlisten=	1,

M port/page.c => port/page.c +57 -217
@@ 8,8 8,6 @@
#define PGHFUN(x, y)	(((ulong)x^(ulong)y)%PGHSIZE)
#define	pghash(s)	palloc.hash[PGHFUN(s->image, p->daddr)]

struct Palloc palloc;

struct Ptealloc
{
	Lock;


@@ 17,240 15,55 @@ struct Ptealloc
	int	pages;
}ptealloclk;

ulong	hiaddr;
static Lock pglock;

/* Multiplex a hardware lock for per page manipulations */
void
lockpage(Page *p)
{	
	int s;

	for(;;) {
		if(p->lock == 0) {
			s = splhi();
			lock(&pglock);
			if(p->lock == 0) {
				p->lock = 1;
				unlock(&pglock);
				splx(s);
				return;
			}
			unlock(&pglock);
			splx(s);
		}
		sched();
	}
}

void
unlockpage(Page *p)
{
	p->lock = 0;
}

typedef struct Region	Region;
struct Region
{
	ulong	start;
	ulong	end;
};

enum
{
	Nregion=	10,
};
Region region[Nregion];


void
addsplit(Region *r, ulong start, ulong end)
{
	int len;
	Region *rr, *eregion;

	len = end - start;
	eregion = &region[Nregion];

	/* first look for an unused one */
	for(rr = region; rr < eregion; rr++){
		if(rr == r)
			continue;
		if(rr->end - rr->start == 0){
			rr->start = start;
			rr->end = end;
			return;
		}
	}

	/* then look for a smaller one */
	for(rr = region; rr < eregion; rr++){
		if(rr == r)
			continue;
		if(rr->end - rr->start < len){
			rr->start = start;
			rr->end = end;
			return;
		}
	}
}

/*
 *  Called to allocate permanent data structures, before calling pageinit().
 *  We assume all of text+data+bss is in the first memory bank.
 *
 *  alignment is in number of bytes.  It pertains both to the start and
 *  end of the allocated memory.
 *
 *  If crevasse is specified, no allocation can span an address that is
 *  a multiple of crevasse.
 */
void*
iallocspan(ulong n, int align, ulong crevasse)
{
	int m;
	ulong p;
	Region *r;
	int ledge;

	if(palloc.active && n!=0)
		print("ialloc bad\n");

	if(palloc.addr0 == 0){
		r = &region[Nregion-2];
		r->start = (((ulong)end)&~KZERO) + conf.base0;
		r->end = conf.base0 + (conf.npage0<<PGSHIFT);
		r++;
		r->start = conf.base1;
		r->end = conf.base1 + (conf.npage1<<PGSHIFT);

		palloc.addr0 = region[Nregion-2].start;
		palloc.addr1 = region[Nregion-1].start;
	}

	/*
	 *  alignment also applies to length
	 */
	if(align){
		m = n % align;
		if(m)
			n += align - m;
	}

	p = 0;
	for(r = region; r < &region[Nregion]; r++){
		/* align region */
		p = r->start;
		if(align){
			m = p % align;
			if(m)
				p += align - m;
		}

		/* check for crossing a crevasse */
		if(crevasse){
			ledge = p / crevasse;
			if(ledge != ((p+n-1) / crevasse))
				p = ((p+n-1) / crevasse) * crevasse;
		}

		/* see if it fits */
		if(p + n > r->end)
			continue;

		/* split the region */
		if(p != r->start)
			addsplit(r, r->start, p);
		r->start = p + n;
		break;
	}
	if(r == &region[Nregion])
		panic("out of memory");

	/*
	 *  remember high water marks
	 */
	if(palloc.addr0 < r->start && r->start <= conf.base0+(conf.npage0<<PGSHIFT))
		palloc.addr0 = r->start;
	else if(palloc.addr1 < r->start && r->start <= conf.base1+(conf.npage1<<PGSHIFT))
		palloc.addr1 = r->start;

	/*
	 *  zero it
	 */
	memset((void*)(p|KZERO), 0, n);
	return (void*)(p|KZERO);
}

/*
 *  allocate with possible page alignment
 */
void*
ialloc(ulong n, int align)
{
	return iallocspan(n, align ? BY2PG : 0, 0);
}
static	Lock pglock;
struct	Palloc palloc;

void
pageinit(void)
{
	ulong np, addr, lim;
	ulong i, vmem, pmem, hw, hr;
	Page *p;
	ulong np, hw, hr, vmem, pmem;

	np = palloc.np0+palloc.np1;
	palloc.head = xalloc(np*sizeof(Page));
	if(palloc.head == 0)
		panic("pageinit");

	/*
	 *  calculate an upper bound to the number of pages structures
	 *  we'll need (np).
	 */
	np = (conf.npage0<<PGSHIFT) - (palloc.addr0 - conf.base0);
	np += (conf.npage1<<PGSHIFT) - (palloc.addr1 - conf.base1);
	np = np>>PGSHIFT;

	/*
	 *  allocate Page structs (no more ialloc's allowed after this).
	 *  np is useless after this ialloc since we've just eaten up
	 *  some pages for the Page structures.
	 */
	palloc.head = ialloc(np*sizeof(Page), 0);
	palloc.active = 1;

	/*
 	 *  for each page in each bank, point a page structure to
	 *  the page and chain it into the free list
	 */
	p = palloc.head;
	addr = palloc.addr0 = PGROUND(palloc.addr0);
	lim = conf.base0 + (conf.npage0<<PGSHIFT);
	for(; addr < lim; addr += BY2PG){
		p->next = p+1;
	while(palloc.np0 > 0) {
		p->prev = p-1;
		p->pa = addr;
		p->next = p+1;
		p->pa = palloc.p0;
		palloc.p0 += BY2PG;
		palloc.np0--;
		p++;
	}
	addr = palloc.addr1 = PGROUND(palloc.addr1);
	lim = conf.base1 + (conf.npage1<<PGSHIFT);
	for(; addr < lim; addr += BY2PG){
		p->next = p+1;
	while(palloc.np1 > 0) {
		p->prev = p-1;
		p->pa = addr;
		p->next = p+1;
		p->pa = palloc.p1;
		palloc.p1 += BY2PG;
		palloc.np1--;
		p++;
	}
	palloc.tail = p - 1;
	palloc.head->prev = 0;
	palloc.tail->next = 0;

	palloc.user = palloc.freecount = p - palloc.head;
	palloc.user = p - palloc.head;
	palloc.freecount = palloc.user;
	pmem = palloc.user*BY2PG/1024;
	vmem = pmem + ((conf.nswap)*BY2PG)/1024;
	vmem = pmem + (conf.nswap*BY2PG)/1024;

	/* Pageing numbers */
	swapalloc.highwater = (palloc.freecount*5)/100;
	swapalloc.headroom = swapalloc.highwater + (swapalloc.highwater/4);
	hw = (swapalloc.highwater*BY2PG)/1024;
	hr = (swapalloc.headroom*BY2PG)/1024;

	hw = swapalloc.highwater*BY2PG;
	hr = swapalloc.headroom*BY2PG;
	
	print("%lud free pages, %dK bytes, swap %dK bytes, highwater %dK, headroom %dK\n", 
				palloc.user, pmem, vmem, hw, hr);
	print("%lud free pages, %dK bytes, swap %dK, highwater %dK, headroom %dK\n", 
	palloc.user, pmem, vmem, hw/1024, hr/1024);
}

Page*


@@ 260,13 73,11 @@ newpage(int clear, Segment **s, ulong va)
	KMap *k;
	int i;

	if(palloc.active == 0)
		print("newpage inactive\n");

	lock(&palloc);

	/* The kp test is a poor guard against the pager deadlocking */
	while((palloc.freecount < swapalloc.highwater && u->p->kp == 0)||palloc.freecount == 0) {
	while((palloc.freecount < swapalloc.highwater && u->p->kp == 0) ||
	       palloc.freecount == 0) {
		palloc.wanted++;
		unlock(&palloc);
		if(s && *s) {


@@ 605,3 416,32 @@ freepte(Segment *s, Pte *p)
	ptealloclk.free = p;
	unlock(&ptealloclk);
}

/* Multiplex a hardware lock for per page manipulations */
void
lockpage(Page *p)
{	
	int s;

	for(;;) {
		if(p->lock == 0) {
			s = splhi();
			lock(&pglock);
			if(p->lock == 0) {
				p->lock = 1;
				unlock(&pglock);
				splx(s);
				return;
			}
			unlock(&pglock);
			splx(s);
		}
		sched();
	}
}

void
unlockpage(Page *p)
{
	p->lock = 0;
}

M port/pgrp.c => port/pgrp.c +32 -192
@@ 5,73 5,8 @@
#include	"fns.h"
#include	"../port/error.h"

Pgrps pgrpalloc;

struct
{
	Lock;
	Egrp	*free;
}egrpalloc;

struct
{
	Lock;
	Fgrp	*free;
}fgrpalloc;

struct{
	Lock;
	Mount	*free;
	Mhead	*mhfree;
	ulong	mountid;
}mountalloc;

void
grpinit(void)
{
	int i;
	Pgrp *p;
	Egrp *e, *ee;
	Fgrp *f, *fe;
	Mount *m, *em;
	Mhead *hm, *hem;
	Crypt *cr;

	i = conf.npgrp*sizeof(Crypt);
	cr = ialloc(i, 0);
	pgrpalloc.cryptbase = (ulong)cr;
	pgrpalloc.crypttop = (ulong)cr + i;
	pgrpalloc.arena = ialloc(conf.npgrp*sizeof(Pgrp), 0);
	pgrpalloc.free = pgrpalloc.arena;

	p = pgrpalloc.free;
	for(i=0; i<conf.npgrp; i++,p++) {
		p->index = i;
		p->next = p+1;
		p->crypt = cr++;
	}
	p[-1].next = 0;

	egrpalloc.free = ialloc(conf.npgrp*sizeof(Egrp), 0);
	ee = &egrpalloc.free[conf.npgrp];
	for(e = egrpalloc.free; e < ee; e++) {
		e->next = e+1;
		e->etab = ialloc(conf.npgenv*sizeof(Env), 0);
	}
	e[-1].next = 0;

	fgrpalloc.free = ialloc(conf.nproc*sizeof(Fgrp), 0);
	fe = &fgrpalloc.free[conf.nproc-1];
	for(f = fgrpalloc.free; f < fe; f++)
		f->next = f+1;
	f->next = 0;
}

Pgrp*
pgrptab(int i)
{
	return &pgrpalloc.arena[i];
}
static Ref pgrpid;
static Ref mountid;

void
pgrpnote(ulong noteid, char *a, long n, int flag)


@@ 109,22 44,12 @@ newpgrp(void)
{
	Pgrp *p;

	for(;;) {
		lock(&pgrpalloc);
		if(p = pgrpalloc.free){
			pgrpalloc.free = p->next;
			p->ref = 1;
			p->pgrpid = ++pgrpalloc.pgrpid;
			memset(p->crypt, 0, sizeof *p->crypt);
			memset(p->rendhash, 0, sizeof(p->rendhash));
			memset(p->mnthash, 0, sizeof(p->mnthash));
			unlock(&pgrpalloc);
			return p;
		}
		unlock(&pgrpalloc);
		resrcwait("no pgrps");
	}
	return 0;		/* not reached */
	p = smalloc(sizeof(Pgrp)+sizeof(Crypt));
	p->ref = 1;
	/* This needs to have its own arena for protection */
	p->crypt = (Crypt*)((uchar*)p+sizeof(Pgrp));
	p->pgrpid = incref(&pgrpid);
	return p;
}

Egrp*


@@ 132,19 57,12 @@ newegrp(void)
{
	Egrp *e;

	for(;;) {
		lock(&egrpalloc);
		if(e = egrpalloc.free) {
			egrpalloc.free = e->next;
			e->ref = 1;
			e->nenv = 0;
			unlock(&egrpalloc);
			return e;
		}
		unlock(&egrpalloc);
		resrcwait("no envgrps");
	}
	return 0;		/* not reached */
	e = smalloc(sizeof(Egrp)+sizeof(Env)*conf.npgenv);

	/* This is a sleazy hack to make malloc work .. devenv need rewriting. */
	e->etab = (Env*)((uchar*)e+sizeof(Egrp));
	e->ref = 1;
	return e;
}

Fgrp*


@@ 152,20 70,9 @@ newfgrp(void)
{
	Fgrp *f;

	for(;;) {
		lock(&fgrpalloc);
		if(f = fgrpalloc.free) {
			fgrpalloc.free = f->next;
			f->ref = 1;
			f->maxfd = 0;
			memset(f->fd, 0, sizeof(f->fd));
			unlock(&fgrpalloc);
			return f;
		}
		unlock(&fgrpalloc);
		resrcwait("no filegrps");
	}
	return 0;		/* not reached */
	f = smalloc(sizeof(Fgrp));
	f->ref = 1;
	return f;
}

Fgrp*


@@ 221,15 128,11 @@ closepgrp(Pgrp *p)
				close(f->from);
				mountfree(f->mount);
				next = f->hash;
				mntheadfree(f);
				free(f);
			}
		}

		lock(&pgrpalloc);
		p->next = pgrpalloc.free;
		pgrpalloc.free = p;
		qunlock(&p->debug);
		unlock(&pgrpalloc);
		free(p);
	}
}



@@ 243,10 146,8 @@ closeegrp(Egrp *eg)
		e = eg->etab;
		for(i=0; i<eg->nenv; i++, e++)
			envpgclose(e);
		lock(&egrpalloc);
		eg->next = egrpalloc.free;
		egrpalloc.free = eg;
		unlock(&egrpalloc);

		free(eg);
	}
}



@@ 261,10 162,7 @@ closefgrp(Fgrp *f)
			if(c = f->fd[i])
				close(c);

		lock(&fgrpalloc);
		f->next = fgrpalloc.free;
		fgrpalloc.free = f;
		unlock(&fgrpalloc);
		free(f);
	}
}



@@ 274,31 172,12 @@ newmount(Mhead *mh, Chan *to)
{
	Mount *m, *f, *e;

	for(;;) {
		lock(&mountalloc);
		if(m = mountalloc.free){		/* assign = */
			mountalloc.free = m->next;
			m->mountid = ++mountalloc.mountid;
			unlock(&mountalloc);
			m->next = 0;
			m->head = mh;
			m->to = to;
			incref(to);
			return m;
		}
		unlock(&mountalloc);

		m = (Mount*)VA(kmap(newpage(0, 0, 0)));
		e = &m[(BY2PG/sizeof(Mount))-1];
		for(f = m; f < e; f++)
			f->next = f+1;

		lock(&mountalloc);
		e->next = mountalloc.free;
		mountalloc.free = m;
		unlock(&mountalloc);
	}
	return 0;	/* not reached */
	m = smalloc(sizeof(Mount));
	m->to = to;
	m->head = mh;
	incref(to);
	m->mountid = incref(&mountid);
	return m;
}

void


@@ 331,7 210,7 @@ pgrpcpy(Pgrp *to, Pgrp *from)
	for(h = from->mnthash; h < e; h++) {
		l = tom++;
		for(f = *h; f; f = f->hash) {
			mh = newmnthead();
			mh = smalloc(sizeof(Mhead));
			mh->from = f->from;
			incref(mh->from);
			*l = mh;


@@ 347,44 226,6 @@ pgrpcpy(Pgrp *to, Pgrp *from)
	runlock(&from->ns);
}

Mhead *
newmnthead(void)
{
	Mhead *mh, *f, *e;

	for(;;) {
		lock(&mountalloc);
		if(mh = mountalloc.mhfree) {		/* Assign '=' */
			mountalloc.mhfree = mh->hash;
			unlock(&mountalloc);
			mh->hash = 0;
			mh->mount = 0;
			return mh;
		}
		unlock(&mountalloc);

		mh = (Mhead*)VA(kmap(newpage(0, 0, 0)));
		e = &mh[(BY2PG/sizeof(Mhead))-1];
		for(f = mh; f < e; f++)
			f->hash = f+1;

		lock(&mountalloc);
		e->hash = mountalloc.mhfree;
		mountalloc.mhfree = mh;
		unlock(&mountalloc);
	}
	return 0;		/* not reached */
}

void
mntheadfree(Mhead *mh)
{
	lock(&mountalloc);
	mh->hash = mountalloc.mhfree;
	mountalloc.mhfree = mh;
	unlock(&mountalloc);
}

void
mountfree(Mount *m)
{


@@ 392,9 233,8 @@ mountfree(Mount *m)

	for(f = m; f->next; f = f->next)
		close(f->to);

	close(f->to);
	lock(&mountalloc);
	f->next = mountalloc.free;
	mountalloc.free = m;
	unlock(&mountalloc);

	free(f);
}

M port/portdat.h => port/portdat.h +4 -5
@@ 38,6 38,8 @@ typedef struct Talarm	Talarm;
typedef struct Waitq	Waitq;
typedef int    Devgen(Chan*, Dirtab*, int, int, Dir*);

#include "fcall.h"

struct List
{
	void	*next;


@@ 394,7 396,6 @@ struct Pgrp
struct Egrp
{
	Ref;
	Egrp	*next;
	int	nenv;			/* highest active env table entry, +1 */
	QLock	ev;			/* for all of etab */
	Env	*etab;


@@ 404,7 405,6 @@ struct Egrp
struct Fgrp
{
	Ref;
	Fgrp	*next;
	Chan	*fd[NFD];
	int	maxfd;			/* highest fd in use */
};


@@ 413,9 413,8 @@ struct Fgrp
struct Palloc
{
	Lock;
	ulong	addr0;			/* next available ialloc addr in bank 0 */
	ulong	addr1;			/* next available ialloc addr in bank 1 */
	int	active;
	ulong	p0, p1;			/* base of pages in bank 0/1 */
	ulong	np0, np1;		/* number of pages in bank 0/1 */
	Page	*head;			/* most recently used */
	Page	*tail;			/* least recently used */
	ulong	freecount;		/* how many pages on free list now */

M port/portfns.h => port/portfns.h +8 -4
@@ 84,7 84,6 @@ Block*	getq(Queue*);
int	gets(IOQ*, void*, int);
void	gotolabel(Label*);
Block*	grabq(Queue*);
void	grpinit(void);
int	hwcursmove(int, int);
int	hwcursset(uchar*, uchar*, int, int);
void*	ialloc(ulong, int);


@@ 232,7 231,6 @@ long	streamwrite(Chan*, void*, long, int);
long	stringread(void*, long, char*, ulong);
void	swapinit(void);
long	syscall(Ureg*);
void	tcpinit(void);
void	tsleep(Rendez*, int (*)(void*), void*, int);
void	uncachepage(Page*);
long	unionread(Chan*, void*, long);


@@ 248,8 246,14 @@ void	rlock(RWlock*);
void	runlock(RWlock*);
void	wlock(RWlock*);
void	wunlock(RWlock*);
Mhead*	newmnthead(void);
void	mountfree(Mount*);
void	mntheadfree(Mhead*);
void	unmount(Chan*, Chan*);
void	urpfillstats(Chan*, char*, int);
void	xinit(void);
void	*xalloc(ulong);
void	xfree(void*);
void	xhole(ulong, ulong);
void	xsummary(void);
void	*malloc(ulong);
void	*smalloc(ulong);
void	free(void*);

M port/proc.c => port/proc.c +3 -2
@@ 62,7 62,8 @@ schedinit(void)		/* never returns */
		u = 0;
		if(p->state == Running)
			ready(p);
		else if(p->state == Moribund) {
		else
		if(p->state == Moribund) {
			p->pid = 0;
			/* 
			 * Holding locks from pexit:


@@ 244,7 245,7 @@ procinit0(void)		/* bad planning - clashes with devproc.c */
	Proc *p;
	int i;

	procalloc.free = ialloc(conf.nproc*sizeof(Proc), 0);
	procalloc.free = xalloc(conf.nproc*sizeof(Proc));
	procalloc.arena = procalloc.free;

	p = procalloc.free;

M port/segment.c => port/segment.c +13 -48
@@ 22,12 22,6 @@ struct Imagealloc
	Image	*hash[IHASHSIZE];
}imagealloc;

struct segalloc
{
	Lock;
	Segment *free;
}segalloc;

static QLock ireclaim;

void


@@ 36,14 30,7 @@ initseg(void)
	Segment *s, *se;
	Image *i, *ie;

	segalloc.free = ialloc(conf.nseg*sizeof(Segment), 0);
	imagealloc.free = ialloc(conf.nimage*sizeof(Image), 0);

	se = &segalloc.free[conf.nseg-1];
	for(s = segalloc.free; s < se; s++)
		s->next = s+1;
	s->next = 0;

	imagealloc.free = xalloc(conf.nimage*sizeof(Image));
	ie = &imagealloc.free[conf.nimage-1];
	for(i = imagealloc.free; i < ie; i++)
		i->next = i+1;


@@ 58,32 45,13 @@ newseg(int type, ulong base, ulong size)
	if(size > (SEGMAPSIZE*PTEPERTAB))
		error(Enovmem);

	for(;;) {
		lock(&segalloc);
		if(s = segalloc.free) {
			segalloc.free = s->next;
			unlock(&segalloc);

			s->ref = 1;
			s->steal = 0;
			s->type = type;
			s->base = base;
			s->top = base+(size*BY2PG);
			s->size = size;
			s->image = 0;
			s->fstart = 0;
			s->flen = 0;
			s->pgalloc = 0;
			s->pgfree = 0;
			s->flushme = 0;
			memset(s->map, 0, sizeof(s->map));

			return s;
		}
		unlock(&segalloc);
		resrcwait("no segments");
	}
	return 0;	/* not reached */
	s = smalloc(sizeof(Segment));
	s->ref = 1;
	s->type = type;
	s->base = base;
	s->top = base+(size*BY2PG);
	s->size = size;
	return s;
}

void


@@ 117,10 85,7 @@ putseg(Segment *s)

		qunlock(&s->lk);

		lock(&segalloc);
		s->next = segalloc.free;		
		segalloc.free = s;
		unlock(&segalloc);
		free(s);
	}
}



@@ 237,10 202,10 @@ attachimage(int type, Chan *c, ulong base, ulong len)
	for(i = ihash(c->qid.path); i; i = i->hash) {
		if(c->qid.path == i->qid.path) {
			lock(i);
			if(eqqid(c->qid, i->qid))
			if(eqqid(c->mqid, i->mqid))
			if(c->mchan == i->mchan)
			if(c->type == i->type) {
			if(eqqid(c->qid, i->qid) &&
			   eqqid(c->mqid, i->mqid) &&
			   c->mchan == i->mchan &&
			   c->type == i->type) {
				i->ref++;
				goto found;
			}

M port/stfcall.c => port/stfcall.c +0 -2
@@ 5,8 5,6 @@
#include	"fns.h"
#include	"../port/error.h"

#include	"fcall.h"

enum
{
	Twritehdr	= 15,	/* Min bytes for Twrite */

M port/stream.c => port/stream.c +18 -162
@@ 6,7 6,6 @@
#include	"io.h"
#include	"../port/error.h"
#include	"devtab.h"
#include	"fcall.h"

enum {
	Nclass=4,	/* number of block classes */


@@ 30,31 29,11 @@ Qinfo procinfo =
 */
static Qinfo *lds;

/*
 *  All stream structures are ialloc'd at boot time
 */
Stream *slist;
Queue *qlist;
static Lock garbagelock;

/*
 *  The block classes.  There are Nclass block sizes, each with its own free list.
 *  All are ialloced at qinit() time.
 */
typedef struct {
	int	size;
	int	made;
	QLock;
	Blist;
} Bclass;
Bclass bclass[Nclass]={
	{ 0 },
	{ 68 },
	{ 268 },
	{ 4096 },
};

/*
 *  Allocate streams, queues, and blocks.  Allocate n block classes with
 *	1/2(m+1) to class m < n-1
 *	1/2(n-1) to class n-1


@@ 62,25 41,12 @@ Bclass bclass[Nclass]={
void
streaminit(void)
{
	int class, i, n;
	Bclass *bcp;

	/*
	 *  allocate queues, streams
	 */
	slist = (Stream *)ialloc(conf.nstream * sizeof(Stream), 0);
	qlist = (Queue *)ialloc(conf.nqueue * sizeof(Queue), 0);

	/*
	 *  set block classes
	 */
	n = conf.nblock;
	for(class = 0; class < Nclass; class++){
		if(class < Nclass-1)
			n = n/2;
		bcp = &bclass[class];
		bcp->made = 0;
	}
	slist = (Stream *)xalloc(conf.nstream * sizeof(Stream));
	qlist = (Queue *)xalloc(conf.nqueue * sizeof(Queue));

	/*
	 *  make stream modules available


@@ 105,107 71,22 @@ newqinfo(Qinfo *qi)
}

/*
 *  upgrade a block 0 block to another class (called with bcp qlocked)
 */
int
newblock(Bclass *bcp)
{
	Page *page;
	int n;
	Block *bp;
	uchar *cp;

	page = newpage(1, 0, 0);
	page->va = VA(kmapperm(page));
	if(bcp == bclass){
		/*
		 *  create some level zero blocks and return
		 */
		n = BY2PG/sizeof(Block);
		bp = (Block *)(page->va);
		while(n-- > 0){
			bp->flags = 0;
			bp->base = bp->lim = bp->rptr = bp->wptr = 0;
			if(bcp->first)
				bcp->last->next = bp;
			else
				bcp->first = bp;
			bcp->last = bp;
			bcp->made++;
			bp++;
		}
	} else {
		/*
		 *  create a page worth of new blocks
		 */
		n = BY2PG/bcp->size;
		cp = (uchar *)(page->va);
		
		while(n-- > 0){
			/*
			 *  upgrade a level 0 block
			 */
			bp = allocb(0);
			qlock(bclass);
			bclass->made--;
			bcp->made++;
			bp->flags = bcp - bclass;
			qunlock(bclass);

			/*
			 *  tack on the data area
			 */
			bp->base = bp->rptr = bp->wptr = cp;
			cp += bcp->size;
			bp->lim = cp;
			if(bcp->first)
				bcp->last->next = bp;
			else
				bcp->first = bp;
			bcp->last = bp;
		}
	}
	return 0;
}

/*
 *  allocate a block
 */
Block *
allocb(ulong size)
{
	Block *bp;
	Bclass *bcp;
	uchar *data;

	/*
	 *  map size to class
	 */
	for(bcp=bclass; bcp->size<size && bcp<&bclass[Nclass-1]; bcp++)
		;
	bp = smalloc(sizeof(Block)+size);

	/*
	 *  look for a free block
	 */
	qlock(bcp);
	while(bcp->first == 0){
		if(waserror()){
			qunlock(bcp);
			nexterror();
		}
		newblock(bcp);
		poperror();
	}
	bp = bcp->first;
	bcp->first = bp->next;
	if(bcp->first == 0)
		bcp->last = 0;
	qunlock(bcp);

	/*
	 *  return an empty block
	 */
	bp->flags = bcp - bclass;
	bp->rptr = bp->wptr = bp->base;
	data = (uchar*)bp + sizeof(Block);
	bp->rptr = data;
	bp->wptr = data;
	bp->base = data;
	bp->lim = data+size;
	bp->flags = 0;
	bp->next = 0;
	bp->list = 0;
	bp->type = M_DATA;


@@ 219,31 100,14 @@ allocb(ulong size)
void
freeb(Block *bp)
{
	ulong mark[1];
	Block *nbp;
	Bclass *bcp;
	int x;
	ulong pc;

#ifdef asdf
	pc = getcallerpc(((uchar*)&bp) - sizeof(bp));
	if((bp->flags&S_CLASS) >= Nclass)		/* Check for double free */
		panic("freeb class last(%lux) this(%lux)", bp->pc, pc);
	bp->pc = pc;
#endif asdf
	for(; bp; bp = nbp){
		bcp = &bclass[bp->flags & S_CLASS];
		bp->flags = bp->flags|S_CLASS;		/* Check for double free */
		qlock(bcp);
		bp->rptr = bp->wptr = 0;
		if(bcp->first)
			bcp->last->next = bp;
		else
			bcp->first = bp;
		bcp->last = bp;
		nbp = bp->next;
		bp->next = 0;
		qunlock(bcp);
	Block *next;

	while(bp){
		bp->rptr = 0;
		bp->wptr = 0;
		next = bp->next;
		free(bp);
		bp = next;	
	}
}



@@ 1497,7 1361,6 @@ dumpqueues(void)
	Queue *q;
	int count, qcount;
	Block *bp;
	Bclass *bcp;

	print("\n");
	qcount = 0;


@@ 1516,11 1379,4 @@ dumpqueues(void)
		dumpblocks(WR(q), 'W');
	}
	print("%d queues\n", qcount);
	for(bcp=bclass; bcp<&bclass[Nclass]; bcp++){
		for(count = 0, bp = bcp->first; bp; count++, bp = bp->next)
			;
		print("%d byte blocks: %d made %d free\n", bcp->size,
			bcp->made, count);
	}
	print("\n");
}

M port/swap.c => port/swap.c +1 -1
@@ 26,7 26,7 @@ int	ioptr;
void
swapinit(void)
{
	swapalloc.swmap = ialloc(conf.nswap, 0);
	swapalloc.swmap = xalloc(conf.nswap);
	swapalloc.top = &swapalloc.swmap[conf.nswap];
	swapalloc.alloc = swapalloc.swmap;


M port/sysfile.c => port/sysfile.c +0 -1
@@ 4,7 4,6 @@
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"fcall.h"

/*
 * The sys*() routines needn't poperror() as they return directly to syscall().

M port/tcpinput.c => port/tcpinput.c +4 -36
@@ 11,27 11,12 @@ int tcpdbg = 0;
#define DPRINT	if(tcpdbg) print
#define LPRINT  if(tcpdbg) print

QLock	reseqlock;
Reseq	*reseqfree;

char *tcpstate[] = {
	"Closed", 	"Listen", 	"Syn_sent", "Syn_received",
	"Established", 	"Finwait1",	"Finwait2", "Close_wait",
	"Closing", 	"Last_ack", 	"Time_wait" };

void
tcpinit(void)
{
	Reseq *r;

	reseqfree = ialloc(sizeof(Reseq)*Nreseq, 0);
	for(r = reseqfree; r < &reseqfree[Nreseq-1]; r++)
		r->next = r+1;

	r->next = 0;
}

void
reset(Ipaddr source, Ipaddr dest, char tos, ushort length, Tcp *seg)
{
	Block *hbp;


@@ 624,20 609,10 @@ void
add_reseq(Tcpctl *tcb, char tos, Tcp *seg, Block *bp, ushort length)
{
	Reseq *rp, *rp1;
	static int dropped;

	qlock(&reseqlock);
	if(!reseqfree) {
		qunlock(&reseqlock);
		if((dropped++%256) == 0)
			print("tcp: no resequence descriptors\n");
		freeb(bp);
	rp = malloc(sizeof(Reseq));
	if(rp == 0)
		return;
	}

	rp = reseqfree;
	reseqfree = rp->next;
	qunlock(&reseqlock);

	rp->seg = *seg;
	rp->tos = tos;


@@ 677,10 652,7 @@ get_reseq(Tcpctl *tcb, char *tos, Tcp *seg, Block **bp, ushort *length)
	*bp = rp->bp;
	*length = rp->length;

	qlock(&reseqlock);
	rp->next = reseqfree;
	reseqfree = rp;
	qunlock(&reseqlock);
	free(rp);
}

int


@@ 874,11 846,7 @@ close_self(Ipconv *s, char reason[])
	for(rp = tcb->reseq;rp != 0;rp = rp1){
		rp1 = rp->next;
		freeb(rp->bp);

		qlock(&reseqlock);
		rp->next = reseqfree;
		reseqfree = rp;
		qunlock(&reseqlock);
		free(rp);
	}

	tcb->reseq = 0;

M ss/dat.h => ss/dat.h +1 -1
@@ 69,6 69,7 @@ struct Conf
	ulong	nimage;		/* number of page cache image headers */
	ulong 	npagetab;	/* number of pte tables */
	ulong	nswap;		/* number of swap blocks */
	ulong	upages;		/* number of user pages */
	int	nalarm;		/* alarms */
	int	nchan;		/* channels */
	int	nenv;		/* distinct environment values */


@@ 92,7 93,6 @@ struct Conf
	int	npipe;		/* number of pipes */
	int	nservice;	/* number of services */
	int	nfsyschan;	/* number of filsys open channels */
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
	ulong	ipif;		/* Ip protocol interfaces */
	ulong	ip;		/* Ip conversations per interface */

M ss/fns.h => ss/fns.h +2 -0
@@ 23,6 23,8 @@ int	kbdstate(IOQ*, int);
void	kbdclock(void);
void	kbdrepeat(int);
KMap*	kmap(Page*);
#define KADDR(a)	((void*)((ulong)(a)|KZERO))
#define PADDR(a)	((ulong)(a)&~KZERO)
void	kmapinit(void);
KMap*	kmappa(ulong, ulong);
KMap*	kmapperm(Page*);

M ss/main.c => ss/main.c +6 -4
@@ 23,10 23,11 @@ main(void)
	active.exiting = 0;
	active.machs = 1;
	confinit();
	xinit();
	mmuinit();
	screeninit();
	printinit();
	print("sparc plan 9\n");
	pageinit();
	trapinit();
	kmapinit();
	ioinit();


@@ 34,11 35,9 @@ main(void)
	intrinit();
	procinit0();
	initseg();
	grpinit();
	chaninit();
	chandevreset();
	streaminit();
	pageinit();
	userinit();
	clockinit();
	schedinit();


@@ 198,12 197,15 @@ confinit(void)
	conf.nmach = 1;
	if(conf.nmach > MAXMACH)
		panic("confinit");

	conf.npage0 = (4*1024*1024)/BY2PG;	/* BUG */
	conf.npage1 = (4*1024*1024)/BY2PG;	/* BUG */
	conf.base0 = 0;
	conf.base1 = 32*1024*1024;
	conf.npage = conf.npage0+conf.npage1;
	conf.maxialloc = 4*1024*1024;		/* BUG */

	conf.upages = 1400;

	mul = 1;
	if(conf.npage1 > 0)
		mul = 2;

M ss/mmu.c => ss/mmu.c +13 -5
@@ 136,25 136,31 @@ purgepid(int pid)
	flushcontext();
}


void
mmuinit(void)
{
	ulong l, i, j, c, pte;
	ulong ktop, l, i, j, c, pte;

	/*
	 * TEMP: just map the first 4M of bank 0 for the kernel - philw
	 */
	ktop = 4*1024*1024;
	/*
	 * First map lots of memory as kernel addressable in all contexts
	 */
	i = 0;		/* used */
	for(c=0; c<NCONTEXT; c++)
		for(i=0; i<conf.maxialloc/BY2SEGM; i++)
		for(i=0; i < ktop/BY2SEGM; i++)
			putcxsegm(c, KZERO+i*BY2SEGM, i);

	kmapalloc.lowpmeg = i;

	/*
	 * Make sure cache is turned on for kernel
	 */
	pte = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM;
	for(i=0; i<conf.maxialloc/BY2PG; i++)
	ktop /= BY2PG;
	for(i=0; i < ktop; i++)
		putpmeg(KZERO+i*BY2PG, pte+i);

	/*


@@ 163,6 169,7 @@ mmuinit(void)
	putsegm(INVALIDSEGM, INVALIDPMEG);
	for(i=0; i<PG2SEGM; i++)
		putpmeg(INVALIDSEGM+i*BY2PG, INVALIDPTE);

	for(c=0; c<NCONTEXT; c++){
		putcontext(c);
		putsegm(INVALIDSEGM, INVALIDPMEG);


@@ 317,7 324,8 @@ kmapinit(void)
	KMap *k;
	int i;

print("low pmeg %d high pmeg %d\n", kmapalloc.lowpmeg, TOPPMEG);
	print("low pmeg %d high pmeg %d\n", kmapalloc.lowpmeg, TOPPMEG);

	kmapalloc.free = 0;
	k = kmapalloc.arena;
	for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){