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