|
|
1.1 root 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: int canflush(Proc *p, Segment*);
9: void executeio(void);
10: int needpages(void*);
11: void pageout(Proc *p, Segment*);
12: void pagepte(int, Page**);
13: void pager(void*);
14:
15: Image swapimage;
16: static int swopen;
17: static Page **iolist;
18: static int ioptr;
19: static int maxpages;
20:
21: void
22: swapinit(void)
23: {
24: swapalloc.swmap = xalloc(conf.nswap);
25: swapalloc.top = &swapalloc.swmap[conf.nswap];
26: swapalloc.alloc = swapalloc.swmap;
27: swapalloc.last = swapalloc.swmap;
28: swapalloc.free = conf.nswap;
29: maxpages = SEGMAXSIZE/BY2PG;
30: if(maxpages > conf.nswap/2)
31: maxpages = conf.nswap/2;
32: iolist = xalloc(maxpages*sizeof(Page*));
33: if(swapalloc.swmap == 0 || iolist == 0)
34: panic("swapinit: not enough memory");
35: }
36:
37: ulong
38: newswap(void)
39: {
40: uchar *look;
41:
42: lock(&swapalloc);
43: if(swapalloc.free == 0)
44: panic("out of swap space");
45:
46: look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
47: if(look == 0)
48: panic("inconsistent swap");
49:
50: *look = 1;
51: swapalloc.last = look;
52: swapalloc.free--;
53: unlock(&swapalloc);
54: return (look-swapalloc.swmap) * BY2PG;
55: }
56:
57: void
58: putswap(Page *p)
59: {
60: uchar *idx;
61:
62: lock(&swapalloc);
63: idx = &swapalloc.swmap[((ulong)p)/BY2PG];
64: if(--(*idx) == 0) {
65: swapalloc.free++;
66: if(idx < swapalloc.last)
67: swapalloc.last = idx;
68: }
69: unlock(&swapalloc);
70: }
71:
72: void
73: dupswap(Page *p)
74: {
75: lock(&swapalloc);
76: swapalloc.swmap[((ulong)p)/BY2PG]++;
77: unlock(&swapalloc);
78: }
79:
80: void
81: kickpager(void)
82: {
83: static int started;
84:
85: if(started)
86: wakeup(&swapalloc.r);
87: else {
88: kproc("pager", pager, 0);
89: started = 1;
90: }
91: }
92:
93: void
94: pager(void *junk)
95: {
96: int i;
97: Proc *p, *ep;
98: Segment *s, *ts;
99:
100: if(waserror())
101: panic("pager: os error\n");
102:
103: USED(junk);
104: p = proctab(0);
105: ep = &p[conf.nproc];
106:
107: loop:
108: u->p->psstate = "Idle";
109: sleep(&swapalloc.r, needpages, 0);
110:
111: while(needpages(junk)) {
112: p++;
113: if(p >= ep)
114: p = proctab(0);
115:
116: if(p->state == Dead || p->kp)
117: continue;
118:
119: /* don't swap out programs from devroot.c - they
120: * supply important system services
121: */
122: ts = p->seg[TSEG];
123: if(ts && ts->image && devchar[ts->image->c->type] == '/')
124: continue;
125:
126: if(swapimage.c) {
127: for(i = 0; i < NSEG; i++) {
128: if(!needpages(junk))
129: goto loop;
130:
131: if(s = p->seg[i]) {
132: switch(s->type&SG_TYPE) {
133: default:
134: break;
135: case SG_TEXT:
136: pageout(p, s);
137: break;
138: case SG_DATA:
139: case SG_BSS:
140: case SG_STACK:
141: case SG_SHARED:
142: u->p->psstate = "Pageout";
143: pageout(p, s);
144: if(ioptr != 0) {
145: u->p->psstate = "I/O";
146: executeio();
147: }
148: }
149: }
150: }
151: continue;
152: }
153:
154: if(palloc.freecount < swapalloc.highwater) {
155: if(!cpuserver)
156: freebroken(); /* can use the memory */
157:
158: /* Emulate the old system if no swap channel */
159: print("no physical memory\n");
160: tsleep(&swapalloc.r, return0, 0, 1000);
161: wakeup(&palloc.r);
162: }
163: }
164: goto loop;
165: }
166:
167: void
168: pageout(Proc *p, Segment *s)
169: {
170: int type, i;
171: Pte *l;
172: Page **pg, *entry;
173:
174: if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */
175: return;
176:
177: if(s->steal) { /* Protected by /dev/proc */
178: qunlock(&s->lk);
179: return;
180: }
181:
182: if(!canflush(p, s)) { /* Able to invalidate all tlbs with references */
183: qunlock(&s->lk);
184: putseg(s);
185: return;
186: }
187:
188: if(waserror()) {
189: qunlock(&s->lk);
190: putseg(s);
191: return;
192: }
193:
194: /* Pass through the pte tables looking for memory pages to swap out */
195: type = s->type&SG_TYPE;
196: for(i = 0; i < SEGMAPSIZE; i++) {
197: l = s->map[i];
198: if(l == 0)
199: continue;
200: for(pg = l->first; pg < l->last; pg++) {
201: entry = *pg;
202: if(pagedout(entry))
203: continue;
204:
205: if(entry->modref & PG_REF) {
206: entry->modref &= ~PG_REF;
207: continue;
208: }
209:
210: while(swapalloc.free == 0) {
211: if(ioptr != 0)
212: goto out;
213:
214: print("out of swap space\n");
215: tsleep(&swapalloc.r, return0, 0, 1000);
216: }
217:
218: pagepte(type, pg);
219:
220: if(ioptr >= maxpages)
221: goto out;
222: }
223: }
224: out:
225: poperror();
226: qunlock(&s->lk);
227: putseg(s);
228: wakeup(&palloc.r);
229: }
230:
231: int
232: canflush(Proc *p, Segment *s)
233: {
234: int i;
235: Proc *ep;
236:
237: lock(s);
238: if(s->ref == 1) { /* Easy if we are the only user */
239: s->ref++;
240: unlock(s);
241: return canpage(p);
242: }
243: s->ref++;
244: unlock(s);
245:
246: /* Now we must do hardwork to ensure all processes which have tlb
247: * entries for this segment will be flushed if we suceed in pageing it out
248: */
249: p = proctab(0);
250: ep = &p[conf.nproc];
251: while(p < ep) {
252: if(p->state != Dead) {
253: for(i = 0; i < NSEG; i++)
254: if(p->seg[i] == s)
255: if(!canpage(p))
256: return 0;
257: }
258: p++;
259: }
260: return 1;
261: }
262:
263: void
264: pagepte(int type, Page **pg)
265: {
266: ulong daddr;
267: Page *outp;
268:
269: outp = *pg;
270: switch(type) {
271: case SG_TEXT: /* Revert to demand load */
272: putpage(outp);
273: *pg = 0;
274: break;
275:
276: case SG_DATA:
277: case SG_BSS:
278: case SG_STACK:
279: case SG_SHARED:
280: case SG_SHDATA:
281: daddr = newswap();
282: cachedel(&swapimage, daddr);
283: lock(outp);
284: outp->ref++;
285: uncachepage(outp);
286: unlock(outp);
287:
288: /* Enter swap page into cache before segment is unlocked so that
289: * a fault will cause a cache recovery rather than a pagein on a
290: * partially written block.
291: */
292: outp->daddr = daddr;
293: cachepage(outp, &swapimage);
294: *pg = (Page*)(daddr|PG_ONSWAP);
295:
296: /* Add me to IO transaction list */
297: iolist[ioptr++] = outp;
298: }
299: }
300:
301: void
302: executeio(void)
303: {
304: Page *out;
305: int i, n;
306: Chan *c;
307: char *kaddr;
308: KMap *k;
309:
310: c = swapimage.c;
311:
312: for(i = 0; i < ioptr; i++) {
313: out = iolist[i];
314: k = kmap(out);
315: kaddr = (char*)VA(k);
316:
317: if(waserror())
318: panic("executeio: page out I/O error");
319:
320: n = (*devtab[c->type].write)(c, kaddr, BY2PG, out->daddr);
321: if(n != BY2PG)
322: nexterror();
323:
324: kunmap(k);
325: poperror();
326:
327: /* Free up the page after I/O */
328: lock(out);
329: out->ref--;
330: unlock(out);
331: putpage(out);
332: }
333: ioptr = 0;
334: }
335:
336: int
337: needpages(void *p)
338: {
339: USED(p);
340: return palloc.freecount < swapalloc.headroom;
341: }
342:
343: void
344: setswapchan(Chan *c)
345: {
346: if(swapimage.c) {
347: if(swapalloc.free != conf.nswap)
348: error(Einuse);
349: close(swapimage.c);
350: }
351: incref(c);
352: swapimage.c = c;
353: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.