xref: /plan9-contrib/sys/src/9k/port/pager.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
1*094d6818SDavid du Colombier #include	"u.h"
2*094d6818SDavid du Colombier #include	"../port/lib.h"
3*094d6818SDavid du Colombier #include	"mem.h"
4*094d6818SDavid du Colombier #include	"dat.h"
5*094d6818SDavid du Colombier #include	"fns.h"
6*094d6818SDavid du Colombier #include	"../port/error.h"
7*094d6818SDavid du Colombier 
8*094d6818SDavid du Colombier /*
9*094d6818SDavid du Colombier  * There's no pager process here.
10*094d6818SDavid du Colombier  * One process waiting for memory becomes the pager,
11*094d6818SDavid du Colombier  * during the call to kickpager()
12*094d6818SDavid du Colombier  */
13*094d6818SDavid du Colombier 
14*094d6818SDavid du Colombier static QLock	pagerlck;
15*094d6818SDavid du Colombier static struct
16*094d6818SDavid du Colombier {
17*094d6818SDavid du Colombier 	ulong ntext;
18*094d6818SDavid du Colombier 	ulong nbig;
19*094d6818SDavid du Colombier 	ulong nall;
20*094d6818SDavid du Colombier } pstats;
21*094d6818SDavid du Colombier 
22*094d6818SDavid du Colombier static void
freepages(uint lg2size,int once)23*094d6818SDavid du Colombier freepages(uint lg2size, int once)
24*094d6818SDavid du Colombier {
25*094d6818SDavid du Colombier 	Pallocpg *pg;
26*094d6818SDavid du Colombier 	Page *p;
27*094d6818SDavid du Colombier 	int i;
28*094d6818SDavid du Colombier 
29*094d6818SDavid du Colombier 	for(i = lg2size; i < nelem(palloc.avail); i++){
30*094d6818SDavid du Colombier 		pg = &palloc.avail[i];
31*094d6818SDavid du Colombier 		if(pg->freecount > 0){
32*094d6818SDavid du Colombier 			DBG("kickpager() up %#p: releasing %udK pages\n",
33*094d6818SDavid du Colombier 				up, (1<<lg2size)/KiB);
34*094d6818SDavid du Colombier 			lock(&palloc);
35*094d6818SDavid du Colombier 			if(pg->freecount == 0){
36*094d6818SDavid du Colombier 				unlock(&palloc);
37*094d6818SDavid du Colombier 				continue;
38*094d6818SDavid du Colombier 			}
39*094d6818SDavid du Colombier 			p = pg->head;
40*094d6818SDavid du Colombier 			pageunchain(p);
41*094d6818SDavid du Colombier 			unlock(&palloc);
42*094d6818SDavid du Colombier 			if(p->ref != 0)
43*094d6818SDavid du Colombier 				panic("freepages pa %#ullx", p->pa);
44*094d6818SDavid du Colombier 			pgfree(p);
45*094d6818SDavid du Colombier 			if(once)
46*094d6818SDavid du Colombier 				break;
47*094d6818SDavid du Colombier 		}
48*094d6818SDavid du Colombier 	}
49*094d6818SDavid du Colombier }
50*094d6818SDavid du Colombier 
51*094d6818SDavid du Colombier static int
tryalloc(int lg2size,int color)52*094d6818SDavid du Colombier tryalloc(int lg2size, int color)
53*094d6818SDavid du Colombier {
54*094d6818SDavid du Colombier 	Page *p;
55*094d6818SDavid du Colombier 
56*094d6818SDavid du Colombier 	p = pgalloc(lg2size, color);
57*094d6818SDavid du Colombier 	if(p != nil){
58*094d6818SDavid du Colombier 		lock(&palloc);
59*094d6818SDavid du Colombier 		pagechainhead(p);
60*094d6818SDavid du Colombier 		unlock(&palloc);
61*094d6818SDavid du Colombier 		return 0;
62*094d6818SDavid du Colombier 	}
63*094d6818SDavid du Colombier 	return -1;
64*094d6818SDavid du Colombier }
65*094d6818SDavid du Colombier 
66*094d6818SDavid du Colombier static int
hascolor(Page * pl,int color)67*094d6818SDavid du Colombier hascolor(Page *pl, int color)
68*094d6818SDavid du Colombier {
69*094d6818SDavid du Colombier 	Page *p;
70*094d6818SDavid du Colombier 
71*094d6818SDavid du Colombier 	lock(&palloc);
72*094d6818SDavid du Colombier 	for(p = pl; p != nil; p = p->next)
73*094d6818SDavid du Colombier 		if(color == NOCOLOR || p->color == color){
74*094d6818SDavid du Colombier 			unlock(&palloc);
75*094d6818SDavid du Colombier 			return 1;
76*094d6818SDavid du Colombier 		}
77*094d6818SDavid du Colombier 	unlock(&palloc);
78*094d6818SDavid du Colombier 	return 0;
79*094d6818SDavid du Colombier }
80*094d6818SDavid du Colombier 
81*094d6818SDavid du Colombier /*
82*094d6818SDavid du Colombier  * Someone couldn't find pages of the given size index and color.
83*094d6818SDavid du Colombier  * (color may be NOCOLOR if the caller is trying to get any page
84*094d6818SDavid du Colombier  * and is desperate).
85*094d6818SDavid du Colombier  * Many processes may be calling this at the same time,
86*094d6818SDavid du Colombier  * The first one operates as a pager and does what it can.
87*094d6818SDavid du Colombier  */
88*094d6818SDavid du Colombier void
kickpager(uint lg2size,int color)89*094d6818SDavid du Colombier kickpager(uint lg2size, int color)
90*094d6818SDavid du Colombier {
91*094d6818SDavid du Colombier 	Pallocpg *pg;
92*094d6818SDavid du Colombier 
93*094d6818SDavid du Colombier 	print("kickpager page size %dK color %d\n", (1<<lg2size)/KiB, color);
94*094d6818SDavid du Colombier 
95*094d6818SDavid du Colombier 	if(DBGFLG>1)
96*094d6818SDavid du Colombier 		DBG("kickpager() %#p\n", up);
97*094d6818SDavid du Colombier 	if(waserror())
98*094d6818SDavid du Colombier 		panic("error in kickpager");
99*094d6818SDavid du Colombier 	qlock(&pagerlck);
100*094d6818SDavid du Colombier 	pg = &palloc.avail[lg2size];
101*094d6818SDavid du Colombier 
102*094d6818SDavid du Colombier 	/*
103*094d6818SDavid du Colombier 	 * 1. did anyone else release one for us in the mean time?
104*094d6818SDavid du Colombier 	 */
105*094d6818SDavid du Colombier 	if(hascolor(pg->head, color))
106*094d6818SDavid du Colombier 		goto Done;
107*094d6818SDavid du Colombier 
108*094d6818SDavid du Colombier 	/*
109*094d6818SDavid du Colombier 	 * 2. try allocating from physical memory
110*094d6818SDavid du Colombier 	 */
111*094d6818SDavid du Colombier 	tryalloc(lg2size, color);
112*094d6818SDavid du Colombier 	if(hascolor(pg->head, color))
113*094d6818SDavid du Colombier 		goto Done;
114*094d6818SDavid du Colombier 
115*094d6818SDavid du Colombier 	/*
116*094d6818SDavid du Colombier 	 * Try releasing memory from bigger pages.
117*094d6818SDavid du Colombier 	 */
118*094d6818SDavid du Colombier 	pstats.nbig++;
119*094d6818SDavid du Colombier 	freepages(1<<(lg2size+1), 1);
120*094d6818SDavid du Colombier 	tryalloc(lg2size, color);
121*094d6818SDavid du Colombier 	if(hascolor(pg->head, color)){
122*094d6818SDavid du Colombier 		DBG("kickpager() found %uld free\n", pg->freecount);
123*094d6818SDavid du Colombier 		goto Done;
124*094d6818SDavid du Colombier 	}
125*094d6818SDavid du Colombier 
126*094d6818SDavid du Colombier 	/*
127*094d6818SDavid du Colombier 	 * Really the last resort. Try releasing memory from all pages.
128*094d6818SDavid du Colombier 	 */
129*094d6818SDavid du Colombier 	pstats.nall++;
130*094d6818SDavid du Colombier 	DBG("kickpager() up %#p: releasing all pages\n", up);
131*094d6818SDavid du Colombier 	freepages(0, 0);
132*094d6818SDavid du Colombier 	tryalloc(lg2size, color);
133*094d6818SDavid du Colombier 	if(pg->freecount > 0){
134*094d6818SDavid du Colombier 		DBG("kickpager() found %uld free\n", pg->freecount);
135*094d6818SDavid du Colombier 		goto Done;
136*094d6818SDavid du Colombier 	}
137*094d6818SDavid du Colombier 
138*094d6818SDavid du Colombier 	/*
139*094d6818SDavid du Colombier 	 * What else can we do?
140*094d6818SDavid du Colombier 	 * But don't panic if we are still trying to get memory of
141*094d6818SDavid du Colombier 	 * a particular color and there's none. We'll retry asking
142*094d6818SDavid du Colombier 	 * for any color.
143*094d6818SDavid du Colombier 	 */
144*094d6818SDavid du Colombier 	if(color == NOCOLOR){
145*094d6818SDavid du Colombier 		print("out of physical memory\n");
146*094d6818SDavid du Colombier 		killbig("out of physical memory");
147*094d6818SDavid du Colombier 		freebroken();
148*094d6818SDavid du Colombier 	}
149*094d6818SDavid du Colombier 
150*094d6818SDavid du Colombier Done:
151*094d6818SDavid du Colombier 	poperror();
152*094d6818SDavid du Colombier 	qunlock(&pagerlck);
153*094d6818SDavid du Colombier 	if(DBGFLG>1)
154*094d6818SDavid du Colombier 		DBG("kickpager() done %#p\n", up);
155*094d6818SDavid du Colombier }
156*094d6818SDavid du Colombier 
157*094d6818SDavid du Colombier void
pagersummary(void)158*094d6818SDavid du Colombier pagersummary(void)
159*094d6818SDavid du Colombier {
160*094d6818SDavid du Colombier 	print("ntext %uld nbig %uld nall %uld\n",
161*094d6818SDavid du Colombier 		pstats.ntext, pstats.nbig, pstats.nall);
162*094d6818SDavid du Colombier 	print("no swap\n");
163*094d6818SDavid du Colombier }
164