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