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