]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/page.c
audiohda: fix syntax error
[plan9front.git] / sys / src / 9 / port / page.c
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 Palloc palloc;
9
10 ulong
11 nkpages(Confmem *cm)
12 {
13         return ((cm->klimit - cm->kbase) + BY2PG-1) / BY2PG;
14 }
15
16 void
17 pageinit(void)
18 {
19         int color, i, j;
20         Page *p, **t;
21         Confmem *cm;
22         vlong m, v, u;
23
24         if(palloc.pages == nil){
25                 ulong np;
26
27                 np = 0;
28                 for(i=0; i<nelem(conf.mem); i++){
29                         cm = &conf.mem[i];
30                         np += cm->npage - nkpages(cm);
31                 }
32                 palloc.pages = xalloc(np*sizeof(Page));
33                 if(palloc.pages == nil)
34                         panic("pageinit");
35         }
36
37         color = 0;
38         palloc.freecount = 0;
39         palloc.head = nil;
40
41         t = &palloc.head;
42         p = palloc.pages;
43
44         for(i=0; i<nelem(conf.mem); i++){
45                 cm = &conf.mem[i];
46                 for(j=nkpages(cm); j<cm->npage; j++){
47                         memset(p, 0, sizeof *p);
48                         p->pa = cm->base+j*BY2PG;
49                         if(cankaddr(p->pa) && (KADDR(p->pa) == nil || KADDR(p->pa) == (void*)-BY2PG))
50                                 continue;
51                         p->color = color;
52                         color = (color+1)%NCOLOR;
53                         *t = p, t = &p->next;
54                         palloc.freecount++;
55                         p++;
56                 }
57         }
58
59         palloc.user = p - palloc.pages;
60         u = palloc.user*BY2PG;
61         v = u + conf.nswap*BY2PG;
62
63         /* Paging numbers */
64         swapalloc.highwater = (palloc.user*5)/100;
65         swapalloc.headroom = swapalloc.highwater + (swapalloc.highwater/4);
66
67         m = 0;
68         for(i=0; i<nelem(conf.mem); i++)
69                 if(conf.mem[i].npage)
70                         m += conf.mem[i].npage*BY2PG;
71         m += PGROUND(end - (char*)KTZERO);
72
73         print("%lldM memory: ", (m+1024*1024-1)/(1024*1024));
74         print("%lldM kernel data, ", (m-u+1024*1024-1)/(1024*1024));
75         print("%lldM user, ", u/(1024*1024));
76         print("%lldM swap\n", v/(1024*1024));
77 }
78
79 static void
80 pagechaindone(void)
81 {
82         if(palloc.pwait[0].p != nil && wakeup(&palloc.pwait[0]) != nil)
83                 return;
84         if(palloc.pwait[1].p != nil)
85                 wakeup(&palloc.pwait[1]);
86 }
87
88 void
89 freepages(Page *head, Page *tail, ulong np)
90 {
91         if(head == nil)
92                 return;
93         if(tail == nil){
94                 tail = head;
95                 for(np = 1;; np++){
96                         tail->ref = 0;
97                         if(tail->next == nil)
98                                 break;
99                         tail = tail->next;
100                 }
101         }
102         lock(&palloc);
103         tail->next = palloc.head;
104         palloc.head = head;
105         palloc.freecount += np;
106         pagechaindone();
107         unlock(&palloc);
108 }
109
110 ulong
111 pagereclaim(Image *i)
112 {
113         Page **h, **l, **x, *p;
114         Page *fh, *ft;
115         ulong np;
116
117         lock(i);
118         if(i->pgref == 0){
119                 unlock(i);
120                 return 0;
121         }
122         incref(i);
123
124         np = 0;
125         fh = ft = nil;
126         for(h = i->pghash; h < &i->pghash[PGHSIZE]; h++){
127                 l = h;
128                 x = nil;
129                 for(p = *l; p != nil; p = p->next){
130                         if(p->ref == 0)
131                                 x = l;
132                         l = &p->next;
133                 }
134                 if(x == nil)
135                         continue;
136
137                 p = *x;
138                 *x = p->next;
139                 p->next = nil;
140                 p->image = nil;
141                 p->daddr = ~0;
142
143                 if(fh == nil)
144                         fh = p;
145                 else
146                         ft->next = p;
147                 ft = p;
148                 np++;
149
150                 decref(i);
151                 if(--i->pgref == 0)
152                         break;
153         }
154         putimage(i);
155
156         if(np > 0)
157                 freepages(fh, ft, np);
158
159         return np;
160 }
161
162 static int
163 ispages(void*)
164 {
165         return palloc.freecount > swapalloc.highwater || up->noswap && palloc.freecount > 0;
166 }
167
168 Page*
169 newpage(int clear, Segment **s, uintptr va)
170 {
171         Page *p, **l;
172         KMap *k;
173         int color;
174
175         lock(&palloc);
176         while(!ispages(nil)){
177                 unlock(&palloc);
178                 if(s != nil)
179                         qunlock(*s);
180
181                 if(!waserror()){
182                         Rendezq *q;
183
184                         q = &palloc.pwait[!up->noswap];
185                         eqlock(q);      
186                         if(!waserror()){
187                                 kickpager();
188                                 sleep(q, ispages, nil);
189                                 poperror();
190                         }
191                         qunlock(q);
192                         poperror();
193                 }
194
195                 /*
196                  * If called from fault and we lost the segment from
197                  * underneath don't waste time allocating and freeing
198                  * a page. Fault will call newpage again when it has
199                  * reacquired the segment locks
200                  */
201                 if(s != nil){
202                         *s = nil;
203                         return nil;
204                 }
205                 lock(&palloc);
206         }
207
208         /* First try for our colour */
209         color = getpgcolor(va);
210         l = &palloc.head;
211         for(p = *l; p != nil; p = p->next){
212                 if(p->color == color)
213                         break;
214                 l = &p->next;
215         }
216
217         if(p == nil) {
218                 l = &palloc.head;
219                 p = *l;
220         }
221
222         *l = p->next;
223         p->next = nil;
224         palloc.freecount--;
225         unlock(&palloc);
226
227         p->ref = 1;
228         p->va = va;
229         p->modref = 0;
230         p->txtflush = 0;
231
232         if(clear) {
233                 k = kmap(p);
234                 memset((void*)VA(k), 0, BY2PG);
235                 kunmap(k);
236         }
237
238         return p;
239 }
240
241 void
242 putpage(Page *p)
243 {
244         if(onswap(p)) {
245                 putswap(p);
246                 return;
247         }
248         if(p->image != nil) {
249                 decref(p);
250                 return;
251         }
252         if(decref(p) == 0)
253                 freepages(p, p, 1);
254 }
255
256 void
257 copypage(Page *f, Page *t)
258 {
259         KMap *ks, *kd;
260
261         ks = kmap(f);
262         kd = kmap(t);
263         memmove((void*)VA(kd), (void*)VA(ks), BY2PG);
264         kunmap(ks);
265         kunmap(kd);
266 }
267
268 void
269 cachepage(Page *p, Image *i)
270 {
271         Page **h;
272
273         lock(i);
274         p->image = i;
275         h = &PGHASH(i, p->daddr);
276         p->next = *h;
277         *h = p;
278         incref(i);
279         i->pgref++;
280         unlock(i);
281 }
282
283 void
284 uncachepage(Page *p)
285 {
286         Page **l, *x;
287         Image *i;
288
289         i = p->image;
290         if(i == nil)
291                 return;
292
293         lock(i);
294         if(p->image != i){
295                 unlock(i);
296                 return;
297         }
298         l = &PGHASH(i, p->daddr);
299         for(x = *l; x != nil; x = x->next) {
300                 if(x == p){
301                         *l = p->next;
302                         p->next = nil;
303                         p->image = nil;
304                         p->daddr = ~0;
305                         i->pgref--;
306                         putimage(i);
307                         return;
308                 }
309                 l = &x->next;
310         }
311         unlock(i);
312 }
313
314 Page*
315 lookpage(Image *i, uintptr daddr)
316 {
317         Page *p, **h, **l;
318
319         lock(i);
320         l = h = &PGHASH(i, daddr);
321         for(p = *l; p != nil; p = p->next){
322                 if(p->daddr == daddr){
323                         *l = p->next;
324                         p->next = *h;
325                         *h = p;
326                         incref(p);
327                         unlock(i);
328                         return p;
329                 }
330                 l = &p->next;
331         }
332         unlock(i);
333
334         return nil;
335 }
336
337 void
338 cachedel(Image *i, uintptr daddr)
339 {
340         Page *p;
341
342         while((p = lookpage(i, daddr)) != nil){
343                 uncachepage(p);
344                 putpage(p);
345         }
346 }
347
348
349 Pte*
350 ptecpy(Pte *old)
351 {
352         Pte *new;
353         Page **src, **dst;
354
355         new = ptealloc();
356         dst = &new->pages[old->first-old->pages];
357         new->first = dst;
358         for(src = old->first; src <= old->last; src++, dst++)
359                 if(*src != nil) {
360                         if(onswap(*src))
361                                 dupswap(*src);
362                         else
363                                 incref(*src);
364                         new->last = dst;
365                         *dst = *src;
366                 }
367
368         return new;
369 }
370
371 Pte*
372 ptealloc(void)
373 {
374         Pte *new;
375
376         new = smalloc(sizeof(Pte));
377         new->first = &new->pages[PTEPERTAB];
378         new->last = new->pages;
379         return new;
380 }
381
382 void
383 freepte(Segment*, Pte *p)
384 {
385         Page **pg, **pe;
386
387         pg = p->first;
388         pe = p->last;
389         while(pg <= pe){
390                 if(*pg != nil)
391                         putpage(*pg);
392                 pg++;
393         }
394         free(p);
395 }