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

1994/0515/port/segment.c (diff list | history)

port/segment.c on 1991/0705
1991/0705    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1991/0705    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1991/0705    
 
1993/1012    
Page*	lkpage(Segment*, ulong); 
void	lkpgfree(Page*); 
void	imagereclaim(void); 
1991/0705    
 
/* System specific segattach devices */ 
1993/0210    
#include "io.h" 
1991/0705    
#include "segment.h" 
 
#define IHASHSIZE	64 
#define ihash(s)	imagealloc.hash[s%IHASHSIZE] 
1992/0625    
struct 
1991/0705    
{ 
	Lock; 
	Image	*free; 
	Image	*hash[IHASHSIZE]; 
1992/0625    
	QLock	ireclaim; 
1991/0705    
}imagealloc; 
 
void 
initseg(void) 
{ 
	Image *i, *ie; 
 
1992/0619    
	imagealloc.free = xalloc(conf.nimage*sizeof(Image)); 
1991/0705    
	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    
 
1992/0619    
	s = smalloc(sizeof(Segment)); 
	s->ref = 1; 
	s->type = type; 
	s->base = base; 
	s->top = base+(size*BY2PG); 
	s->size = size; 
	return s; 
1991/0705    
} 
 
void 
putseg(Segment *s) 
{ 
	Pte **pp, **emap; 
	Image *i; 
 
1991/0726    
	if(s == 0) 
		return; 
 
	i = s->image; 
1993/0725    
	if(i != 0) { 
1991/0726    
		lock(i); 
1993/0725    
		lock(s); 
		if(i->s == s && s->ref == 1) 
1991/0726    
			i->s = 0; 
		unlock(i); 
	} 
1993/0725    
	else 
		lock(s); 
1991/0726    
 
1993/0725    
	s->ref--; 
	if(s->ref != 0) { 
		unlock(s); 
		return; 
	} 
1991/0726    
 
1993/0725    
	qlock(&s->lk); 
	if(i) 
		putimage(i); 
1991/1109    
 
1993/0725    
	emap = &s->map[SEGMAPSIZE]; 
	for(pp = s->map; pp < emap; pp++) 
		if(*pp) 
			freepte(s, *pp); 
1991/0705    
 
1993/0725    
	qunlock(&s->lk); 
	free(s); 
1991/0705    
} 
 
void 
relocateseg(Segment *s, ulong offset) 
{ 
1993/0810    
	Page **pg, *x; 
	Pte *pte, **p, **endpte; 
1991/0705    
 
	endpte = &s->map[SEGMAPSIZE]; 
1992/0824    
	for(p = s->map; p < endpte; p++) { 
1993/0810    
		if(*p == 0) 
			continue; 
		pte = *p; 
		for(pg = pte->first; pg <= pte->last; pg++) { 
			if(x = *pg) 
				x->va += offset; 
1991/0705    
		} 
1992/0824    
	} 
1991/0705    
} 
 
Segment* 
1992/1104    
dupseg(Segment **seg, int segno, int share) 
1991/0705    
{ 
1992/0824    
	int i; 
1991/0705    
	Pte *pte; 
1992/1104    
	Segment *n, *s; 
1991/0705    
 
1992/0824    
	SET(n); 
1992/1104    
	s = seg[segno]; 
 
1991/0705    
	switch(s->type&SG_TYPE) { 
1994/0515    
	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_STACK: 
		qlock(&s->lk); 
1991/0705    
		n = newseg(s->type, s->base, s->size); 
1992/0824    
		break; 
1991/0705    
 
1994/0515    
	case SG_BSS:		/* Just copy on write */ 
1992/0430    
		qlock(&s->lk); 
		if(share && s->ref == 1) { 
			s->type = (s->type&~SG_TYPE)|SG_SHARED; 
			incref(s); 
			qunlock(&s->lk); 
			return s; 
		} 
		n = newseg(s->type, s->base, s->size); 
1992/0824    
		break; 
1992/0430    
 
1994/0515    
	case SG_DATA:		/* Copy on write plus demand load info */ 
1992/1104    
		if(segno == TSEG) 
			return data2txt(s); 
 
1991/0706    
		qlock(&s->lk); 
1992/0430    
		if(share && s->ref == 1) { 
			s->type = (s->type&~SG_TYPE)|SG_SHDATA; 
			incref(s); 
			qunlock(&s->lk); 
			return s; 
		} 
1991/0706    
		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; 
1992/0824    
		break; 
1991/0705    
	} 
1992/0824    
	for(i = 0; i < SEGMAPSIZE; i++) 
		if(pte = s->map[i]) 
			n->map[i] = ptecpy(pte); 
1991/0705    
 
1992/0824    
	n->flushme = s->flushme; 
	qunlock(&s->lk); 
	return n;	 
1991/0705    
} 
 
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); 
1992/0619    
			if(eqqid(c->qid, i->qid) && 
			   eqqid(c->mqid, i->mqid) && 
			   c->mchan == i->mchan && 
			   c->type == i->type) { 
1991/0705    
				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) { 
1993/0725    
		/* Disaster after commit in exec */ 
		if(waserror()) { 
			unlock(i); 
			pexit(Enovmem, 1); 
		} 
1991/0705    
		i->s = newseg(type, base, len); 
		i->s->image = i; 
1993/0725    
		poperror(); 
1991/0705    
	} 
	else 
		incref(i->s); 
 
	return i; 
} 
 
void 
1991/0706    
imagereclaim(void) 
{ 
	Page *p; 
 
1992/0625    
	/* Somebody is already cleaning the page cache */ 
	if(!canqlock(&imagealloc.ireclaim)) 
1991/0706    
		return; 
 
1992/0404    
	lock(&palloc); 
	for(p = palloc.head; p; p = p->next) { 
1992/0822    
		if(p->image && p->ref == 0 && p->image != &swapimage && canlock(p)) { 
1992/0225    
			if(p->ref == 0) 
1992/0404    
				uncachepage(p); 
1992/0625    
			unlock(p); 
1992/0314    
		} 
1991/0706    
	} 
1992/0404    
	unlock(&palloc); 
1992/0625    
	qunlock(&imagealloc.ireclaim); 
1991/0706    
} 
 
void 
1991/0705    
putimage(Image *i) 
{ 
	Chan *c; 
1992/0625    
	Image *f, **l; 
1991/0705    
 
	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); 
 
1992/0625    
		close(c); 
1991/0705    
		return; 
	} 
	unlock(i); 
} 
 
long 
1991/0706    
ibrk(ulong addr, int seg) 
1991/0705    
{ 
	Segment *s, *ns; 
	ulong newtop, newsize; 
	int i; 
 
1993/0501    
	s = up->seg[seg]; 
1991/0705    
	if(s == 0) 
1992/0114    
		error(Ebadarg); 
1991/0705    
 
	if(addr == 0) 
		return s->base; 
 
1991/1125    
	qlock(&s->lk); 
 
1992/0824    
	/* We may start with the bss overlapping the data */ 
1991/0705    
	if(addr < s->base) { 
1993/0501    
		if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) { 
1991/0705    
			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); 
1992/1206    
		flushmmu(); 
1991/0705    
		return 0; 
	} 
 
	for(i = 0; i < NSEG; i++) { 
1993/0501    
		ns = up->seg[i]; 
1991/0705    
		if(ns == 0 || ns == s) 
			continue; 
1992/0824    
		if(newtop >= ns->base && newtop < ns->top) { 
1991/0705    
			qunlock(&s->lk); 
1992/0824    
			error(Esoverlap); 
1991/0705    
		} 
	} 
 
1992/0824    
	if(newsize > (PTEMAPMEM*SEGMAPSIZE)/BY2PG) { 
		qunlock(&s->lk); 
1992/0912    
		error(Enovmem); 
1992/0824    
	} 
 
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)  
1992/1206    
			break; 
		if(s->map[i] == 0) { 
			pages -= PTEPERTAB-j; 
			j = 0; 
			continue; 
		} 
		while(j < PTEPERTAB) { 
			pg = s->map[i]->pages[j]; 
			if(pg) { 
				putpage(pg); 
				s->map[i]->pages[j] = 0;	 
1991/0705    
			} 
1992/1206    
			if(--pages == 0) 
				return; 
			j++; 
1991/0705    
		} 
1991/0726    
		j = 0; 
1991/0705    
	} 
} 
 
1994/0514    
int 
isoverlap(Proc *p, ulong va, int len) 
{ 
	int i; 
	Segment *ns; 
	ulong newtop; 
 
	newtop = va+len; 
	for(i = 0; i < NSEG; i++) { 
		ns = p->seg[i]; 
		if(ns == 0) 
			continue;	 
		if((newtop > ns->base && newtop <= ns->top) || 
		   (va >= ns->base && va < ns->top)) 
			return 1; 
	} 
	return 0; 
} 
 
1991/0705    
ulong 
segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) 
{ 
	int i, sno; 
1994/0514    
	Segment *s; 
	Physseg *ps; 
1991/0705    
 
1991/1115    
	USED(p); 
1994/0514    
	if(va != 0 && (va&KZERO) == 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++) 
1994/0514    
		if(p->seg[sno] == 0 && sno != ESEG) 
1991/0705    
			break; 
 
	if(sno == NSEG) 
1992/0114    
		error(Enovmem); 
1991/0705    
 
	len = PGROUND(len); 
1994/0514    
 
	/* Find a hole in the address space */ 
	if(va == 0) { 
		va = p->seg[SSEG]->base - len; 
		for(i = 0; i < 20; i++) { 
			if(isoverlap(p, va, len) == 0) 
				break; 
			va -= len; 
		} 
1991/0705    
	} 
 
1994/0514    
	va = va&~(BY2PG-1); 
	if(isoverlap(p, va, len)) 
		error(Esoverlap); 
 
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    
 
1993/0725    
	attr &= ~SG_TYPE;		/* Turn off what we are not allowed */ 
	attr |= ps->attr;		/* Copy in defaults */ 
1991/0705    
 
	s = newseg(attr, va, len/BY2PG); 
1993/0210    
	s->pseg = ps; 
1994/0514    
	p->seg[sno] = s; 
1991/0705    
 
1994/0514    
	return va; 
1991/0705    
} 
 
1993/0919    
void 
pteflush(Pte *pte, int s, int e) 
{ 
	int i; 
	Page *p; 
 
	for(i = s; i < e; i++) { 
		p = pte->pages[i]; 
1993/1001    
		if(pagedout(p) == 0) 
1993/0919    
			memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl)); 
	} 
} 
 
1991/0705    
long 
syssegflush(ulong *arg) 
{ 
	Segment *s; 
1993/1001    
	ulong addr, l; 
	Pte *pte; 
1993/0919    
	int chunk, ps, pe, len; 
1991/0705    
 
1993/0919    
	addr = arg[0]; 
	len = arg[1]; 
1991/0706    
 
1993/0919    
	while(len > 0) { 
1993/0930    
		s = seg(up, addr, 1); 
1993/0919    
		if(s == 0) 
			error(Ebadarg); 
1991/0705    
 
1993/0919    
		s->flushme = 1; 
1993/1001    
	more: 
1993/0919    
		l = len; 
		if(addr+l > s->top) 
			l = s->top - addr; 
1993/0725    
 
1993/1001    
		ps = addr-s->base; 
		pte = s->map[ps/PTEMAPMEM]; 
		ps &= PTEMAPMEM-1; 
		pe = PTEMAPMEM; 
		if(pe-ps > l){ 
			pe = ps + l; 
			pe = (pe+BY2PG-1)&~(BY2PG-1); 
		} 
		if(pe == ps) { 
			qunlock(&s->lk); 
			error(Ebadarg); 
		} 
 
		if(pte) 
			pteflush(pte, ps/BY2PG, pe/BY2PG); 
 
1993/0919    
		chunk = pe-ps; 
		len -= chunk; 
		addr += chunk; 
1993/1001    
 
		if(len > 0 && addr < s->top) 
			goto more; 
1993/0919    
 
		qunlock(&s->lk); 
	} 
1991/0705    
	flushmmu(); 
1992/0520    
	return 0; 
1991/0705    
} 


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