plan 9 kernel history: overview | file list | diff list

1992/0310/port/segment.c (diff list | history)

port/segment.c on 1991/0705
1991/0705    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1991/0705    
 
Page *lkpage(ulong addr); 
Page *snewpage(ulong addr); 
void lkpgfree(Page*); 
1991/0706    
void imagereclaim(void); 
1991/0705    
 
/* System specific segattach devices */ 
#include "segment.h" 
 
#define IHASHSIZE	64 
#define ihash(s)	imagealloc.hash[s%IHASHSIZE] 
struct Imagealloc 
{ 
	Lock; 
	Image	*free; 
	Image	*hash[IHASHSIZE]; 
}imagealloc; 
 
struct segalloc 
{ 
	Lock; 
	Segment *free; 
}segalloc; 
 
1991/0706    
static QLock ireclaim; 
 
1991/0705    
void 
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; 
 
	ie = &imagealloc.free[conf.nimage-1]; 
	for(i = imagealloc.free; i < ie; i++) 
		i->next = i+1; 
	i->next = 0; 
} 
 
Segment * 
newseg(int type, ulong base, ulong size) 
{ 
	Segment *s; 
 
	if(size > (SEGMAPSIZE*PTEPERTAB)) 
1992/0114    
		error(Enovmem); 
1991/0705    
 
	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; 
1991/0706    
			s->flushme = 0; 
1991/0705    
			memset(s->map, 0, sizeof(s->map)); 
 
			return s; 
		} 
		unlock(&segalloc); 
		resrcwait("no segments"); 
	} 
} 
 
void 
putseg(Segment *s) 
{ 
	Pte **pp, **emap; 
	Image *i; 
 
1991/0726    
	if(s == 0) 
		return; 
 
	i = s->image; 
	if(i && i->s == s && s->ref == 1){ 
		lock(i); 
		if(s->ref == 1) 
			i->s = 0; 
		unlock(i); 
	} 
 
	if(decref(s) == 0) { 
1991/1109    
		qlock(&s->lk); 
1991/0726    
		if(i) 
			putimage(i); 
 
1991/0705    
		emap = &s->map[SEGMAPSIZE]; 
		for(pp = s->map; pp < emap; pp++) 
			if(*pp) 
				freepte(s, *pp); 
1991/1109    
 
		qunlock(&s->lk); 
1991/0705    
 
		lock(&segalloc); 
		s->next = segalloc.free;		 
		segalloc.free = s; 
		unlock(&segalloc); 
	} 
} 
 
void 
relocateseg(Segment *s, ulong offset) 
{ 
	Pte **p, **endpte; 
	Page **pg, **endpages; 
 
	endpte = &s->map[SEGMAPSIZE]; 
	for(p = s->map; p < endpte; p++) 
		if(*p) { 
			endpages = &((*p)->pages[PTEPERTAB]); 
			for(pg = (*p)->pages; pg < endpages; pg++) 
				if(*pg) 
					(*pg)->va += offset; 
		} 
} 
 
Segment* 
dupseg(Segment *s) 
{ 
	Pte *pte; 
	Segment *n; 
	int i; 
 
	switch(s->type&SG_TYPE) { 
1991/0706    
	case SG_TEXT:			/* New segment shares pte set */ 
1991/0705    
	case SG_SHARED: 
	case SG_PHYSICAL: 
1992/0307    
	case SG_SHDATA: 
1991/0705    
		incref(s); 
		return s; 
1991/0706    
 
	case SG_BSS:			/* Just copy on write */ 
	case SG_STACK: 
		qlock(&s->lk); 
1991/0705    
		n = newseg(s->type, s->base, s->size); 
1991/0706    
		goto copypte; 
1991/0705    
 
1991/0706    
	case SG_DATA:			/* Copy on write plus demand load info */ 
		qlock(&s->lk); 
		n = newseg(s->type, s->base, s->size); 
 
1991/0705    
		incref(s->image); 
		n->image = s->image; 
		n->fstart = s->fstart; 
		n->flen = s->flen; 
	copypte: 
		for(i = 0; i < SEGMAPSIZE; i++) 
			if(pte = s->map[i]) 
				n->map[i] = ptecpy(pte); 
1991/0706    
 
		n->flushme = s->flushme; 
		qunlock(&s->lk); 
1991/0705    
		return n;	 
	} 
 
	panic("dupseg"); 
} 
 
void 
segpage(Segment *s, Page *p) 
{ 
	Pte **pte; 
	ulong off; 
1991/1122    
	Page **pg; 
1991/0705    
 
	if(p->va < s->base || p->va >= s->top) 
		panic("segpage"); 
 
	off = p->va - s->base; 
	pte = &s->map[off/PTEMAPMEM]; 
	if(*pte == 0) 
		*pte = ptealloc(); 
 
1991/1122    
	pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG]; 
	*pg = p; 
	if(pg < (*pte)->first) 
		(*pte)->first = pg; 
	if(pg > (*pte)->last) 
		(*pte)->last = pg; 
1991/0705    
} 
 
Image* 
attachimage(int type, Chan *c, ulong base, ulong len) 
{ 
	Image *i, **l; 
 
	lock(&imagealloc); 
 
1991/0724    
	/* 
	 * Search the image cache for remains of the text from a previous  
	 * or currently running incarnation  
	 */ 
1991/0705    
	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) { 
				i->ref++; 
				goto found; 
			} 
			unlock(i); 
		} 
	} 
	 
1991/0724    
	/* 
	 * imagereclaim dumps pages from the free list which are cached by image 
	 * structures. This should free some image structures. 
	 */ 
1991/0705    
	while(!(i = imagealloc.free)) { 
		unlock(&imagealloc); 
1991/0706    
		imagereclaim(); 
1991/0710    
		resrcwait(0); 
1991/0705    
		lock(&imagealloc); 
	} 
 
	imagealloc.free = i->next; 
 
	lock(i); 
	incref(c); 
	i->c = c; 
	i->type = c->type; 
	i->qid = c->qid; 
	i->mqid = c->mqid; 
	i->mchan = c->mchan; 
	i->ref = 1; 
	l = &ihash(c->qid.path); 
	i->hash = *l; 
	*l = i; 
found: 
	unlock(&imagealloc); 
 
	if(i->s == 0) { 
		i->s = newseg(type, base, len); 
		i->s->image = i; 
	} 
	else 
		incref(i->s); 
 
	return i; 
} 
 
void 
1991/0706    
imagereclaim(void) 
{ 
	Page *p; 
 
	if(!canqlock(&ireclaim))	/* Somebody is already cleaning the page cache */ 
		return; 
 
1992/0310    
	if(conf.cntrlp) 
	print("ireclaim %lud\n", TK2MS(MACHP(0)->ticks)); 
 
1991/1024    
	for(;;) { 
		lock(&palloc); 
		for(p = palloc.head; p; p = p->next) 
1992/0225    
			if(p->image) 
			if(p->ref == 0) 
			if(p->image != &swapimage) 
1991/1024    
				break; 
1991/0706    
 
		unlock(&palloc); 
1991/1024    
		if(p == 0) 
			break; 
 
1991/0706    
		lockpage(p); 
1992/0225    
		if(p->ref == 0) 
1991/0706    
			uncachepage(p); 
		unlockpage(p); 
	} 
1992/0310    
 
	if(conf.cntrlp) 
	print("ireclaim done %lud\n", TK2MS(MACHP(0)->ticks)); 
1991/0706    
 
	qunlock(&ireclaim); 
} 
 
void 
1991/0705    
putimage(Image *i) 
{ 
	Image *f, **l; 
	Chan *c; 
 
	if(i == &swapimage) 
		return; 
 
	lock(i); 
	if(--i->ref == 0) { 
		l = &ihash(i->qid.path); 
		i->qid = (Qid){~0, ~0};	 
		unlock(i); 
		c = i->c; 
	 
		lock(&imagealloc); 
		for(f = *l; f; f = f->hash) { 
			if(f == i) { 
				*l = i->hash; 
				break; 
			} 
			l = &f->hash; 
		} 
 
		i->next = imagealloc.free; 
		imagealloc.free = i; 
		unlock(&imagealloc); 
 
		close(c);		/* Delay close because we could error */ 
		return; 
	} 
	unlock(i); 
} 
 
long 
1991/0706    
ibrk(ulong addr, int seg) 
1991/0705    
{ 
	Segment *s, *ns; 
	ulong newtop, newsize; 
	int i; 
 
	s = u->p->seg[seg]; 
	if(s == 0) 
1992/0114    
		error(Ebadarg); 
1991/0705    
 
	if(addr == 0) 
		return s->base; 
 
1991/1125    
	qlock(&s->lk); 
 
1991/0705    
	if(addr < s->base) { 
		/* We may start with the bss overlapping the data */ 
		if(seg != BSEG || u->p->seg[DSEG] == 0 || addr < u->p->seg[DSEG]->base) { 
			qunlock(&s->lk); 
1992/0114    
			error(Enovmem); 
1991/1125    
		} 
1991/0705    
		addr = s->base; 
	} 
		 
	newtop = PGROUND(addr); 
	newsize = (newtop-s->base)/BY2PG; 
	if(newtop < s->top) { 
		mfreeseg(s, newtop, (s->top-newtop)/BY2PG); 
		qunlock(&s->lk); 
		return 0; 
	} 
 
	if(newsize > (PTEMAPMEM*SEGMAPSIZE)/BY2PG) { 
		qunlock(&s->lk); 
1991/0830    
		return -1; 
1991/0705    
	} 
 
	for(i = 0; i < NSEG; i++) { 
		ns = u->p->seg[i]; 
		if(ns == 0 || ns == s) 
			continue; 
1992/0307    
		if(newtop >= ns->base) 
		if(newtop < ns->top) { 
1991/0705    
			qunlock(&s->lk); 
			pprint("segments overlap\n"); 
1992/0114    
			error(Enovmem); 
1991/0705    
		} 
	} 
 
	s->top = newtop; 
	s->size = newsize; 
 
	qunlock(&s->lk); 
	return 0; 
} 
 
void 
mfreeseg(Segment *s, ulong start, int pages) 
{ 
	int i, j; 
	ulong soff; 
	Page *pg; 
 
	soff = start-s->base; 
	j = (soff&(PTEMAPMEM-1))/BY2PG; 
 
	for(i = soff/PTEMAPMEM; i < SEGMAPSIZE; i++) { 
		if(pages <= 0)  
			goto done; 
		if(s->map[i]) { 
			while(j < PTEPERTAB) { 
				if(pg = s->map[i]->pages[j]) { 
					putpage(pg); 
					s->map[i]->pages[j] = 0;	 
				} 
				if(--pages == 0) 
					goto done; 
				j++; 
			} 
		} 
		else 
1991/0726    
			pages -= PTEPERTAB-j; 
		j = 0; 
1991/0705    
	} 
done: 
	flushmmu(); 
} 
 
ulong 
segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) 
{ 
	Segment *s, *ns, *new; 
	Physseg *ps; 
	ulong newtop; 
	int i, sno; 
 
1991/1115    
	USED(p); 
1991/0705    
	if(va&KZERO)					/* BUG: Only ok for now */ 
1992/0114    
		error(Ebadarg); 
1991/0705    
 
	validaddr((ulong)name, 1, 0); 
	vmemchr(name, 0, ~0); 
 
	for(sno = 0; sno < NSEG; sno++) 
1992/0307    
		if(u->p->seg[sno] == 0) 
		if(sno != ESEG) 
1991/0705    
			break; 
 
	if(sno == NSEG) 
1992/0114    
		error(Enovmem); 
1991/0705    
 
	va = va&~(BY2PG-1); 
	len = PGROUND(len); 
	newtop = va+len; 
	for(i = 0; i < NSEG; i++) { 
		ns = u->p->seg[i]; 
		if(ns == 0) 
			continue;	 
1991/0803    
		if((newtop > ns->base && newtop <= ns->top) || 
		   (va >= ns->base && va < ns->top)) 
1992/0114    
			error(Enovmem); 
1991/0705    
	} 
 
1991/0731    
	for(ps = physseg; ps->name; ps++) 
1991/0705    
		if(strcmp(name, ps->name) == 0) 
			goto found; 
 
1992/0114    
	error(Ebadarg); 
1991/0705    
found: 
	if(len > ps->size) 
1992/0114    
		error(Enovmem); 
1991/0705    
 
	attr &= ~SG_TYPE;			/* Turn off what we are not allowed */ 
	attr |= ps->attr;			/* Copy in defaults */ 
 
	s = newseg(attr, va, len/BY2PG); 
	s->pgalloc = ps->pgalloc; 
	s->pgfree = ps->pgfree; 
	u->p->seg[sno] = s; 
 
	/* Need some code build mapped devices here */ 
 
	return 0; 
} 
 
long 
syssegflush(ulong *arg) 
{ 
	Segment *s; 
	int i, j, pages; 
	ulong soff; 
	Page *pg; 
 
	s = seg(u->p, arg[0], 1); 
	if(s == 0) 
1992/0114    
		error(Ebadarg); 
1991/0706    
 
	s->flushme = 1; 
1991/0705    
 
	soff = arg[0]-s->base; 
	j = (soff&(PTEMAPMEM-1))/BY2PG; 
	pages = ((arg[0]+arg[1]+(BY2PG-1))&~(BY2PG-1))-(arg[0]&~(BY2PG-1)); 
 
	for(i = soff/PTEMAPMEM; i < SEGMAPSIZE; i++) { 
		if(pages <= 0)  
			goto done; 
		if(s->map[i]) { 
			while(j < PTEPERTAB) { 
				if(pg = s->map[i]->pages[j])  
					memset(pg->cachectl, PG_TXTFLUSH, sizeof pg->cachectl); 
				if(--pages == 0) 
					goto done; 
				j++; 
			} 
			j = 0; 
		} 
		else 
			pages -= PTEMAPMEM/BY2PG; 
	} 
done: 
	qunlock(&s->lk); 
	flushmmu(); 
} 
 
Page* 
snewpage(ulong addr) 
{ 
	return newpage(1, 0, addr); 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)