| plan 9 kernel history: overview | file list | diff list |
1997/0516/port/swap.c (diff list | history)
| 1997/0516/sys/src/9/port/swap.c:1,339 – 1998/0403/sys/src/9/port/swap.c:1,340 (short | long | prev | next) | ||
|
Bug fix: require caller to setswapchan to incref the Chan.
rsc Fri Mar 4 12:44:25 2005 | ||
| 1991/0705 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1991/0705 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1991/0705 | ||
| 1995/0815 | static int canflush(Proc*, Segment*); static void executeio(void); static int needpages(void*); static void pageout(Proc*, Segment*); static void pagepte(int, Page**); static void pager(void*); | |
| 1991/0705 | enum { | |
| 1992/1209 | Maxpages = SEGMAXSIZE/BY2PG, /* Max # of pageouts per segment pass */ | |
| 1991/0705 | }; | |
| 1992/0910 | Image swapimage; static int swopen; | |
| 1993/0103 | static Page **iolist; | |
| 1992/0910 | static int ioptr; | |
| 1991/0705 | void swapinit(void) { | |
| 1992/0619 | swapalloc.swmap = xalloc(conf.nswap); | |
| 1991/0705 | swapalloc.top = &swapalloc.swmap[conf.nswap]; swapalloc.alloc = swapalloc.swmap; | |
| 1992/0912 | swapalloc.last = swapalloc.swmap; | |
| 1991/0705 | swapalloc.free = conf.nswap; | |
| 1993/0103 | iolist = xalloc(Maxpages*sizeof(Page*)); if(swapalloc.swmap == 0 || iolist == 0) panic("swapinit: not enough memory"); | |
| 1994/0817 | swapimage.notext = 1; | |
| 1991/0705 | } ulong newswap(void) { | |
| 1992/0912 | uchar *look; | |
| 1991/0705 | lock(&swapalloc); if(swapalloc.free == 0) panic("out of swap space"); | |
| 1992/0912 | look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last); | |
| 1992/0628 | if(look == 0) | |
| 1992/0912 | panic("inconsistent swap"); | |
| 1991/0705 | *look = 1; | |
| 1992/0912 | swapalloc.last = look; | |
| 1991/0928 | swapalloc.free--; | |
| 1991/0705 | unlock(&swapalloc); return (look-swapalloc.swmap) * BY2PG; } void putswap(Page *p) { | |
| 1992/0912 | uchar *idx; | |
| 1991/0705 | lock(&swapalloc); | |
| 1992/0912 | idx = &swapalloc.swmap[((ulong)p)/BY2PG]; | |
| 1992/0913 | if(--(*idx) == 0) { | |
| 1991/0705 | swapalloc.free++; | |
| 1992/0913 | if(idx < swapalloc.last) swapalloc.last = idx; } | |
| 1991/0705 | 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; } } | |
| 1995/0815 | static void | |
| 1991/0705 | pager(void *junk) { | |
| 1992/0805 | int i; | |
| 1993/1011 | Segment *s; Proc *p, *ep; | |
| 1991/0705 | ||
| 1992/0303 | if(waserror()) panic("pager: os error\n"); | |
| 1991/0705 | p = proctab(0); ep = &p[conf.nproc]; | |
| 1992/0303 | loop: | |
| 1993/0501 | up->psstate = "Idle"; | |
| 1992/0303 | sleep(&swapalloc.r, needpages, 0); | |
| 1992/0301 | ||
| 1993/0910 | while(needpages(junk)) { | |
| 1992/0303 | p++; | |
| 1992/0628 | if(p >= ep) | |
| 1992/0303 | p = proctab(0); | |
| 1991/0705 | ||
| 1993/1105 | if(p->state == Dead || p->kp) continue; | |
| 1992/0303 | if(swapimage.c) { for(i = 0; i < NSEG; i++) { if(!needpages(junk)) goto loop; | |
| 1992/0628 | ||
| 1992/0303 | if(s = p->seg[i]) { | |
| 1992/0805 | switch(s->type&SG_TYPE) { | |
| 1992/0304 | default: break; case SG_TEXT: | |
| 1992/0805 | pageout(p, s); break; | |
| 1992/0304 | case SG_DATA: case SG_BSS: case SG_STACK: case SG_SHARED: | |
| 1997/0516 | case SG_MAP: | |
| 1993/0501 | up->psstate = "Pageout"; | |
| 1992/0304 | pageout(p, s); | |
| 1992/0805 | if(ioptr != 0) { | |
| 1993/0501 | up->psstate = "I/O"; | |
| 1992/0805 | executeio(); } | |
| 1992/0304 | } | |
| 1992/0303 | } | |
| 1991/0705 | } } | |
| 1993/0910 | else { | |
| 1992/0725 | if(!cpuserver) freebroken(); /* can use the memory */ | |
| 1993/1123 | else killbig(); | |
| 1991/0705 | ||
| 1992/0303 | /* Emulate the old system if no swap channel */ print("no physical memory\n"); | |
| 1995/0319 | tsleep(&swapalloc.pause, return0, 0, 5000); | |
| 1993/1120 | wakeup(&palloc.r); | |
| 1992/0303 | } | |
| 1991/0705 | } | |
| 1992/0303 | goto loop; | |
| 1991/0705 | } | |
| 1995/0815 | static void | |
| 1991/0705 | pageout(Proc *p, Segment *s) { | |
| 1992/0805 | int type, i; Pte *l; | |
| 1992/0302 | Page **pg, *entry; | |
| 1991/0705 | if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */ return; | |
| 1992/0304 | if(s->steal) { /* Protected by /dev/proc */ | |
| 1991/0705 | qunlock(&s->lk); return; } | |
| 1992/0304 | if(!canflush(p, s)) { /* Able to invalidate all tlbs with references */ | |
| 1992/0303 | qunlock(&s->lk); putseg(s); return; } | |
| 1991/0705 | if(waserror()) { qunlock(&s->lk); putseg(s); return; } /* Pass through the pte tables looking for memory pages to swap out */ type = s->type&SG_TYPE; | |
| 1992/0805 | for(i = 0; i < SEGMAPSIZE; i++) { l = s->map[i]; | |
| 1992/0302 | if(l == 0) continue; for(pg = l->first; pg < l->last; pg++) { entry = *pg; if(pagedout(entry)) continue; | |
| 1992/0303 | ||
| 1992/0805 | if(entry->modref & PG_REF) { | |
| 1992/0302 | entry->modref &= ~PG_REF; | |
| 1992/0805 | continue; } | |
| 1991/0705 | ||
| 1992/0805 | pagepte(type, pg); | |
| 1992/0302 | if(ioptr >= Maxpages) goto out; } } out: | |
| 1991/0705 | poperror(); qunlock(&s->lk); putseg(s); } | |
| 1995/0815 | static int | |
| 1991/0705 | canflush(Proc *p, Segment *s) { int i; | |
| 1992/0805 | Proc *ep; | |
| 1991/0705 | 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 | |
| 1995/0815 | * entries for this segment will be flushed if we succeed in paging 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; } | |
| 1995/0815 | static void | |
| 1992/0711 | pagepte(int type, Page **pg) | |
| 1991/0705 | { ulong daddr; Page *outp; outp = *pg; switch(type) { | |
| 1994/0509 | case SG_TEXT: /* Revert to demand load */ | |
| 1991/0705 | putpage(outp); *pg = 0; break; | |
| 1992/0302 | ||
| 1991/0705 | case SG_DATA: case SG_BSS: case SG_STACK: case SG_SHARED: | |
| 1992/0307 | case SG_SHDATA: | |
| 1992/0628 | daddr = newswap(); | |
| 1992/0629 | cachedel(&swapimage, daddr); | |
| 1992/0625 | lock(outp); | |
| 1991/0705 | outp->ref++; uncachepage(outp); | |
| 1992/0625 | unlock(outp); | |
| 1991/0705 | /* 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. */ | |
| 1992/0628 | outp->daddr = daddr; | |
| 1991/0705 | cachepage(outp, &swapimage); *pg = (Page*)(daddr|PG_ONSWAP); /* Add me to IO transaction list */ iolist[ioptr++] = outp; } } | |
| 1995/0815 | static void | |
| 1991/0705 | 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]; k = kmap(out); kaddr = (char*)VA(k); if(waserror()) panic("executeio: page out I/O error"); | |
| 1997/0327 | n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr); | |
| 1991/0705 | if(n != BY2PG) nexterror(); kunmap(k); poperror(); /* Free up the page after I/O */ | |
| 1992/0625 | lock(out); | |
| 1991/0705 | out->ref--; | |
| 1992/0625 | unlock(out); | |
| 1991/0705 | putpage(out); } ioptr = 0; } | |
| 1995/0815 | static int | |
| 1995/0804 | needpages(void*) | |
| 1991/0705 | { | |
| 1993/1120 | return palloc.freecount < swapalloc.headroom; | |
| 1991/0705 | } void setswapchan(Chan *c) { if(swapimage.c) { | |
| 1998/0403 | if(swapalloc.free != conf.nswap){ cclose(c); | |
| 1992/0114 | error(Einuse); | |
| 1998/0403 | } | |
| 1997/0327 | cclose(swapimage.c); | |
| 1991/0705 | } | |