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

1992/0130/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 
{ 
1991/0706    
	Maxpages = 500,		/* Max number of pageouts per segment pass */ 
1991/0705    
}; 
 
Image 	swapimage; 
static 	int swopen; 
Page	*iolist[Maxpages]; 
int	ioptr; 
 
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; 
 
1991/1115    
	USED(junk); 
1991/0705    
	p = proctab(0); 
	ep = &p[conf.nproc]; 
	for(;;) { 
		if(waserror())  
			panic("pager: os error\n"); 
 
		for(p = proctab(0); p < ep; p++) { 
			if(p->state == Dead || p->kp) 
				continue; 
 
1991/0926    
			u->p->psstate = "Idle"; 
1991/0705    
			sleep(&swapalloc.r, needpages, 0); 
1991/0926    
			u->p->psstate = "Pageout"; 
1991/0705    
 
1991/0726    
			if(p->state == Dead || p->kp) 
				continue; 
1991/0705    
			if(swapimage.c) { 
				for(i = 0; i < NSEG; i++) 
					if(s = p->seg[i]) { 
						pageout(p, s); 
						executeio(); 
					} 
			} 
1991/0727    
			else  
			if(palloc.freecount < HIGHWATER) { 
1992/0130    
				/* Rob made me do it ! */ 
				if(conf.cntrlp == 0) 
					freebroken(); 
 
1991/0705    
				/* Emulate the old system if no swap channel */ 
				print("no physical memory\n"); 
				tsleep(&swapalloc.r, return0, 0, 1000); 
				wakeup(&palloc.r); 
			} 
		} 
 
		poperror(); 
	} 
} 
 
void			 
pageout(Proc *p, Segment *s) 
{ 
	Pte **sm, **endsm; 
	Page **pg, **epg; 
	int type; 
 
	if(!canqlock(&s->lk))	/* We cannot afford to wait, we will surely deadlock */ 
		return; 
 
	if(!canflush(p, s) || s->steal) { 
		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; 
	endsm = &s->map[SEGMAPSIZE]; 
	for(sm = s->map; sm < endsm && ioptr < Maxpages; sm++) 
		if(*sm) { 
			pg = (*sm)->pages; 
			for(epg = &pg[PTEPERTAB]; pg < epg && ioptr < Maxpages; pg++) 
				if(!pagedout(*pg)) { 
					if((*pg)->modref & PG_REF) 
						(*pg)->modref &= ~PG_REF; 
					else  
					if(pagepte(type, s, pg) == 0) 
						break; 
				} 
		} 
 
	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]; 
	for(; p < ep; p++) 
		if(p->state != Dead) 
			for(i = 0; i < NSEG; i++) 
				if(p->seg[i] == s) 
					if(!canpage(p)) 
						return 0; 
	return 1;						 
} 
 
int 
pagepte(int type, Segment *s, Page **pg) 
{ 
	ulong daddr; 
	char *kaddr; 
	int n; 
	Chan *c; 
	Page *outp; 
	KMap *k; 
 
	outp = *pg; 
 
	switch(type) { 
	case SG_TEXT:					/* Revert to demand load */ 
		putpage(outp); 
		*pg = 0; 
		break; 
	case SG_DATA: 
		/* Unmodified data may be reverted to a demand load record if it 
		 * is not the last page in the DSEG 
		 */ 
/*							BUG: needs to check the last page 
		if((outp->modref&PG_MOD) == 0) { 
			putpage(outp); 
			*pg = 0; 
			break; 
		} 
*/ 
							/* NO break */	 
	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; 
	} 
 
	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]; 
		if(out->ref > 2) { 
			lockpage(out); 
			if(out->ref > 2) {		/* Page was reclaimed, abort io */ 
				out->ref -= 2; 
				unlockpage(out); 
				continue; 
			} 
			unlockpage(out); 
		} 
		k = kmap(out); 
		kaddr = (char*)VA(k); 
		qlock(&c->wrl); 
 
		/* BUG: what to do ? Nobody to tell, nowhere to go: open to suggestions  
		 *	the problem is I do not know whose page this is. 
		 */ 
		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); 
1991/0705    
	return palloc.freecount < HIGHWATER+MAXHEADROOM; 
} 
 
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)