805 lines · 14.4 KB · Text
RawDownload
#include	"u.h"#include	"lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"error.h" static void	imagereclaim(void);static void	imagechanreclaim(void); #include "io.h" /* * Attachable segment types */static Physseg physseg[10] = {	{ SG_SHARED,	"shared",	0,	SEGMAXSIZE,	0, 	0 },	{ SG_BSS,	"memory",	0,	SEGMAXSIZE,	0,	0 },	{ 0,		0,		0,	0,		0,	0 },}; static Lock physseglock; #define NFREECHAN	64#define IHASHSIZE	64#define ihash(s)	imagealloc.hash[s%IHASHSIZE]static struct Imagealloc{	Lock lk;	Image	*free;	Image	*hash[IHASHSIZE];	QLock	ireclaim;	/* mutex on reclaiming free images */ 	Chan	**freechan;	/* free image channels */	int	nfreechan;	/* number of free channels */	int	szfreechan;	/* size of freechan array */	QLock	fcreclaim;	/* mutex on reclaiming free channels */}imagealloc; Segment* (*_globalsegattach)(Proc*, char*); voidinitseg(void){	Image *i, *ie; 	imagealloc.free = xalloc(conf.nimage*sizeof(Image));	if (imagealloc.free == nil)		panic("initseg: no memory");	ie = &imagealloc.free[conf.nimage-1];	for(i = imagealloc.free; i < ie; i++)		i->next = i+1;	i->next = 0;	imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*));	imagealloc.szfreechan = NFREECHAN;} Segment *newseg(int type, ulong base, ulong size){	Segment *s;	int mapsize; 	if(size > (SEGMAPSIZE*PTEPERTAB))		error(Enovmem); 	if(swapfull())		error(Enoswap);	s = smalloc(sizeof(Segment));	s->ref.ref = 1;	s->type = type;	s->base = base;	s->top = base+(size*BY2PG);	s->size = size;	s->sema.prev = &s->sema;	s->sema.next = &s->sema; 	mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB;	if(mapsize > nelem(s->ssegmap)){		mapsize *= 2;		if(mapsize > (SEGMAPSIZE*PTEPERTAB))			mapsize = (SEGMAPSIZE*PTEPERTAB);		s->map = smalloc(mapsize*sizeof(Pte*));		s->mapsize = mapsize;	}	else{		s->map = s->ssegmap;		s->mapsize = nelem(s->ssegmap);	} 	return s;} voidputseg(Segment *s){	Pte **pp, **emap;	Image *i; 	if(s == 0)		return; 	i = s->image;	if(i != 0) {		lock(&i->ref.lk);		lock(&s->ref.lk);		if(i->s == s && s->ref.ref == 1)			i->s = 0;		unlock(&i->ref.lk);	}	else		lock(&s->ref.lk); 	s->ref.ref--;	if(s->ref.ref != 0) {		unlock(&s->ref.lk);		return;	}	unlock(&s->ref.lk); 	qlock(&s->lk);	if(i)		putimage(i); 	emap = &s->map[s->mapsize];	for(pp = s->map; pp < emap; pp++)		if(*pp)			freepte(s, *pp); 	qunlock(&s->lk);	if(s->map != s->ssegmap)		free(s->map);	if(s->profile != 0)		free(s->profile);	free(s);} voidrelocateseg(Segment *s, ulong offset){	Page **pg, *x;	Pte *pte, **p, **endpte; 	endpte = &s->map[s->mapsize];	for(p = s->map; p < endpte; p++) {		if(*p == 0)			continue;		pte = *p;		for(pg = pte->first; pg <= pte->last; pg++) {			if((x = *pg))				x->va += offset;		}	}} Segment*dupseg(Segment **seg, int segno, int share){	int i, size;	Pte *pte;	Segment *n, *s; 	n = 0;	s = seg[segno]; 	qlock(&s->lk);	if(waserror()){		qunlock(&s->lk);		nexterror();	}	switch(s->type&SG_TYPE) {	case SG_TEXT:		/* New segment shares pte set */	case SG_SHARED:	case SG_PHYSICAL:		goto sameseg; 	case SG_STACK:		n = newseg(s->type, s->base, s->size);		break; 	case SG_BSS:		/* Just copy on write */		if(share)			goto sameseg;		n = newseg(s->type, s->base, s->size);		break; 	case SG_DATA:		/* Copy on write plus demand load info */		if(segno == TSEG){			poperror();			qunlock(&s->lk);			return data2txt(s);		} 		if(share)			goto sameseg;		n = newseg(s->type, s->base, s->size); 		incref(&s->image->ref);		n->image = s->image;		n->fstart = s->fstart;		n->flen = s->flen;		break;	}	size = s->mapsize;	for(i = 0; i < size; i++)		if((pte = s->map[i]))			n->map[i] = ptecpy(pte); 	n->flushme = s->flushme;	if(s->ref.ref > 1)		procflushseg(s);	poperror();	qunlock(&s->lk);	return n; sameseg:	incref(&s->ref);	poperror();	qunlock(&s->lk);	return s;} voidsegpage(Segment *s, Page *p){	Pte **pte;	ulong off;	Page **pg; 	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(); 	pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];	*pg = p;	if(pg < (*pte)->first)		(*pte)->first = pg;	if(pg > (*pte)->last)		(*pte)->last = pg;} Image*attachimage(int type, Chan *c, ulong base, ulong len){	Image *i, **l; 	/* reclaim any free channels from reclaimed segments */print("nfreechan=%d\n", imagealloc.nfreechan);	if(imagealloc.nfreechan)		imagechanreclaim(); 	lock(&imagealloc.lk); 	/*	 * Search the image cache for remains of the text from a previous	 * or currently running incarnation	 */	for(i = ihash(c->qid.path); i; i = i->hash) {		if(c->qid.path == i->qid.path) {			lock(&i->ref.lk);			if(eqqid(c->qid, i->qid) &&			   eqqid(c->mqid, i->mqid) &&			   c->mchan == i->mchan &&			   c->type == i->type) {print("found %#p %d %s %#p %d\n", c, c->ref.ref, c->path->s, i->c, i->c->ref.ref);				goto found;			}			unlock(&i->ref.lk);		}	} 	/*	 * imagereclaim dumps pages from the free list which are cached by image	 * structures. This should free some image structures.	 */	while(!(i = imagealloc.free)) {		unlock(&imagealloc.lk);		imagereclaim();		sched();		lock(&imagealloc.lk);	} 	imagealloc.free = i->next; 	lock(&i->ref.lk);	incref(&c->ref);	i->c = c;	i->type = c->type;	i->qid = c->qid;	i->mqid = c->mqid;	i->mchan = c->mchan;	l = &ihash(c->qid.path);	i->hash = *l;	*l = i;print("new %#p %C %d %s\n", c, devtab[c->type]->dc, c->ref.ref, c->path->s);found:	unlock(&imagealloc.lk); 	if(i->s == 0) {		/* Disaster after commit in exec */		if(waserror()) {			unlock(&i->ref.lk);			pexit(Enovmem, 1);		}		i->s = newseg(type, base, len);		i->s->image = i;		i->ref.ref++;		poperror();	}	else		incref(&i->s->ref); print("iref %d\n", i->ref.ref);	return i;} static struct {	int	calls;			/* times imagereclaim was called */	int	loops;			/* times the main loop was run */	uvlong	ticks;			/* total time in the main loop */	uvlong	maxt;			/* longest time in main loop */} irstats; static voidimagereclaim(void){	int n;	Page *p;	uvlong ticks; 	irstats.calls++;	/* Somebody is already cleaning the page cache */	if(!canqlock(&imagealloc.ireclaim))		return; 	lock(&palloc.lk);	ticks = fastticks(nil);	n = 0;	/*	 * All the pages with images backing them are at the	 * end of the list (see putpage) so start there and work	 * backward.	 */	for(p = palloc.tail; p && p->image && n<1000; p = p->prev) {		if(p->ref == 0 && canlock(&p->lk)) {			if(p->ref == 0) {				n++;				uncachepage(p);			}			unlock(&p->lk);		}	}	ticks = fastticks(nil) - ticks;	unlock(&palloc.lk);	irstats.loops++;	irstats.ticks += ticks;	if(ticks > irstats.maxt)		irstats.maxt = ticks;	//print("T%llud+", ticks);	qunlock(&imagealloc.ireclaim);} /* *  since close can block, this has to be called outside of *  spin locks. */static voidimagechanreclaim(void){	Chan *c; print("imagechanreclaim %d\n", imagealloc.nfreechan);	/* Somebody is already cleaning the image chans */	if(!canqlock(&imagealloc.fcreclaim))		return; 	/*	 * We don't have to recheck that nfreechan > 0 after we	 * acquire the lock, because we're the only ones who decrement 	 * it (the other lock contender increments it), and there's only	 * one of us thanks to the qlock above.	 */	while(imagealloc.nfreechan > 0){		lock(&imagealloc.lk);		imagealloc.nfreechan--;		c = imagealloc.freechan[imagealloc.nfreechan];		unlock(&imagealloc.lk);print("cclose %C\n", devtab[c->type]->dc);		cclose(c);	} 	qunlock(&imagealloc.fcreclaim);} voidputimage(Image *i){	Chan *c, **cp;	Image *f, **l; 	if(i->notext)		return; print("putimage(%d)\n", i->ref.ref);	lock(&i->ref.lk);	if(--i->ref.ref == 0) {		l = &ihash(i->qid.path);		mkqid(&i->qid, ~0, ~0, QTFILE);		unlock(&i->ref.lk);		c = i->c; 		lock(&imagealloc.lk);		for(f = *l; f; f = f->hash) {			if(f == i) {				*l = i->hash;				break;			}			l = &f->hash;		} 		i->next = imagealloc.free;		imagealloc.free = i; 		/* defer freeing channel till we're out of spin lock's */		if(imagealloc.nfreechan == imagealloc.szfreechan){			imagealloc.szfreechan += NFREECHAN;			cp = malloc(imagealloc.szfreechan*sizeof(Chan*));			if(cp == nil)				panic("putimage");			memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*));			free(imagealloc.freechan);			imagealloc.freechan = cp;		}		imagealloc.freechan[imagealloc.nfreechan++] = c;		unlock(&imagealloc.lk); 		return;	}	unlock(&i->ref.lk);} longibrk(ulong addr, int seg){	Segment *s, *ns;	ulong newtop, newsize;	int i, mapsize;	Pte **map; 	s = up->seg[seg];	if(s == 0)		error(Ebadarg); 	if(addr == 0)		return s->base; 	qlock(&s->lk); 	/* We may start with the bss overlapping the data */	if(addr < s->base) {		if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) {			qunlock(&s->lk);			error(Enovmem);		}		addr = s->base;	} 	newtop = PGROUND(addr);	newsize = (newtop-s->base)/BY2PG;	if(newtop < s->top) {		mfreeseg(s, newtop, (s->top-newtop)/BY2PG);		s->top = newtop;		s->size = newsize;		qunlock(&s->lk);		flushmmu();		return 0;	} 	if(swapfull()){		qunlock(&s->lk);		error(Enoswap);	} 	for(i = 0; i < NSEG; i++) {		ns = up->seg[i];		if(ns == 0 || ns == s)			continue;		if(newtop >= ns->base && newtop < ns->top) {print("grow segment %d -> %p would overlap %d [%p-%p]\n",	seg, newtop, i, ns->base, ns->top);			qunlock(&s->lk);			error(Esoverlap);		}	} 	if(newsize > (SEGMAPSIZE*PTEPERTAB)) {

Lines 1–500 of 805.