Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/gnot/page.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname gnot/page.c 1990/03091
## diff -e /dev/null /n/bootesdump/1990/03091/sys/src/9/68020/page.c
0a
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"

struct
{
	Lock;
	ulong	addr;
	int	active;
	Page	*page;		/* base of Page structures, indexed by phys addr */
	ulong	minppn;		/* index of first usable page */
	Page	*head;		/* most recently used */
	Page	*tail;		/* least recently used */
}palloc;

struct
{
	Lock;
	Orig	*arena;
	Orig	*free;
}origalloc;

typedef union PTEA	PTEA;
union PTEA{
	PTE;
	struct{
		ulong	n;	/* for growpte */
		Orig	*o;	/* for growpte */
		PTEA	*next;	/* for newmod */
	};
};

struct
{
	Lock;
	PTEA	*arena;
	PTEA	*free;
	PTEA	*end;
}ptealloc;

struct{
	Lock;
	PTEA	*free;
}modalloc;

/*
 * Called to allocate permanent data structures, before calling pageinit().
 */
void*
ialloc(ulong n, int align)
{
	ulong p;

	if(palloc.active)
		print("ialloc bad\n");
	if(palloc.addr == 0)
		palloc.addr = ((ulong)&end)&~KZERO;
	if(align){
		palloc.addr += BY2PG-1;
		palloc.addr &= ~(BY2PG-1);
	}
	memset((void*)(palloc.addr|KZERO), 0, n);
	p = palloc.addr;
	palloc.addr += n;
	if(align){
		palloc.addr += BY2PG-1;
		palloc.addr &= ~(BY2PG-1);
	}
	return (void*)(p|KZERO);
}

void
audit(char *s)
{
	int nf, nb;
	Page *p;
	static int here;

	do;while(here);
	here=1;
	p = palloc.head;
	nf=nb=0;
	while(p){
		print("%lux %lux %d\n", p->pa, p->va, p->ref);
		if(p->o){
			print("\t%d %lux %c\n", p->o->nproc, p->o->qid, devchar[p->o->type]);
			delay(100);	/* let it drain; there's a lot here */
		}
		nf++;
		p = p->next;
	}
	p = palloc.tail;
	while(p){
		nb++;
		p = p->prev;
	}
	print("%s: nf: %d nb: %d\n", s, nf, nb);
	delay(1000);
	here=0;
}

void
pageinit(void)
{
	ulong pa, nb, ppn;
	ulong i;
	Page *p;
	PTEA *pte;
	Orig *o;

	ptealloc.arena = ialloc(conf.npte*sizeof(PTEA), 0);
	ptealloc.free = ptealloc.arena;
	ptealloc.end = ptealloc.arena+conf.npte;

	modalloc.free = ialloc(conf.nmod*sizeof(PTEA), 0);

	pte = modalloc.free;
	for(i=0; i<conf.nmod-1; i++,pte++)
		pte->next = pte+1;
	pte->next = 0;

	origalloc.free = ialloc(conf.norig*sizeof(Orig), 0);
	origalloc.arena = origalloc.free;

	o = origalloc.free;
	for(i=0; i<conf.norig-1; i++,o++)
		o->next = o+1;
	o->next = 0;
	palloc.active = 1;

	nb = (conf.npage<<PGSHIFT) - palloc.addr;
	nb -= ((nb+(BY2PG-1))>>PGSHIFT)*sizeof(Page);	/* safe overestimate */
	nb &= ~(BY2PG-1);
	pa = (conf.npage<<PGSHIFT) - nb;	/* physical addr of first free page */
	ppn = pa >> PGSHIFT;			/* physical page number of first free page */
	palloc.page = (Page *)((palloc.addr - ppn*sizeof(Page))|KZERO);
	/*
	 * Now palloc.page[ppn] describes first free page
	 */
	palloc.minppn = ppn;
	palloc.addr = ppn<<PGSHIFT;

	palloc.head = &palloc.page[ppn];
	palloc.tail = &palloc.page[conf.npage-1];
	memset(palloc.head, 0, (conf.npage-ppn)*sizeof(Page));
	print("%lud free pages\n", conf.npage-ppn);
	for(p=palloc.head; p<=palloc.tail; p++,ppn++){
		p->next = p+1;
		p->prev = p-1;
		p->pa = ppn<<PGSHIFT;
	}
	palloc.head->prev = 0;
	palloc.tail->next = 0;
}

Page*
newpage(int noclear, Orig *o, ulong va)
{
	Page *p;
	Orig *o1;

	if(palloc.active == 0)
		print("newpage inactive\n");
loop:
	lock(&palloc);
	for(p=palloc.tail; p; p=p->prev){
		if(p->ref == 0)
			goto out;
#ifdef asdf
		if(p->ref == 1){	/* a pageout daemon should do this */
			o1 = p->o;
			if(o1 && o1->nproc==0 && canlock(o1)){
				if(o1->nproc){
					unlock(o1);
					continue;
				}
				print("free %d pages va %lux %lux %c\n", o1->npage, o->va, o1->qid, devchar[o1->type]);
				freepage(o1);
				/* neworig will free the orig and pte's later */
				unlock(o1);
				if(p->ref == 0)
					goto out;
				print("newpage ref != 0");
			}
		}
#endif
	}
	print("no physical memory\n");
	unlock(&palloc);
	if(u == 0)
		panic("newpage");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
    out:
	if(p->o){
		print("page in use %lux %lux %lux\n", p->va, p->o, origalloc.arena);
		print("%c %lux %lux, %d %d %d\n", devchar[p->o->type], p->o->va, p->o->qid, p->o->flag, p->o->nproc, p->o->npte);
		panic("shit");
	}
	p->ref = 1;
	usepage(p, 0);
	unlock(&palloc);
	if(!noclear)
		memset((void*)(p->pa|KZERO), 0, BY2PG);
	p->o = o;
	p->va = va;

	return p;
}

/*
 * Move page to head of list
 */
void
usepage(Page *p, int dolock)
{
	if(dolock)
		lock(&palloc);
	/*
	 * Unlink
	 */
	if(p->prev)
		p->prev->next = p->next;
	else
		palloc.head = p->next;
	if(p->next)
		p->next->prev = p->prev;
	else
		palloc.tail = p->prev;
	/*
	 * Link
	 */
	p->next = palloc.head;
	p->prev = 0;
	if(p->next)
		p->next->prev = p;
	else
		palloc.tail = p;
	palloc.head = p;
	if(dolock)
		unlock(&palloc);
}

Orig*
lookorig(ulong va, ulong npte, int flag, Chan *c)
{
	Orig *o;
	ulong i;

	for(o=origalloc.arena,i=0; i<conf.norig; i++,o++)
		if(o->npage && o->qid==c->qid && o->va==va){
			lock(o);
			if(o->npage && o->qid==c->qid)
			if(o->va==va && o->npte==npte && o->flag==flag)
			if(o->mchan==c->mchan && o->mqid==c->mqid && o->type==c->type){
				if(o->chan == 0){
					o->chan = c;
					incref(c);
				}
				o->nproc++;
				unlock(o);
				return o;
			}
			unlock(o);
		}
	return 0;
}

Orig*
neworig(ulong va, ulong npte, int flag, Chan *c)
{
	Orig *o;
	int i, freed;

	lock(&origalloc);
loop:
	if(o = origalloc.free){		/* assign = */
		origalloc.free = o->next;
		o->va = va;
		o->pte = 0;
		o->flag = flag;
		o->nproc = 1;
		o->npage = 0;
		o->chan = c;
		if(c){
			o->type = c->type;
			o->qid = c->qid;
			o->mchan = c->mchan;
			o->mqid = c->mqid;
			incref(c);
		}else{
			o->type = -1;
			o->qid = -1;
			o->mqid = -1;
			o->mchan = 0;
		}
		growpte(o, npte);
		unlock(&origalloc);
		return o;
	}
	/*
	 * This is feeble.  Orig's should perhaps be held in
	 * an LRU list.  This algorithm is too aggressive.
	 */
	freed = 0;
	for(o=origalloc.arena,i=0; i<conf.norig; i++,o++){
		if(o->nproc==0 && canlock(o)){
			if(o->nproc){
				unlock(o);
				continue;
			}
			freepage(o);
			freepte(o);
			unlock(o);
			o->next = origalloc.free;
			origalloc.free = o;
			freed++;
		}
	}
	if(freed)
		goto loop;
	print("no origs freed\n");
	unlock(&origalloc);
	if(u == 0)
		panic("neworig");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	lock(&origalloc);
	goto loop;
}

PTE*
newmod(void)
{
	PTEA *pte;

loop:
	lock(&modalloc);
	if(pte = modalloc.free){		/* assign = */
		modalloc.free = pte->next;
		unlock(&modalloc);
		memset(pte, 0, sizeof(PTE));
		return pte;
	}
	unlock(&modalloc);
	print("no mods\n");
	if(u == 0)
		panic("newmod");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
}

/*
 * Duplicate mod structure for this segment (old) in new process p.
 * old->o must be locked.
 */
void
forkmod(Seg *old, Seg *new, Proc *p)
{
	Orig *o;
	PTE *pte, *ppte, *opte, *npte;
	ulong va;

	o = old->o;
	ppte = 0;
	pte = old->mod;
	while(pte){
if(pte->page==0) panic("forkmod zero page");
if(pte->proc != u->p) panic("forkmod wrong page");
		npte = newmod();
		npte->proc = p;
		npte->page = pte->page;
		pte->page->ref++;
		o->npage++;
		/*
		 * Link into mod list for this va
		 */
		npte->nextmod = pte->nextmod;
		pte->nextmod = npte;
		/*
		 * Link into mod list for new segment
		 */
		if(ppte == 0)
			new->mod = npte;
		else
			ppte->nextva = npte;
		npte->nextva = 0;
		ppte = npte;
		pte = pte->nextva;
	}
}

void
freesegs(int save)
{
	int i, j;
	Seg *s;
	Orig *o;
	PTE *pte, *opte;
	PTEA *old;
	Page *pg;
	Chan *c;

	s = u->p->seg;
	for(i=0; i<NSEG; i++,s++){
		if(i == save)
			continue;
		o = s->o;
		if(o == 0)
			continue;
		lock(o);
		if(pte = s->mod){	/* assign = */
			while(pte){
				opte = &o->pte[(pte->page->va-o->va)>>PGSHIFT];
				while(opte->nextmod != pte){
					if(opte->page && opte->page->va != pte->page->va)
						panic("pte %lux %lux\n", opte->page->va, pte->page->va);
					opte = opte->nextmod;
					if(opte == 0)
						panic("freeseg opte==0");
				}
				opte->nextmod = pte->nextmod;
				pg = pte->page;
				if(pg->ref == 1){
					pte->page = 0;
					pg->o = 0;
				}
				pg->ref--;
				o->npage--;
				old = (PTEA*)pte;
				pte = pte->nextva;
				lock(&modalloc);
				old->next = modalloc.free;
				modalloc.free = old;
				unlock(&modalloc);
			}
		}
		o->nproc--;
		if(o->nproc == 0){
			if(c = o->chan){	/* assign = */
				o->chan = 0;
				close(c);
			}
			if(!(o->flag&OCACHED) || o->npage==0){
				freepage(o);
				freepte(o);
				unlock(o);
				lock(&origalloc);
				o->next = origalloc.free;
				origalloc.free = o;
				unlock(&origalloc);
			}else
				unlock(o);
		}else{
			/*
			 * BUG: there is a leak here. if the origin pte is being used only
			 * by the exiting process, the associated page will linger.  the fix
			 * is to remember either the length of the mod list at each va or
			 * the number of processes sharing the origin pte, and to promote one
			 * of the mods to the origin pte when no process is left using the
			 *  origin pte.
			 */
			unlock(o);
		}
	}
}

/*
 * Adjust segment to desired size.  This implementation is rudimentary.
 */
int
segaddr(Seg *s, ulong min, ulong max)
{
	Orig *o;

	if(max < min)
		return 0;
	if(min != s->minva)	/* can't grow down yet (stacks: fault.c) */
		return 0;
	max = (max+(BY2PG-1)) & ~(BY2PG-1);
	o = s->o;
	if(max == s->maxva)
		return 1;
	if(max > s->maxva){
		/*
		 * Grow
		 */
		/* BUG: check spill onto other segments */
		if(o->va+BY2PG*o->npte < max)
			growpte(o, (max-o->va)>>PGSHIFT);
		s->maxva = max;
		return 1;
	}
	/*
	 * Shrink
	 */
	print("segaddr shrink");
	for(;;);
}

/*
 * o is locked
 */
void
freepage(Orig *o)
{
	PTE *pte;
	Page *pg;
	int i;

	pte = o->pte;
	for(i=0; i<o->npte; i++,pte++)
		if(pg = pte->page){	/* assign = */
			if(pg->ref == 1){
				pte->page = 0;
				pg->o = 0;
			}
			pg->ref--;
		}
	o->npage = 0;
}

/*
 * Compacting allocator
 */

void
freepte(Orig *o)	/* o is locked */
{
	PTEA *p;
	p = (PTEA*)(o->pte - 1);
	p->o = 0;
}

void
growpte(Orig *o, ulong n)
{
	PTEA *p;
	ulong nfree;

	lock(&ptealloc);
	lock(o);
	if(o->pte){
		if(o->npte == n)
			panic("growpte pointless");
		p = (PTEA*)(o->pte - 1);
		if(o->npte > n){
			nfree = o->npte - n;
			p->n -= nfree;
			o->npte -= nfree;
			p += p->n;
			p->o = 0;
			p->n = nfree;
		}else{
			n++;
			if(p+p->n == ptealloc.free){
				compactpte(o, n - p->n);
				p = (PTEA*)(o->pte - 1);
				ptealloc.free += n - p->n;
			}else{
				compactpte(o, n);
				p = ptealloc.free;
				ptealloc.free += n;
				memcpy(p+1, o->pte, o->npte*sizeof(PTE));
				p->o = o;
				((PTEA*)(o->pte-1))->o = 0;
				o->pte = p+1;
			}
			memset(p+1+o->npte, 0, (n-(1+o->npte))*sizeof(PTE));
			p->n = n;
			o->npte = n-1;
		}
		unlock(o);
		unlock(&ptealloc);
		return;
	}
	n++;
	compactpte(o, n);
	p = ptealloc.free;
	ptealloc.free += n;
	memset(p, 0, n*sizeof(PTE));
	p->n = n;
	p->o = o;
	o->pte = p+1;
	o->npte = n-1;
	unlock(o);
	unlock(&ptealloc);
}

void
compactpte(Orig *o, ulong n)
{
	PTEA *p1, *p2;
	Orig *p2o;

	if(ptealloc.end-ptealloc.free >= n)
		return;
	p1 = ptealloc.arena;	/* dest */
	p2 = ptealloc.arena;	/* source */
	while(p2 < ptealloc.free){
		p2o = p2->o;
		if(p2o == 0){
    Free:
			p2 += p2->n;
			continue;
		}
		if(p1 != p2){
			if(p2o != o)
				lock(p2o);
			if(p2->o != p2o){	/* freepte()d very recently */
				if(p2->o)
					panic("compactpte p2->o %lux\n", p2->o);
				unlock(p2o);
				goto Free;
			}
			memcpy(p1, p2, p2->n*sizeof(PTE));
			p2o->pte = p1+1;
			if(p2o != o)
				unlock(p2o);
		}
		p2 += p1->n;
		p1 += p1->n;
	}
	ptealloc.free = p1;
	if(ptealloc.end-ptealloc.free >= n)
		return;
	unlock(o);
	unlock(&ptealloc);
	panic("compactpte %d %lux %d", n, o->va, o->npte);
}
.
## diffname gnot/page.c 1990/06021
## diff -e /n/bootesdump/1990/03091/sys/src/9/68020/page.c /n/bootesdump/1990/06021/sys/src/9/68020/page.c
208,209c
	if(!noclear){
		k = kmap(p);
		memset((void*)k->va, 0, BY2PG);
		kunmap(k);
	}
.
163a
	KMap *k;
.
153c
		if(ppn < conf.npage0)
			p->pa = conf.base0+(ppn<<PGSHIFT);
		else
			p->pa = conf.base1+((ppn-conf.npage0)<<PGSHIFT);
.
60a
	if(n == 0)	/* done by kmapinit */
		return (void*)(palloc.addr|KZERO);
	if(palloc.active)
		print("ialloc bad\n");
.
57,58d
13c
	Page	*page;		/* base of Page structures, indexed by phys page number */
.
## diffname gnot/page.c 1990/0614
## diff -e /n/bootesdump/1990/06021/sys/src/9/68020/page.c /n/bootesdump/1990/0614/sys/src/9/68020/page.c
216c
		memset((void*)VA(k), 0, BY2PG);
.
## diffname gnot/page.c 1990/0709
## diff -e /n/bootesdump/1990/0614/sys/src/9/68020/page.c /n/bootesdump/1990/0709/sys/src/9/68020/page.c
73a
	if(palloc.addr >= (4*1024*1024-256*1024-BY2PG))
		panic("keep bill joy away");
.
## diffname gnot/page.c 1990/0728
## diff -e /n/bootesdump/1990/0709/sys/src/9/68020/page.c /n/bootesdump/1990/0728/sys/src/9/68020/page.c
604a
    Return:
.
592,594c
		goto Return;
.
566a
			print("growpte shrink");
			goto Return;
.
563,564c
		if(o->npte == n){
			print("growpte pointless\n");
			goto Return;
		}
.
## diffname gnot/page.c 1990/0802
## diff -e /n/bootesdump/1990/0728/sys/src/9/68020/page.c /n/bootesdump/1990/0802/sys/src/9/68020/page.c
651c
	if(u && u->p)
		print("%s: %s: ", u->p->text, u->p->pgrp->user);
	print("compactpte fails addr %lux\n", o->va+n*BY2PG);
	return 0;
.
648c
		return 1;
.
619c
		return 1;
.
612c
int
.
609a
	return;

    Trouble:
	unlock(&ptealloc);
	if(u && u->p)
		error(0, Enovmem);
	panic("growpte fails %d %lux %d\n", n, o->va, o->npte);
.
608d
599c
	if(!compactpte(o, n))
		goto Trouble;
.
584c
				if(!compactpte(o, n))
					goto Trouble;
.
580c
				if(!compactpte(o, n - p->n))
					goto Trouble;
.
563a
if(u && u->p) print("%s: ", u->p->text);
.
561d
509a
		unlock(o);
		poperror();
.
507a
		lock(o);
		if(waserror()){
			unlock(o);
			nexterror();
		}
.
313a
		if(u && u->p)
			poperror();
		unlock(o);
.
312a
		lock(o);
		if(u && u->p && waserror()){
			unlock(o);
			unlock(&origalloc);
			nexterror();
		}
.
6a
#include	"errno.h"
.
## diffname gnot/page.c 1990/0814
## diff -e /n/bootesdump/1990/0802/sys/src/9/68020/page.c /n/bootesdump/1990/0814/sys/src/9/68020/page.c
632a
	unlock(o);
.
628a
	unlock(o);
.
614a
		memset(p+1+o->npte, 0, (n-(1+o->npte))*sizeof(PTE));
		p->n = n;
		o->npte = n-1;
.
595,613c
			if(!compactpte(o, n))
				goto Trouble;
			p = ptealloc.free;
			ptealloc.free += n;
			memcpy(p+1, o->pte, o->npte*sizeof(PTE));
			p->o = o;
			((PTEA*)(o->pte-1))->o = 0;
			o->pte = p+1;
.
585,593c
		n++;
		if(p+p->n == ptealloc.free){
			if(!compactpte(o, n - p->n))
				goto Trouble;
			p = (PTEA*)(o->pte - 1);
			ptealloc.free += n - p->n;
.
583d
579,581c
		if(o->npte >= n)
.
577a
	lock(o);
.
570a
/*
 * o is locked.  this will always do a grow; if n<=o->npte someone
 * else got here first and we can just return.
 */
.
525,526d
518,522d
323d
316d
314d
## diffname gnot/page.c 1990/11211
## diff -e /n/bootesdump/1990/0814/sys/src/9/68020/page.c /n/bootesdump/1990/11211/sys/src/9/68020/page.c
617c
		error(Enovmem);
.
310,311c
			o->qid.path = -1;
			o->qid.vers = 0;
			o->mqid.path = -1;
			o->mqid.vers = 0;
.
272c
			if(o->mchan==c->mchan && eqqid(o->mqid, c->mqid) && o->type==c->type){
.
270c
			if(o->npage && eqqid(o->qid, c->qid))
.
268c
		if(o->npage && eqqid(o->qid, c->qid) && o->va==va){
.
## diffname gnot/page.c 1990/1126
## diff -e /n/bootesdump/1990/11211/sys/src/9/68020/page.c /n/bootesdump/1990/1126/sys/src/9/68020/page.c
309c
			o->type = ~0;
.
## diffname gnot/page.c 1990/1211
## diff -e /n/bootesdump/1990/1126/sys/src/9/68020/page.c /n/bootesdump/1990/1211/sys/src/9/68020/page.c
260a
/*
 * Move page to tail of list
 */
void
unusepage(Page *p, int dolock)
{
}

.
## diffname gnot/page.c 1990/1212 # deleted
## diff -e /n/bootesdump/1990/1211/sys/src/9/68020/page.c /n/bootesdump/1990/1212/sys/src/9/68020/page.c
1,674d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].