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

1992/0303/port/swap.c (diff list | history)

port/swap.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    
 
/* Predeclaration */ 
void	pageout(Proc *p, Segment*); 
int	pagepte(int, Segment*, Page**); 
int	needpages(void*); 
void	pager(void*); 
void	executeio(void); 
int	canflush(Proc *p, Segment*); 
 
enum 
{ 
1992/0303    
	Maxpages = 500,		/* Max number of pageouts per segment pass */ 
1991/0705    
}; 
 
1992/0303    
#define DBG	if(1)print 
 
1991/0705    
Image 	swapimage; 
static 	int swopen; 
Page	*iolist[Maxpages]; 
int	ioptr; 
1992/0302    
int	scavenge; 
1991/0705    
 
void 
swapinit(void) 
{ 
	swapalloc.swmap = ialloc(conf.nswap, 0); 
	swapalloc.top = &swapalloc.swmap[conf.nswap]; 
	swapalloc.alloc = swapalloc.swmap; 
 
	swapalloc.free = conf.nswap; 
} 
 
ulong 
newswap(void) 
{ 
	char *look; 
	int n; 
 
	lock(&swapalloc); 
	if(swapalloc.free == 0) 
		panic("out of swap space"); 
 
	n = swapalloc.top - swapalloc.alloc; 
	look = swapalloc.alloc; 
	while(n && *look) { 
		n--; 
		look++; 
	} 
	if(n == 0) { 
		look = swapalloc.swmap; 
		while(*look) 
			look++; 
	} 
	if(look == swapalloc.top) 
		swapalloc.alloc = swapalloc.swmap; 
	else 
		swapalloc.alloc = look+1; 
 
	*look = 1; 
1991/0928    
	swapalloc.free--; 
1991/0705    
	unlock(&swapalloc); 
	return (look-swapalloc.swmap) * BY2PG;  
} 
 
void 
putswap(Page *p) 
{ 
	lock(&swapalloc); 
	if(--swapalloc.swmap[((ulong)p)/BY2PG] == 0) 
		swapalloc.free++; 
	unlock(&swapalloc); 
} 
 
void 
dupswap(Page *p) 
{ 
	lock(&swapalloc); 
	swapalloc.swmap[((ulong)p)/BY2PG]++; 
	unlock(&swapalloc); 
} 
 
void 
kickpager(void) 
{ 
	static int started; 
 
	if(started) 
		wakeup(&swapalloc.r); 
	else { 
		kproc("pager", pager, 0); 
		started = 1; 
	} 
} 
 
void 
pager(void *junk) 
{ 
	Proc *p, *ep; 
	Segment *s; 
	int i; 
 
1992/0303    
	if(waserror())  
		panic("pager: os error\n"); 
 
1991/1115    
	USED(junk); 
1991/0705    
	p = proctab(0); 
	ep = &p[conf.nproc]; 
 
1992/0303    
loop: 
	u->p->psstate = "Idle"; 
	sleep(&swapalloc.r, needpages, 0); 
	u->p->psstate = "Pageout"; 
1992/0301    
 
1992/0303    
	for(;;) { 
		p++; 
		if(p > ep) 
			p = proctab(0); 
1991/0705    
 
1992/0303    
		if(p->state == Dead || p->kp) 
			continue; 
1992/0130    
 
1992/0303    
		if(swapimage.c) { 
			for(i = 0; i < NSEG; i++) { 
				if(!needpages(junk)) 
					goto loop; 
				if(s = p->seg[i]) { 
					pageout(p, s); 
					executeio(); 
				} 
1991/0705    
			} 
		} 
1992/0303    
		else  
		if(palloc.freecount < swapalloc.highwater) { 
			/* Rob made me do it ! */ 
			if(conf.cntrlp == 0) 
				freebroken(); 
1991/0705    
 
1992/0303    
			/* Emulate the old system if no swap channel */ 
			print("no physical memory\n"); 
			tsleep(&swapalloc.r, return0, 0, 1000); 
			wakeup(&palloc.r); 
		} 
1991/0705    
	} 
1992/0303    
	goto loop; 
1991/0705    
} 
 
void			 
pageout(Proc *p, Segment *s) 
{ 
1992/0302    
	Pte **sm, **endsm, *l; 
	Page **pg, *entry; 
1992/0303    
	int type, nr; 
1992/0302    
extern char *sname[]; 
1991/0705    
 
1992/0303    
 
1991/0705    
	if(!canqlock(&s->lk))	/* We cannot afford to wait, we will surely deadlock */ 
		return; 
 
1992/0303    
	if(s->steal) { 
1991/0705    
		qunlock(&s->lk); 
		putseg(s); 
		return; 
	} 
 
1992/0303    
	if(!canflush(p, s)) { 
		qunlock(&s->lk); 
		putseg(s); 
		return; 
	} 
 
1991/0705    
	if(waserror()) { 
		qunlock(&s->lk); 
		putseg(s); 
		return; 
	} 
 
1992/0302    
	scavenge = 0; 
1992/0303    
	nr = 0; 
1992/0302    
 
1991/0705    
	/* Pass through the pte tables looking for memory pages to swap out */ 
	type = s->type&SG_TYPE; 
	endsm = &s->map[SEGMAPSIZE]; 
1992/0302    
	for(sm = s->map; sm < endsm; sm++) { 
		l = *sm; 
		if(l == 0) 
			continue; 
		for(pg = l->first; pg < l->last; pg++) { 
1992/0303    
			nr++; 
1992/0302    
			entry = *pg; 
			if(pagedout(entry)) 
				continue; 
1992/0303    
 
			if(entry->modref & PG_REF) 
1992/0302    
				entry->modref &= ~PG_REF; 
			else  
				pagepte(type, s, pg); 
1991/0705    
 
1992/0302    
			if(ioptr >= Maxpages) 
				goto out; 
		} 
	} 
out: 
1992/0303    
	DBG("%s: %d: %5s s %d nr %d fr %d\n",  
	p->text, p->pid, sname[type], scavenge, nr, palloc.freecount); 
 
1991/0705    
	poperror(); 
	qunlock(&s->lk); 
	putseg(s); 
	wakeup(&palloc.r); 
} 
 
int 
canflush(Proc *p, Segment *s) 
{ 
	Proc *ep; 
	int i; 
 
	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 
1991/0706    
	 * entries for this segment will be flushed if we suceed in pageing it out 
1991/0705    
	 */ 
	p = proctab(0); 
	ep = &p[conf.nproc]; 
1992/0302    
	while(p < ep) { 
		if(p->state != Dead) { 
1991/0705    
			for(i = 0; i < NSEG; i++) 
				if(p->seg[i] == s) 
					if(!canpage(p)) 
						return 0; 
1992/0302    
		} 
		p++; 
	} 
 
1991/0705    
	return 1;						 
} 
 
int 
pagepte(int type, Segment *s, Page **pg) 
{ 
	ulong daddr; 
	Page *outp; 
 
	outp = *pg; 
	switch(type) { 
	case SG_TEXT:					/* Revert to demand load */ 
		putpage(outp); 
		*pg = 0; 
1992/0302    
		scavenge++; 
1991/0705    
		break; 
1992/0302    
 
1991/0705    
	case SG_DATA: 
	case SG_BSS: 
	case SG_STACK: 
	case SG_SHARED: 
		lockpage(outp); 
		outp->ref++; 
		uncachepage(outp); 
		unlockpage(outp); 
 
		daddr = newswap(); 
		outp->daddr = daddr; 
 
		/* Enter swap page into cache before segment is unlocked so that 
		 * a fault will cause a cache recovery rather than a pagein on a 
		 * partially written block. 
		 */ 
		cachepage(outp, &swapimage); 
		*pg = (Page*)(daddr|PG_ONSWAP); 
 
		/* Add me to IO transaction list */ 
		iolist[ioptr++] = outp; 
1992/0302    
		scavenge++; 
1991/0705    
	} 
 
	return 1; 
} 
 
void 
executeio(void) 
{ 
	Page *out; 
	int i, n; 
	Chan *c; 
	char *kaddr; 
	KMap *k; 
 
	c = swapimage.c; 
 
	for(i = 0; i < ioptr; i++) { 
		out = iolist[i]; 
1992/0303    
 
1991/0705    
		k = kmap(out); 
		kaddr = (char*)VA(k); 
		qlock(&c->wrl); 
 
		if(waserror()) 
			panic("executeio: page out I/O error"); 
 
		n = (*devtab[c->type].write)(c, kaddr, BY2PG, out->daddr); 
		if(n != BY2PG) 
			nexterror(); 
 
		qunlock(&c->wrl); 
		kunmap(k); 
		poperror(); 
 
		/* Free up the page after I/O */ 
		lockpage(out); 
		out->ref--; 
		unlockpage(out); 
		putpage(out); 
	} 
 
	ioptr = 0; 
} 
 
int 
needpages(void *p) 
{ 
1991/1115    
	USED(p); 
1992/0303    
	return palloc.freecount < swapalloc.headroom; 
1991/0705    
} 
 
void 
setswapchan(Chan *c) 
{ 
	if(swapimage.c) { 
		if(swapalloc.free != conf.nswap) 
1992/0114    
			error(Einuse); 
1991/0705    
		close(swapimage.c); 
	} 
	incref(c); 
	swapimage.c = c; 
} 
 


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