From a7cce8b741b0870b12232bc993b6733b17df3e64 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 8 Jan 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-01-08 --- port/devproc.c | 2 ++ port/fault.c | 47 ++++++++++++++++++++++++++++++++++------------- port/page.c | 13 +++++++++++-- port/portdat.h | 2 ++ port/portfns.h | 1 + port/proc.c | 2 ++ port/swap.c | 44 ++++++++++++++++++++++++++++++++++++-------- port/sysproc.c | 22 ++++++++++++++++++++++ 8 files changed, 110 insertions(+), 23 deletions(-) diff --git a/port/devproc.c b/port/devproc.c index ef5ff1d58bc28d9ab77b8502bd2b039bf782a3f6..19a1c066bf6464ccb1ae8380188ee78dfa638e19 100644 --- a/port/devproc.c +++ b/port/devproc.c @@ -975,6 +975,7 @@ txt2data(Proc *p, Segment *s) ps->flen = s->flen; ps->flushme = 1; + qlock(&p->seglock); for(i = 0; i < NSEG; i++) if(p->seg[i] == s) break; @@ -985,6 +986,7 @@ txt2data(Proc *p, Segment *s) putseg(s); qlock(&ps->lk); p->seg[i] = ps; + qunlock(&p->seglock); return ps; } diff --git a/port/fault.c b/port/fault.c index 99d4dcb88ed1796895ce9a4a0790fe002dd03b38..1efa3894dba4e0de796954087216a0c2312b58cf 100644 --- a/port/fault.c +++ b/port/fault.c @@ -51,6 +51,7 @@ int fixfault(Segment *s, ulong addr, int read, int doputmmu) { int type; + int ref; Pte **p, *etp; char buf[ERRLEN]; ulong va, mmuphys=0, soff; @@ -92,6 +93,11 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu) lkp = *pg; lock(lkp); + + /* uncache the current page (since we may be changing it) + * and, if a text page, put a duplicate back onto + * the free list + */ if(lkp->image) duppage(lkp); unlock(lkp); @@ -129,7 +135,11 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu) lkp = *pg; lock(lkp); - if(lkp->ref > 1) { + if(lkp->image == &swapimage && lkp->daddr) + ref = lkp->ref + swapcount(lkp->daddr); + else + ref = lkp->ref; + if(ref > 1) { unlock(lkp); new = newpage(0, &s, addr); if(s == 0) @@ -139,7 +149,8 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu) putpage(lkp); } else { - /* put a duplicate of a text page back onto + /* uncache the current page (since we may be changing it) + * and, if a text page, put a duplicate back onto * the free list */ if(lkp->image) @@ -181,7 +192,7 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu) void pio(Segment *s, ulong addr, ulong soff, Page **p) { - Page *new; + Page *new, *new2; KMap *k; Chan *c; int n, ask; @@ -197,7 +208,7 @@ pio(Segment *s, ulong addr, ulong soff, Page **p) else { daddr = swapaddr(loadrec); new = lookpage(&swapimage, daddr); - if(new) + if(new != nil) putswap(loadrec); } @@ -235,7 +246,8 @@ pio(Segment *s, ulong addr, ulong soff, Page **p) poperror(); kunmap(k); qlock(&s->lk); - if(*p == 0) { /* Someone may have got there first */ + /* race, we may have multiple simultaneous reads */ + if(*p == 0) { new->daddr = daddr; cachepage(new, s->image); *p = new; @@ -245,10 +257,21 @@ pio(Segment *s, ulong addr, ulong soff, Page **p) } else { /* This is paged out */ c = swapimage.c; + qlock(&swapimage.rdlock); /* mutex */ + + new2 = lookpage(&swapimage, daddr); + if(new2 != nil){ + putpage(new); + putswap(*p); + *p = new2; + qunlock(&swapimage.rdlock); + return; + } if(waserror()) { kunmap(k); putpage(new); + qunlock(&swapimage.rdlock); qlock(&s->lk); qunlock(&s->lk); faulterror("sys: page in I/O error"); @@ -262,14 +285,12 @@ pio(Segment *s, ulong addr, ulong soff, Page **p) kunmap(k); qlock(&s->lk); - if(pagedout(*p)) { - new->daddr = daddr; - cachepage(new, &swapimage); - putswap(*p); - *p = new; - } - else - putpage(new); + new->daddr = daddr; + putswap(*p); + cachepage(new, &swapimage); + *p = new; + + qunlock(&swapimage.rdlock); } if(s->flushme) diff --git a/port/page.c b/port/page.c index 847f70b64f3470cc7799491359c75559862ea5b0..f93a21dc6e4903edbfc1b3752dbe849b832ddafd 100644 --- a/port/page.c +++ b/port/page.c @@ -270,10 +270,16 @@ retry: if(retries++ > 10000) panic("duppage %d", retries); - /* No dup for swap/cache pages */ - if(p->ref == 0 || p->image == nil || p->image->notext) + /* don't dup pages with no image */ + if(p->ref == 0 || p->image == nil) return; + /* No dup for swap/cache pages but we still have to uncache */ + if(p->image->notext){ + uncachepage(p); + return; + } + /* * normal lock ordering is to call * lock(&palloc) before lock(p). @@ -390,6 +396,9 @@ cachedel(Image *i, ulong daddr) for(f = *l; f; f = f->hash) { if(f->image == i && f->daddr == daddr) { *l = f->hash; + putimage(f->image); + f->image = 0; + f->daddr = 0; break; } l = &f->hash; diff --git a/port/portdat.h b/port/portdat.h index bc56295b5f8ad21e0a06e863c26b964c8a5d21a2..a610d2db883a317e2cd623313c5fa152a91c1e12 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -326,6 +326,7 @@ struct Image Image *hash; /* Qid hash chains */ Image *next; /* Free list */ int notext; /* no file associated */ + QLock rdlock; /* mutex for reading from image */ }; struct Pte @@ -543,6 +544,7 @@ struct Proc int state; char *psstate; /* What /proc/#/status reports */ Segment *seg[NSEG]; + QLock seglock; /* locked whenever seg[] changes */ ulong pid; ulong noteid; /* Equivalent of note group */ diff --git a/port/portfns.h b/port/portfns.h index ecaaf088f3234f9a177856f490590ee270c51b34..b5d9373cb7f0a3987acee5171b0522ae2100f34d 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -293,6 +293,7 @@ int spllo(void); void splx(int); void splxpc(int); void srvrecover(Chan*, Chan*); +int swapcount(ulong); void swapinit(void); Block* trimblock(Block*, int, int); void tsleep(Rendez*, int (*)(void*), void*, int); diff --git a/port/proc.c b/port/proc.c index 5367e2a49547d7f18dee07c990229b2428c80cde..98399b6a66a0a480cf569f60f885e40ab98d4de8 100644 --- a/port/proc.c +++ b/port/proc.c @@ -796,6 +796,7 @@ pexit(char *exitstr, int freemem) if(!freemem) addbroken(up); + qlock(&up->seglock); es = &up->seg[NSEG]; for(s = up->seg; s < es; s++) { if(*s) { @@ -803,6 +804,7 @@ pexit(char *exitstr, int freemem) *s = 0; } } + qunlock(&up->seglock); lock(&up->exl); /* Prevent my children from leaving waits */ up->pid = 0; diff --git a/port/swap.c b/port/swap.c index a098d981955d3610a8f7b19525f21f583483750a..dd911d5ed241b9f100f73eb06f8b5bc70b761e71 100644 --- a/port/swap.c +++ b/port/swap.c @@ -60,6 +60,8 @@ putswap(Page *p) lock(&swapalloc); idx = &swapalloc.swmap[((ulong)p)/BY2PG]; if(--(*idx) == 0) { + if(swapalloc.swmap[((ulong)p)/BY2PG]==255) + panic("putswap"); swapalloc.free++; if(idx < swapalloc.last) swapalloc.last = idx; @@ -71,10 +73,18 @@ void dupswap(Page *p) { lock(&swapalloc); + if(swapalloc.swmap[((ulong)p)/BY2PG]==255) + panic("dupswap"); swapalloc.swmap[((ulong)p)/BY2PG]++; unlock(&swapalloc); } +int +swapcount(ulong daddr) +{ + return swapalloc.swmap[daddr/BY2PG]; +} + void kickpager(void) { @@ -106,17 +116,21 @@ loop: sleep(&swapalloc.r, needpages, 0); while(needpages(junk)) { - p++; - if(p >= ep) - p = proctab(0); - - if(p->state == Dead || p->kp) - continue; if(swapimage.c) { + p++; + if(p >= ep) + p = proctab(0); + + if(p->state == Dead || p->kp) + continue; + + qlock(&p->seglock); for(i = 0; i < NSEG; i++) { - if(!needpages(junk)) + if(!needpages(junk)){ + qunlock(&p->seglock); goto loop; + } if(s = p->seg[i]) { switch(s->type&SG_TYPE) { @@ -141,6 +155,7 @@ loop: } } } + qunlock(&p->seglock); } else { if(!cpuserver) @@ -264,12 +279,24 @@ pagepte(int type, Page **pg) case SG_SHARED: case SG_SHDATA: case SG_MAP: + /* if it's already on disk, we're done */ +#ifdef asdf + lock(outp); + if(outp->daddr != 0 && outp->image == &swapimage){ + dupswap((Page*)outp->daddr); + *pg = (Page*)(outp->daddr|PG_ONSWAP); + unlock(outp); + putpage(outp); + return; + } + unlock(outp); +#endif asdf + daddr = newswap(); cachedel(&swapimage, daddr); lock(outp); outp->ref++; uncachepage(outp); - unlock(outp); /* Enter swap page into cache before segment is unlocked so that * a fault will cause a cache recovery rather than a pagein on a @@ -278,6 +305,7 @@ pagepte(int type, Page **pg) outp->daddr = daddr; cachepage(outp, &swapimage); *pg = (Page*)(daddr|PG_ONSWAP); + unlock(outp); /* Add me to IO transaction list */ iolist[ioptr++] = outp; diff --git a/port/sysproc.c b/port/sysproc.c index 5e3a6d65ac570b9354b6bee2fe119c381ab9b7c7..0ebdf50cc9249b53fe221229ad44eea39beedc49 100644 --- a/port/sysproc.c +++ b/port/sysproc.c @@ -92,9 +92,16 @@ sysrfork(ulong *arg) /* Make a new set of memory segments */ n = flag & RFMEM; + qlock(&p->seglock); + if(waserror()){ + qunlock(&p->seglock); + nexterror(); + } for(i = 0; i < NSEG; i++) if(up->seg[i]) p->seg[i] = dupseg(up->seg, i, n); + qunlock(&p->seglock); + poperror(); /* File descriptors */ if(flag & (RFFDG|RFCFDG)) { @@ -304,6 +311,11 @@ sysexec(ulong *arg) if(spage > TSTKSIZ) error(Enovmem); + qlock(&up->seglock); + if(waserror()){ + qunlock(&up->seglock); + nexterror(); + } up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); /* @@ -383,6 +395,8 @@ sysexec(ulong *arg) s = up->seg[ESEG]; up->seg[ESEG] = 0; up->seg[SSEG] = s; + qunlock(&up->seglock); + poperror(); s->base = USTKTOP-USTKSIZE; s->top = USTKTOP; relocateseg(s, USTKTOP-TSTKTOP); @@ -587,6 +601,12 @@ syssegdetach(ulong *arg) ulong addr; Segment *s; + qlock(&up->seglock); + if(waserror()){ + qunlock(&up->seglock); + nexterror(); + } + s = 0; addr = arg[0]; for(i = 0; i < NSEG; i++) @@ -609,6 +629,8 @@ found: up->seg[i] = 0; qunlock(&s->lk); putseg(s); + qunlock(&up->seglock); + poperror(); /* Ensure we flush any entries from the lost segment */ flushmmu();