⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 segment.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
字号:
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"static void	imagereclaim(void);static void	imagechanreclaim(void);/* System specific segattach devices */#include "io.h"#include "segment.h"static Lock physseglock;#define NFREECHAN	64#define IHASHSIZE	64#define ihash(s)	imagealloc.hash[s%IHASHSIZE]static struct{	Lock;	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;voidinitseg(void){	Image *i, *ie;	imagealloc.free = xalloc(conf.nimage*sizeof(Image));	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 = 1;	s->type = type;	s->base = base;	s->top = base+(size*BY2PG);	s->size = size;	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);		lock(s);		if(i->s == s && s->ref == 1)			i->s = 0;		unlock(i);	}	else		lock(s);	s->ref--;	if(s->ref != 0) {		unlock(s);		return;	}	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;	SET(n);	s = seg[segno];	switch(s->type&SG_TYPE) {	case SG_TEXT:		/* New segment shares pte set */	case SG_SHARED:	case SG_PHYSICAL:	case SG_SHDATA:		incref(s);		return s;	case SG_STACK:		qlock(&s->lk);		if(waserror()){			qunlock(&s->lk);			nexterror();		}		n = newseg(s->type, s->base, s->size);		poperror();		break;	case SG_BSS:		/* Just copy on write */	case SG_MAP:		qlock(&s->lk);		if(share && s->ref == 1) {			s->type = (s->type&~SG_TYPE)|SG_SHARED;			incref(s);			qunlock(&s->lk);			return s;		}		if(waserror()){			qunlock(&s->lk);			nexterror();		}		n = newseg(s->type, s->base, s->size);		poperror();		break;	case SG_DATA:		/* Copy on write plus demand load info */		if(segno == TSEG)			return data2txt(s);		qlock(&s->lk);		if(share && s->ref == 1) {			s->type = (s->type&~SG_TYPE)|SG_SHDATA;			incref(s);			qunlock(&s->lk);			return s;		}		if(waserror()){			qunlock(&s->lk);			nexterror();		}		n = newseg(s->type, s->base, s->size);		poperror();		incref(s->image);		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;	qunlock(&s->lk);	return n;}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 */	if(imagealloc.nfreechan)		imagechanreclaim();	lock(&imagealloc);	/*	 * 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);			if(eqqid(c->qid, i->qid) &&			   eqqid(c->mqid, i->mqid) &&			   c->mchan == i->mchan &&			   c->type == i->type) {				i->ref++;				goto found;			}			unlock(i);		}	}	/*	 * 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);		imagereclaim();		sched();		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) {		/* Disaster after commit in exec */		if(waserror()) {			unlock(i);			pexit(Enovmem, 1);		}		i->s = newseg(type, base, len);		i->s->image = i;		poperror();	}	else		incref(i->s);	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){	Page *p;	uvlong ticks;	irstats.calls++;	/* Somebody is already cleaning the page cache */	if(!canqlock(&imagealloc.ireclaim))		return;	lock(&palloc);	ticks = fastticks(nil);	for(p = palloc.head; p; p = p->next) {		if(p->ref == 0 && p->image && canlock(p)) {			if(p->ref == 0)				uncachepage(p);			unlock(p);		}	}	ticks = fastticks(nil) - ticks;	unlock(&palloc);	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;	/* 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);		imagealloc.nfreechan--;		c = imagealloc.freechan[imagealloc.nfreechan];		unlock(&imagealloc);		cclose(c);	}	qunlock(&imagealloc.fcreclaim);}voidputimage(Image *i){	Chan *c, **cp;	Image *f, **l;	if(i->notext)		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;		/* 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);		return;	}	unlock(i);}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);		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) {			qunlock(&s->lk);			error(Esoverlap);		}	}	if(newsize > (SEGMAPSIZE*PTEPERTAB)) {		qunlock(&s->lk);		error(Enovmem);	}	mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB;	if(mapsize > s->mapsize){		map = smalloc(mapsize*sizeof(Pte*));		memmove(map, s->map, s->mapsize*sizeof(Pte*));		if(s->map != s->ssegmap)			free(s->map);		s->map = map;		s->mapsize = mapsize;	}	s->top = newtop;	s->size = newsize;	qunlock(&s->lk);	return 0;}/* *  called with s->lk locked */voidmfreeseg(Segment *s, ulong start, int pages){	int i, j, size;	ulong soff;	Page *pg;	Page *list;	soff = start-s->base;	j = (soff&(PTEMAPMEM-1))/BY2PG;	size = s->mapsize;	list = nil;	for(i = soff/PTEMAPMEM; i < size; i++) {		if(pages <= 0)			break;		if(s->map[i] == 0) {			pages -= PTEPERTAB-j;			j = 0;			continue;		}		while(j < PTEPERTAB) {			pg = s->map[i]->pages[j];			if(pg){				s->map[i]->pages[j] = 0;				pg->next = list;				list = pg;			}			if(--pages == 0)				goto out;			j++;		}		j = 0;	}out:	/* flush this seg in all other processes */	i = s->type&SG_TYPE;	switch(i){	case SG_SHARED:	case SG_SHDATA:		procflushseg(s);		break;	}	/* free the pages */	for(pg = list; pg != nil; pg = list){		list = list->next;		putpage(pg);	}}Segment*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 ns;	}	return nil;}intaddphysseg(Physseg* new){	Physseg *ps;	/*	 * Check not already entered and there is room	 * for a new entry and the terminating null entry.	 */	lock(&physseglock);	for(ps = physseg; ps->name; ps++){		if(strcmp(ps->name, new->name) == 0){			unlock(&physseglock);			return -1;		}	}	if(ps-physseg >= nelem(physseg)-2){		unlock(&physseglock);		return -1;	}	*ps = *new;	unlock(&physseglock);	return 0;}ulongsegattach(Proc *p, ulong attr, char *name, ulong va, ulong len){	int sno;	Segment *s, *os;	Physseg *ps;	if(va != 0 && (va&KZERO) == KZERO)	/* BUG: Only ok for now */		error(Ebadarg);	validaddr((ulong)name, 1, 0);	vmemchr(name, 0, ~0);	for(sno = 0; sno < NSEG; sno++)		if(p->seg[sno] == nil && sno != ESEG)			break;	if(sno == NSEG)		error(Enovmem);	len = PGROUND(len);	if(len == 0)		error(Ebadarg);	/*	 * Find a hole in the address space.	 * Starting at the lowest possible stack address - len,	 * check for an overlapping segment, and repeat at the	 * base of that segment - len until either a hole is found	 * or the address space is exhausted.	 */	if(va == 0) {		va = p->seg[SSEG]->base - len;		for(;;) {			os = isoverlap(p, va, len);			if(os == nil)				break;			va = os->base;			if(len > va)				error(Enovmem);			va -= len;		}	}	va = va&~(BY2PG-1);	if(isoverlap(p, va, len) != nil)		error(Esoverlap);	for(ps = physseg; ps->name; ps++)		if(strcmp(name, ps->name) == 0)			goto found;	error(Ebadarg);found:	if(len > ps->size)		error(Enovmem);	attr &= ~SG_TYPE;		/* Turn off what is not allowed */	attr |= ps->attr;		/* Copy in defaults */	s = newseg(attr, va, len/BY2PG);	s->pseg = ps;	p->seg[sno] = s;	return va;}voidpteflush(Pte *pte, int s, int e){	int i;	Page *p;	for(i = s; i < e; i++) {		p = pte->pages[i];		if(pagedout(p) == 0)			memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl));	}}longsyssegflush(ulong *arg){	Segment *s;	ulong addr, l;	Pte *pte;	int chunk, ps, pe, len;	addr = arg[0];	len = arg[1];	while(len > 0) {		s = seg(up, addr, 1);		if(s == 0)			error(Ebadarg);		s->flushme = 1;	more:		l = len;		if(addr+l > s->top)			l = s->top - addr;		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);		chunk = pe-ps;		len -= chunk;		addr += chunk;		if(len > 0 && addr < s->top)			goto more;		qunlock(&s->lk);	}	flushmmu();	return 0;}voidsegclock(ulong pc){	Segment *s;	s = up->seg[TSEG];	if(s == 0 || s->profile == 0)		return;	s->profile[0] += TK2MS(1);	if(pc >= s->base && pc < s->top) {		pc -= s->base;		s->profile[pc>>LRESPROF] += TK2MS(1);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -