| plan 9 kernel history: overview | file list | diff list |
1992/0303/port/swap.c (diff list | history)
| port/swap.c on 1991/0705 | ||
| 1991/0705 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1991/0705 | /* Predeclaration */ void pageout(Proc *p, Segment*); int pagepte(int, Segment*, Page**); int needpages(void*); void pager(void*); void executeio(void); int canflush(Proc *p, Segment*); enum { | |
| 1992/0303 | Maxpages = 500, /* Max number of pageouts per segment pass */ | |
| 1991/0705 | }; | |
| 1992/0303 | #define DBG if(1)print | |
| 1991/0705 | Image swapimage; static int swopen; Page *iolist[Maxpages]; int ioptr; | |
| 1992/0302 | int scavenge; | |
| 1991/0705 | void swapinit(void) { swapalloc.swmap = ialloc(conf.nswap, 0); swapalloc.top = &swapalloc.swmap[conf.nswap]; swapalloc.alloc = swapalloc.swmap; swapalloc.free = conf.nswap; } ulong newswap(void) { char *look; int n; lock(&swapalloc); if(swapalloc.free == 0) panic("out of swap space"); n = swapalloc.top - swapalloc.alloc; look = swapalloc.alloc; while(n && *look) { n--; look++; } if(n == 0) { look = swapalloc.swmap; while(*look) look++; } if(look == swapalloc.top) swapalloc.alloc = swapalloc.swmap; else swapalloc.alloc = look+1; *look = 1; | |
| 1991/0928 | swapalloc.free--; | |
| 1991/0705 | unlock(&swapalloc); return (look-swapalloc.swmap) * BY2PG; } void putswap(Page *p) { lock(&swapalloc); if(--swapalloc.swmap[((ulong)p)/BY2PG] == 0) swapalloc.free++; unlock(&swapalloc); } void dupswap(Page *p) { lock(&swapalloc); swapalloc.swmap[((ulong)p)/BY2PG]++; unlock(&swapalloc); } void kickpager(void) { static int started; if(started) wakeup(&swapalloc.r); else { kproc("pager", pager, 0); started = 1; } } void pager(void *junk) { Proc *p, *ep; Segment *s; int i; | |
| 1992/0303 | if(waserror()) panic("pager: os error\n"); | |
| 1991/1115 | USED(junk); | |
| 1991/0705 | p = proctab(0); ep = &p[conf.nproc]; | |
| 1992/0303 | loop: u->p->psstate = "Idle"; sleep(&swapalloc.r, needpages, 0); u->p->psstate = "Pageout"; | |
| 1992/0301 | ||
| 1992/0303 | for(;;) { p++; if(p > ep) p = proctab(0); | |
| 1991/0705 | ||
| 1992/0303 | if(p->state == Dead || p->kp) continue; | |
| 1992/0130 | ||
| 1992/0303 | if(swapimage.c) { for(i = 0; i < NSEG; i++) { if(!needpages(junk)) goto loop; if(s = p->seg[i]) { pageout(p, s); executeio(); } | |
| 1991/0705 | } } | |
| 1992/0303 | else if(palloc.freecount < swapalloc.highwater) { /* Rob made me do it ! */ if(conf.cntrlp == 0) freebroken(); | |
| 1991/0705 | ||
| 1992/0303 | /* Emulate the old system if no swap channel */ print("no physical memory\n"); tsleep(&swapalloc.r, return0, 0, 1000); wakeup(&palloc.r); } | |
| 1991/0705 | } | |
| 1992/0303 | goto loop; | |
| 1991/0705 | } void pageout(Proc *p, Segment *s) { | |
| 1992/0302 | Pte **sm, **endsm, *l; Page **pg, *entry; | |
| 1992/0303 | int type, nr; | |
| 1992/0302 | extern char *sname[]; | |
| 1991/0705 | ||
| 1992/0303 | ||
| 1991/0705 | if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */ return; | |
| 1992/0303 | if(s->steal) { | |
| 1991/0705 | qunlock(&s->lk); putseg(s); return; } | |
| 1992/0303 | if(!canflush(p, s)) { qunlock(&s->lk); putseg(s); return; } | |
| 1991/0705 | if(waserror()) { qunlock(&s->lk); putseg(s); return; } | |
| 1992/0302 | scavenge = 0; | |
| 1992/0303 | nr = 0; | |
| 1992/0302 | ||
| 1991/0705 | /* Pass through the pte tables looking for memory pages to swap out */ type = s->type&SG_TYPE; endsm = &s->map[SEGMAPSIZE]; | |
| 1992/0302 | for(sm = s->map; sm < endsm; sm++) { l = *sm; if(l == 0) continue; for(pg = l->first; pg < l->last; pg++) { | |
| 1992/0303 | nr++; | |
| 1992/0302 | entry = *pg; if(pagedout(entry)) continue; | |
| 1992/0303 | if(entry->modref & PG_REF) | |
| 1992/0302 | entry->modref &= ~PG_REF; else pagepte(type, s, pg); | |
| 1991/0705 | ||
| 1992/0302 | if(ioptr >= Maxpages) goto out; } } out: | |
| 1992/0303 | DBG("%s: %d: %5s s %d nr %d fr %d\n", p->text, p->pid, sname[type], scavenge, nr, palloc.freecount); | |
| 1991/0705 | poperror(); qunlock(&s->lk); putseg(s); wakeup(&palloc.r); } int canflush(Proc *p, Segment *s) { Proc *ep; int i; lock(s); if(s->ref == 1) { /* Easy if we are the only user */ s->ref++; unlock(s); return canpage(p); } s->ref++; unlock(s); /* Now we must do hardwork to ensure all processes which have tlb | |
| 1991/0706 | * entries for this segment will be flushed if we suceed in pageing it out | |
| 1991/0705 | */ p = proctab(0); ep = &p[conf.nproc]; | |
| 1992/0302 | while(p < ep) { if(p->state != Dead) { | |
| 1991/0705 | for(i = 0; i < NSEG; i++) if(p->seg[i] == s) if(!canpage(p)) return 0; | |
| 1992/0302 | } p++; } | |
| 1991/0705 | return 1; } int pagepte(int type, Segment *s, Page **pg) { ulong daddr; Page *outp; outp = *pg; switch(type) { case SG_TEXT: /* Revert to demand load */ putpage(outp); *pg = 0; | |
| 1992/0302 | scavenge++; | |
| 1991/0705 | break; | |
| 1992/0302 | ||
| 1991/0705 | case SG_DATA: case SG_BSS: case SG_STACK: case SG_SHARED: lockpage(outp); outp->ref++; uncachepage(outp); unlockpage(outp); daddr = newswap(); outp->daddr = daddr; /* Enter swap page into cache before segment is unlocked so that * a fault will cause a cache recovery rather than a pagein on a * partially written block. */ cachepage(outp, &swapimage); *pg = (Page*)(daddr|PG_ONSWAP); /* Add me to IO transaction list */ iolist[ioptr++] = outp; | |
| 1992/0302 | scavenge++; | |
| 1991/0705 | } return 1; } void executeio(void) { Page *out; int i, n; Chan *c; char *kaddr; KMap *k; c = swapimage.c; for(i = 0; i < ioptr; i++) { out = iolist[i]; | |
| 1992/0303 | ||
| 1991/0705 | k = kmap(out); kaddr = (char*)VA(k); qlock(&c->wrl); if(waserror()) panic("executeio: page out I/O error"); n = (*devtab[c->type].write)(c, kaddr, BY2PG, out->daddr); if(n != BY2PG) nexterror(); qunlock(&c->wrl); kunmap(k); poperror(); /* Free up the page after I/O */ lockpage(out); out->ref--; unlockpage(out); putpage(out); } ioptr = 0; } int needpages(void *p) { | |
| 1991/1115 | USED(p); | |
| 1992/0303 | return palloc.freecount < swapalloc.headroom; | |
| 1991/0705 | } void setswapchan(Chan *c) { if(swapimage.c) { if(swapalloc.free != conf.nswap) | |
| 1992/0114 | error(Einuse); | |
| 1991/0705 | close(swapimage.c); } incref(c); swapimage.c = c; } | |