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

📄 swap.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"static int	canflush(Proc*, Segment*);static void	executeio(void);static int	needpages(void*);static void	pageout(Proc*, Segment*);static void	pagepte(int, Page**);static void	pager(void*);	Image 	swapimage;static 	int	swopen;static	Page	**iolist;static	int	ioptr;voidswapinit(void){	swapalloc.swmap = xalloc(conf.nswap);	swapalloc.top = &swapalloc.swmap[conf.nswap];	swapalloc.alloc = swapalloc.swmap;	swapalloc.last = swapalloc.swmap;	swapalloc.free = conf.nswap;	iolist = xalloc(conf.nswppo*sizeof(Page*));	if(swapalloc.swmap == 0 || iolist == 0)		panic("swapinit: not enough memory");	swapimage.notext = 1;}ulongnewswap(void){	uchar *look;	lock(&swapalloc);	if(swapalloc.free == 0){		unlock(&swapalloc);		return ~0;	}	look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);	if(look == 0)		panic("inconsistent swap");	*look = 1;	swapalloc.last = look;	swapalloc.free--;	unlock(&swapalloc);	return (look-swapalloc.swmap) * BY2PG;}voidputswap(Page *p){	uchar *idx;	lock(&swapalloc);	idx = &swapalloc.swmap[((ulong)p)/BY2PG];	if(--(*idx) == 0) {		swapalloc.free++;		if(idx < swapalloc.last)			swapalloc.last = idx;	}	if(*idx >= 254)		panic("putswap %lux == %ud", p, *idx);	unlock(&swapalloc);}voiddupswap(Page *p){	lock(&swapalloc);	if(++swapalloc.swmap[((ulong)p)/BY2PG] == 0)		panic("dupswap");	unlock(&swapalloc);}intswapcount(ulong daddr){	return swapalloc.swmap[daddr/BY2PG];}voidkickpager(void){	static int started;	if(started)		wakeup(&swapalloc.r);	else {		kproc("pager", pager, 0);		started = 1;	}}static voidpager(void *junk){	int i;	Segment *s;	Proc *p, *ep;	if(waserror())		panic("pager: os error\n");	p = proctab(0);	ep = &p[conf.nproc];loop:	up->psstate = "Idle";	sleep(&swapalloc.r, needpages, 0);	while(needpages(junk)) {		if(swapimage.c) {			p++;			if(p >= ep)				p = proctab(0);				if(p->state == Dead || p->noswap)				continue;			if(!canqlock(&p->seglock))				continue;		/* process changing its segments */			for(i = 0; i < NSEG; i++) {				if(!needpages(junk)){					qunlock(&p->seglock);					goto loop;				}				if(s = p->seg[i]) {					switch(s->type&SG_TYPE) {					default:						break;					case SG_TEXT:						pageout(p, s);						break;					case SG_DATA:					case SG_BSS:					case SG_STACK:					case SG_SHARED:						up->psstate = "Pageout";						pageout(p, s);						if(ioptr != 0) {							up->psstate = "I/O";							executeio();						}						break;					}				}			}			qunlock(&p->seglock);		}		else {			print("out of physical memory; no swap configured\n");			if(!cpuserver)				freebroken();	/* can use the memory */			else				killbig("out of memory");			/* Emulate the old system if no swap channel */			tsleep(&up->sleep, return0, 0, 5000);			wakeup(&palloc.r);		}	}	goto loop;}static voidpageout(Proc *p, Segment *s){	int type, i, size;	Pte *l;	Page **pg, *entry;	if(!canqlock(&s->lk))	/* We cannot afford to wait, we will surely deadlock */		return;	if(s->steal) {		/* Protected by /dev/proc */		qunlock(&s->lk);		return;	}	if(!canflush(p, s)) {	/* Able to invalidate all tlbs with references */		qunlock(&s->lk);		putseg(s);		return;	}	if(waserror()) {		qunlock(&s->lk);		putseg(s);		return;	}	/* Pass through the pte tables looking for memory pages to swap out */	type = s->type&SG_TYPE;	size = s->mapsize;	for(i = 0; i < size; i++) {		l = s->map[i];		if(l == 0)			continue;		for(pg = l->first; pg < l->last; pg++) {			entry = *pg;			if(pagedout(entry))				continue;			if(entry->modref & PG_REF) {				entry->modref &= ~PG_REF;				continue;			}			pagepte(type, pg);			if(ioptr >= conf.nswppo)				goto out;		}	}out:	poperror();	qunlock(&s->lk);	putseg(s);}static intcanflush(Proc *p, Segment *s){	int i;	Proc *ep;	lock(s);	if(s->ref == 1) {		/* Easy if we are the only user */		s->ref++;		unlock(s);		return canpage(p);	}	s->ref++;	unlock(s);	/* Now we must do hardwork to ensure all processes which have tlb	 * entries for this segment will be flushed if we succeed in paging it out	 */	p = proctab(0);	ep = &p[conf.nproc];	while(p < ep) {		if(p->state != Dead) {			for(i = 0; i < NSEG; i++)				if(p->seg[i] == s)					if(!canpage(p))						return 0;		}		p++;	}	return 1;}static voidpagepte(int type, Page **pg){	ulong daddr;	Page *outp;	outp = *pg;	switch(type) {	case SG_TEXT:				/* Revert to demand load */		putpage(outp);		*pg = 0;		break;	case SG_DATA:	case SG_BSS:	case SG_STACK:	case SG_SHARED:		/*		 *  get a new swap address and clear any pages		 *  referring to it from the cache		 */		daddr = newswap();		if(daddr == ~0)			break;		cachedel(&swapimage, daddr);		lock(outp);		/* forget anything that it used to cache */		uncachepage(outp);		/*		 *  incr the reference count to make sure it sticks around while		 *  being written		 */		outp->ref++;		/*		 *  enter it into the cache so that a fault happening		 *  during the write will grab the page from the cache		 *  rather than one partially written to the disk		 */		outp->daddr = daddr;		cachepage(outp, &swapimage);		*pg = (Page*)(daddr|PG_ONSWAP);		unlock(outp);		/* Add page to IO transaction list */		iolist[ioptr++] = outp;		break;	}}voidpagersummary(void){	print("%lud/%lud memory %lud/%lud swap %d iolist\n",		palloc.user-palloc.freecount,		palloc.user, conf.nswap-swapalloc.free, conf.nswap,		ioptr);}static voidexecuteio(void){	Page *out;	int i, n;	Chan *c;	char *kaddr;	KMap *k;	c = swapimage.c;	for(i = 0; i < ioptr; i++) {		if(ioptr > conf.nswppo)			panic("executeio: ioptr %d > %d\n", ioptr, conf.nswppo);		out = iolist[i];		k = kmap(out);		kaddr = (char*)VA(k);		if(waserror())			panic("executeio: page out I/O error");		n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);		if(n != BY2PG)			nexterror();		kunmap(k);		poperror();		/* Free up the page after I/O */		lock(out);		out->ref--;		unlock(out);		putpage(out);	}	ioptr = 0;}static intneedpages(void*){	return palloc.freecount < swapalloc.headroom;}voidsetswapchan(Chan *c){	uchar dirbuf[sizeof(Dir)+100];	Dir d;	int n;	if(swapimage.c) {		if(swapalloc.free != conf.nswap){			cclose(c);			error(Einuse);		}		cclose(swapimage.c);	}	/*	 *  if this isn't a file, set the swap space	 *  to be at most the size of the partition	 */	if(devtab[c->type]->dc != L'M'){		n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);		if(n <= 0){			cclose(c);			error("stat failed in setswapchan");		}		convM2D(dirbuf, n, &d, nil);		if(d.length < conf.nswap*BY2PG){			conf.nswap = d.length/BY2PG;			swapalloc.top = &swapalloc.swmap[conf.nswap];			swapalloc.free = conf.nswap;		}	}	swapimage.c = c;}intswapfull(void){	return swapalloc.free < conf.nswap/10;}

⌨️ 快捷键说明

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