summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/9/pc/mmu.c26
-rw-r--r--sys/src/9/port/cache.c3
-rw-r--r--sys/src/9/port/chan.c28
-rw-r--r--sys/src/9/port/devaoe.c22
-rw-r--r--sys/src/9/port/devcons.c4
-rw-r--r--sys/src/9/port/devproc.c31
-rw-r--r--sys/src/9/port/fault.c104
-rw-r--r--sys/src/9/port/page.c383
-rw-r--r--sys/src/9/port/pgrp.c4
-rw-r--r--sys/src/9/port/portdat.h62
-rw-r--r--sys/src/9/port/portfns.h1
-rw-r--r--sys/src/9/port/proc.c15
-rw-r--r--sys/src/9/port/segment.c280
-rw-r--r--sys/src/9/port/swap.c243
-rw-r--r--sys/src/9/port/sysproc.c46
15 files changed, 559 insertions, 693 deletions
diff --git a/sys/src/9/pc/mmu.c b/sys/src/9/pc/mmu.c
index b91edf90e..4c3284646 100644
--- a/sys/src/9/pc/mmu.c
+++ b/sys/src/9/pc/mmu.c
@@ -303,7 +303,7 @@ mmuswitch(Proc* proc)
proc->newtlb = 0;
}
- if(proc->mmupdb){
+ if(proc->mmupdb != nil){
pdb = tmpmap(proc->mmupdb);
pdb[PDX(MACHADDR)] = m->pdb[PDX(MACHADDR)];
tmpunmap(pdb);
@@ -341,11 +341,11 @@ mmurelease(Proc* proc)
if(islo())
panic("mmurelease: islo");
taskswitch(PADDR(m->pdb), (ulong)m + BY2PG);
- if(proc->kmaptable){
+ if(proc->kmaptable != nil){
if(proc->mmupdb == nil)
panic("mmurelease: no mmupdb");
- if(--proc->kmaptable->ref)
- panic("mmurelease: kmap ref %d", proc->kmaptable->ref);
+ if(--proc->kmaptable->ref != 0)
+ panic("mmurelease: kmap ref %ld", proc->kmaptable->ref);
if(proc->nkmap)
panic("mmurelease: nkmap %d", proc->nkmap);
/*
@@ -361,23 +361,23 @@ mmurelease(Proc* proc)
* move kmaptable to free list.
*/
pagechainhead(proc->kmaptable);
- proc->kmaptable = 0;
+ proc->kmaptable = nil;
}
- if(proc->mmupdb){
+ if(proc->mmupdb != nil){
mmuptefree(proc);
mmupdbfree(proc, proc->mmupdb);
- proc->mmupdb = 0;
+ proc->mmupdb = nil;
}
- for(page = proc->mmufree; page; page = next){
+ for(page = proc->mmufree; page != nil; page = next){
next = page->next;
- if(--page->ref)
- panic("mmurelease: page->ref %d", page->ref);
+ if(--page->ref != 0)
+ panic("mmurelease: page->ref %ld", page->ref);
pagechainhead(page);
}
- if(proc->mmufree && palloc.r.p)
+ if(proc->mmufree != nil && palloc.r.p != nil)
wakeup(&palloc.r);
- proc->mmufree = 0;
- if(proc->ldt){
+ proc->mmufree = nil;
+ if(proc->ldt != nil){
free(proc->ldt);
proc->ldt = nil;
proc->nldt = 0;
diff --git a/sys/src/9/port/cache.c b/sys/src/9/port/cache.c
index d32d68ef9..22ba52fbc 100644
--- a/sys/src/9/port/cache.c
+++ b/sys/src/9/port/cache.c
@@ -55,7 +55,8 @@ struct Ecache
Extent* head;
};
-static Image fscache;
+Image fscache;
+
static Cache cache;
static Ecache ecache;
static int maxcache = MAXCACHE;
diff --git a/sys/src/9/port/chan.c b/sys/src/9/port/chan.c
index d49301201..23085cb0a 100644
--- a/sys/src/9/port/chan.c
+++ b/sys/src/9/port/chan.c
@@ -96,25 +96,27 @@ isdotdot(char *p)
long
incref(Ref *r)
{
- long x;
+ long old, new;
- lock(r);
- x = ++r->ref;
- unlock(r);
- return x;
+ do {
+ old = r->ref;
+ new = old+1;
+ } while(!cmpswap(&r->ref, old, new));
+ return new;
}
long
decref(Ref *r)
{
- long x;
-
- lock(r);
- x = --r->ref;
- unlock(r);
- if(x < 0)
- panic("decref pc=%#p", getcallerpc(&r));
- return x;
+ long old, new;
+
+ do {
+ old = r->ref;
+ if(old <= 0)
+ panic("decref pc=%#p", getcallerpc(&r));
+ new = old-1;
+ } while(!cmpswap(&r->ref, old, new));
+ return new;
}
/*
diff --git a/sys/src/9/port/devaoe.c b/sys/src/9/port/devaoe.c
index a583ed4f3..e1512a49c 100644
--- a/sys/src/9/port/devaoe.c
+++ b/sys/src/9/port/devaoe.c
@@ -954,7 +954,7 @@ aoegen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
devdir(c, q, "devlink", 0, eve, 0555, dp);
return 1;
}
- if(i >= units.ref)
+ if(i >= Maxunits || i >= units.ref)
return -1;
d = unit2dev(i);
if(s >= d->ndl)
@@ -1728,24 +1728,18 @@ newunit(void)
{
int x;
- lock(&units);
- if(units.ref == Maxunits)
+ x = incref(&units);
+ if(x >= Maxunits){
+ decref(&units);
x = -1;
- else
- x = units.ref++;
- unlock(&units);
+ }
return x;
}
static int
dropunit(void)
{
- int x;
-
- lock(&units);
- x = --units.ref;
- unlock(&units);
- return x;
+ return decref(&units);
}
/*
@@ -2064,9 +2058,7 @@ aoeidentify(Aoedev *d, ushort *id)
static void
newvers(Aoedev *d)
{
- lock(&drivevers);
- d->vers = drivevers.ref++;
- unlock(&drivevers);
+ d->vers = incref(&drivevers);
}
static int
diff --git a/sys/src/9/port/devcons.c b/sys/src/9/port/devcons.c
index 1e317e2b1..339845a1d 100644
--- a/sys/src/9/port/devcons.c
+++ b/sys/src/9/port/devcons.c
@@ -480,6 +480,8 @@ consread(Chan *c, void *buf, long n, vlong off)
int i, k, id;
vlong offset = off;
extern char configfile[];
+ extern Image fscache;
+ extern Image swapimage;
if(n <= 0)
return n;
@@ -611,7 +613,7 @@ consread(Chan *c, void *buf, long n, vlong off)
(uvlong)conf.npage*BY2PG,
(uvlong)BY2PG,
conf.npage-conf.upages,
- palloc.user-palloc.freecount, palloc.user,
+ palloc.user-palloc.freecount-fscache.pgref-swapimage.pgref, palloc.user,
conf.nswap-swapalloc.free, conf.nswap,
(uvlong)mainmem->cursize,
(uvlong)mainmem->maxsize,
diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c
index 6befe3e23..346da3c3a 100644
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -260,7 +260,7 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
break;
case Qprofile:
q = p->seg[TSEG];
- if(q && q->profile) {
+ if(q != nil && q->profile != nil) {
len = (q->top-q->base)>>LRESPROF;
len *= sizeof(*q->profile);
}
@@ -800,7 +800,7 @@ procread(Chan *c, void *va, long n, vlong off)
case Qprofile:
s = p->seg[TSEG];
- if(s == 0 || s->profile == 0)
+ if(s == nil || s->profile == nil)
error("profile is off");
i = (s->top-s->base)>>LRESPROF;
i *= sizeof(*s->profile);
@@ -904,9 +904,9 @@ procread(Chan *c, void *va, long n, vlong off)
}
for(i=0; i<NSEG; i++){
if(s = p->seg[i]){
- eqlock(&s->lk);
+ eqlock(s);
l += mcountseg(s);
- qunlock(&s->lk);
+ qunlock(s);
}
}
poperror();
@@ -1212,18 +1212,14 @@ proctext(Chan *c, Proc *p)
Segment *s;
s = p->seg[TSEG];
- if(s == 0)
+ if(s == nil)
error(Enonexist);
if(p->state==Dead)
error(Eprocdied);
- lock(s);
i = s->image;
- if(i == 0) {
- unlock(s);
+ if(i == nil)
error(Eprocdied);
- }
- unlock(s);
lock(i);
if(waserror()) {
@@ -1231,8 +1227,11 @@ proctext(Chan *c, Proc *p)
nexterror();
}
+ if(i->s != s)
+ error(Eprocdied);
+
tc = i->c;
- if(tc == 0)
+ if(tc == nil)
error(Eprocdied);
if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
@@ -1292,8 +1291,8 @@ procctlclosefiles(Proc *p, int all, int fd)
if(f == nil)
error(Eprocdied);
+ incref(f);
lock(f);
- f->ref++;
while(fd <= f->maxfd){
c = f->fd[fd];
if(c != nil){
@@ -1417,11 +1416,11 @@ procctlreq(Proc *p, char *va, int n)
s = p->seg[TSEG];
if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
error(Ebadctl);
- if(s->profile != 0)
+ if(s->profile != nil)
free(s->profile);
npc = (s->top-s->base)>>LRESPROF;
s->profile = malloc(npc*sizeof(*s->profile));
- if(s->profile == 0)
+ if(s->profile == nil)
error(Enomem);
break;
case CMstart:
@@ -1632,9 +1631,9 @@ txt2data(Proc *p, Segment *s)
if(i == NSEG)
panic("segment gone");
- qunlock(&s->lk);
+ qunlock(s);
putseg(s);
- qlock(&ps->lk);
+ qlock(ps);
p->seg[i] = ps;
qunlock(&p->seglock);
diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c
index fa836b641..54824e8ba 100644
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -28,14 +28,14 @@ fault(uintptr addr, int read)
for(;;) {
spllo();
- s = seg(up, addr, 1); /* leaves s->lk qlocked if seg != nil */
- if(s == 0) {
+ s = seg(up, addr, 1); /* leaves s locked if seg != nil */
+ if(s == nil) {
up->psstate = sps;
return -1;
}
if(!read && (s->type&SG_RONLY)) {
- qunlock(&s->lk);
+ qunlock(s);
up->psstate = sps;
return -1;
}
@@ -62,7 +62,7 @@ faulterror(char *s, Chan *c, int freemem)
{
char buf[ERRMAX];
- if(c && c->path){
+ if(c != nil && c->path != nil){
snprint(buf, sizeof buf, "%s accessing %s: %s", s, c->path->s, up->errstr);
s = buf;
}
@@ -82,13 +82,13 @@ fixfault(Segment *s, uintptr addr, int read, int doputmmu)
int type;
Pte **p, *etp;
uintptr soff, mmuphys=0;
- Page **pg, *lkp, *new;
+ Page **pg, *old, *new;
Page *(*fn)(Segment*, uintptr);
addr &= ~(BY2PG-1);
soff = addr-s->base;
p = &s->map[soff/PTEMAPMEM];
- if(*p == 0)
+ if(*p == nil)
*p = ptealloc();
etp = *p;
@@ -116,9 +116,9 @@ fixfault(Segment *s, uintptr addr, int read, int doputmmu)
case SG_BSS:
case SG_SHARED: /* Zero fill on demand */
case SG_STACK:
- if(*pg == 0) {
+ if(*pg == nil) {
new = newpage(1, &s, addr);
- if(s == 0)
+ if(s == nil)
return -1;
*pg = new;
}
@@ -139,30 +139,23 @@ fixfault(Segment *s, uintptr addr, int read, int doputmmu)
break;
}
- lkp = *pg;
- lock(lkp);
- if(lkp->ref == 0)
- panic("fault %#p ref == 0", lkp);
- if(lkp->ref == 1 && lkp->image == nil) {
- unlock(lkp);
- } else if(lkp->image == &swapimage && (lkp->ref + swapcount(lkp->daddr)) == 1) {
- uncachepage(lkp);
- unlock(lkp);
- } else {
- unlock(lkp);
+ old = *pg;
+ if(old->image == &swapimage && (old->ref + swapcount(old->daddr)) == 1)
+ uncachepage(old);
+ if(old->ref > 1 || old->image != nil) {
new = newpage(0, &s, addr);
- if(s == 0)
+ if(s == nil)
return -1;
*pg = new;
- copypage(lkp, *pg);
- putpage(lkp);
+ copypage(old, *pg);
+ putpage(old);
}
mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
(*pg)->modref = PG_MOD|PG_REF;
break;
case SG_PHYSICAL:
- if(*pg == 0) {
+ if(*pg == nil) {
fn = s->pseg->pgalloc;
if(fn)
*pg = (*fn)(s, addr);
@@ -181,7 +174,7 @@ fixfault(Segment *s, uintptr addr, int read, int doputmmu)
(*pg)->modref = PG_MOD|PG_REF;
break;
}
- qunlock(&s->lk);
+ qunlock(s);
if(doputmmu)
putmmu(addr, mmuphys, *pg);
@@ -202,7 +195,7 @@ pio(Segment *s, uintptr addr, uintptr soff, Page **p)
retry:
loadrec = *p;
- if(loadrec == 0) { /* from a text/data image */
+ if(loadrec == nil) { /* from a text/data image */
daddr = s->fstart+soff;
new = lookpage(s->image, daddr);
if(new != nil) {
@@ -229,7 +222,7 @@ retry:
c = swapimage.c;
ask = BY2PG;
}
- qunlock(&s->lk);
+ qunlock(s);
new = newpage(0, 0, addr);
k = kmap(new);
@@ -250,37 +243,42 @@ retry:
poperror();
kunmap(k);
- qlock(&s->lk);
- if(loadrec == 0) { /* This is demand load */
+ qlock(s);
+ if(loadrec == nil) { /* This is demand load */
/*
* race, another proc may have gotten here first while
- * s->lk was unlocked
+ * s was unlocked
*/
- if(*p == 0) {
- new->daddr = daddr;
- cachepage(new, s->image);
- *p = new;
+ if(*p == nil) {
+ /*
+ * check page cache again after i/o to reduce double caching
+ */
+ *p = lookpage(s->image, daddr);
+ if(*p == nil) {
+ incref(new);
+ new->daddr = daddr;
+ cachepage(new, s->image);
+ *p = new;
+ }
}
- else
- putpage(new);
}
else { /* This is paged out */
/*
* race, another proc may have gotten here first
* (and the pager may have run on that page) while
- * s->lk was unlocked
+ * s was unlocked
*/
- if(*p != loadrec){
- if(!pagedout(*p)){
+ if(*p != loadrec) {
+ if(!pagedout(*p)) {
/* another process did it for me */
- putpage(new);
goto done;
- } else if(*p) {
+ } else if(*p != nil) {
/* another process and the pager got in */
putpage(new);
goto retry;
} else {
/* another process segfreed the page */
+ incref(new);
k = kmap(new);
memset((void*)VA(k), 0, ask);
kunmap(k);
@@ -289,13 +287,14 @@ retry:
}
}
+ incref(new);
new->daddr = daddr;
cachepage(new, &swapimage);
*p = new;
putswap(loadrec);
}
-
done:
+ putpage(new);
if(s->flushme)
memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl));
}
@@ -311,7 +310,7 @@ okaddr(uintptr addr, ulong len, int write)
if((long)len >= 0) {
for(;;) {
s = seg(up, addr, 0);
- if(s == 0 || (write && (s->type&SG_RONLY)))
+ if(s == nil || (write && (s->type&SG_RONLY)))
break;
if(addr+len > s->top) {
@@ -369,21 +368,20 @@ seg(Proc *p, uintptr addr, int dolock)
et = &p->seg[NSEG];
for(s = p->seg; s < et; s++) {
- n = *s;
- if(n == 0)
+ if((n = *s) == nil)
continue;
if(addr >= n->base && addr < n->top) {
if(dolock == 0)
return n;
- qlock(&n->lk);
+ qlock(n);
if(addr >= n->base && addr < n->top)
return n;
- qunlock(&n->lk);
+ qunlock(n);
}
}
- return 0;
+ return nil;
}
extern void checkmmu(uintptr, uintptr);
@@ -402,22 +400,20 @@ checkpages(void)
checked = 0;
for(sp=up->seg, ep=&up->seg[NSEG]; sp<ep; sp++){
- s = *sp;
- if(s == nil)
+ if((s = *sp) == nil)
continue;
- qlock(&s->lk);
+ qlock(s);
for(addr=s->base; addr<s->top; addr+=BY2PG){
off = addr - s->base;
- p = s->map[off/PTEMAPMEM];
- if(p == 0)
+ if((p = s->map[off/PTEMAPMEM]) == nil)
continue;
pg = p->pages[(off&(PTEMAPMEM-1))/BY2PG];
- if(pg == 0 || pagedout(pg))
+ if(pagedout(pg))
continue;
checkmmu(addr, pg->pa);
checked++;
}
- qunlock(&s->lk);
+ qunlock(s);
}
print("%ld %s: checked %d page table entries\n", up->pid, up->text, checked);
}
diff --git a/sys/src/9/port/page.c b/sys/src/9/port/page.c
index 48e393d2b..f3397c4fa 100644
--- a/sys/src/9/port/page.c
+++ b/sys/src/9/port/page.c
@@ -5,9 +5,7 @@
#include "fns.h"
#include "../port/error.h"
-#define pghash(daddr) palloc.hash[(daddr>>PGSHIFT)&(PGHSIZE-1)]
-
-struct Palloc palloc;
+Palloc palloc;
void
pageinit(void)
@@ -31,24 +29,19 @@ pageinit(void)
}
color = 0;
- palloc.head = palloc.pages;
- p = palloc.head;
+ palloc.head = nil;
+ p = palloc.pages;
for(i=0; i<nelem(palloc.mem); i++){
pm = &palloc.mem[i];
for(j=0; j<pm->npage; j++){
memset(p, 0, sizeof *p);
- p->prev = p-1;
- p->next = p+1;
p->pa = pm->base+j*BY2PG;
p->color = color;
- palloc.freecount++;
color = (color+1)%NCOLOR;
+ pagechainhead(p);
p++;
}
}
- palloc.tail = p - 1;
- palloc.head->prev = 0;
- palloc.tail->next = 0;
palloc.user = p - palloc.pages;
u = palloc.user*BY2PG;
@@ -71,78 +64,100 @@ pageinit(void)
}
void
-pageunchain(Page *p)
+pagechainhead(Page *p)
{
- if(canlock(&palloc))
- panic("pageunchain (palloc %p)", &palloc);
- if(p->prev)
- p->prev->next = p->next;
- else
- palloc.head = p->next;
- if(p->next)
- p->next->prev = p->prev;
- else
- palloc.tail = p->prev;
- p->prev = p->next = nil;
- palloc.freecount--;
+ p->next = palloc.head;
+ palloc.head = p;
+ palloc.freecount++;
}
-void
-pagechaintail(Page *p)
+static void
+freepages(Page *head, Page *tail, int n)
{
- if(canlock(&palloc))
- panic("pagechaintail");
- if(palloc.tail) {
- p->prev = palloc.tail;
- palloc.tail->next = p;
- }
- else {
- palloc.head = p;
- p->prev = 0;
- }
- palloc.tail = p;
- p->next = 0;
- palloc.freecount++;
+ lock(&palloc);
+ tail->next = palloc.head;
+ palloc.head = head;
+ palloc.freecount += n;
+ if(palloc.r.p != nil)
+ wakeup(&palloc.r);
+ unlock(&palloc);
}
-void
-pagechainhead(Page *p)
+int
+pagereclaim(Image *i, int min)
{
- if(canlock(&palloc))
- panic("pagechainhead");
- if(palloc.head) {
- p->next = palloc.head;
- palloc.head->prev = p;
+ Page **h, **l, *p;
+ Page *fh, *ft;
+ int n;
+
+ lock(i);
+ if(i->pgref == 0){
+ unlock(i);
+ return 0;
}
- else {
- palloc.tail = p;
- p->next = 0;
+ incref(i);
+
+ n = 0;
+ fh = ft = nil;
+ for(h = i->pghash; h < &i->pghash[PGHSIZE]; h++){
+ if((p = *h) == nil)
+ continue;
+ for(l = h; p != nil; p = p->next){
+ if(p->ref == 0)
+ break;
+ l = &p->next;
+ }
+ if(p == nil)
+ continue;
+
+ *l = p->next;
+ p->next = nil;
+ p->image = nil;
+ p->daddr = ~0;
+ i->pgref--;
+ decref(i);
+
+ if(fh == nil)
+ fh = p;
+ else
+ ft->next = p;
+ ft = p;
+ if(++n >= min)
+ break;
}
- palloc.head = p;
- p->prev = 0;
- palloc.freecount++;
+ unlock(i);
+ putimage(i);
+
+ if(n > 0)
+ freepages(fh, ft, n);
+
+ return n;
+}
+
+int
+ispages(void*)
+{
+ return palloc.freecount >= swapalloc.highwater;
}
Page*
newpage(int clear, Segment **s, uintptr va)
{
- Page *p;
+ Page *p, **l;
KMap *k;
uchar ct;
- int i, hw, color;
+ int i, color;
- lock(&palloc);
color = getpgcolor(va);
- hw = swapalloc.highwater;
+ lock(&palloc);
for(;;) {
- if(palloc.freecount > hw)
+ if(palloc.freecount > swapalloc.highwater)
break;
if(up->kp && palloc.freecount > 0)
break;
-
unlock(&palloc);
- if(s)
- qunlock(&((*s)->lk));
+ if(s != nil)
+ qunlock(*s);
if(!waserror()){
eqlock(&palloc.pwait); /* Hold memory requesters here */
@@ -164,40 +179,40 @@ newpage(int clear, Segment **s, uintptr va)
* a page. Fault will call newpage again when it has
* reacquired the segment locks
*/
- if(s){
- *s = 0;
- return 0;
+ if(s != nil){
+ *s = nil;
+ return nil;
}
lock(&palloc);
}
/* First try for our colour */
- for(p = palloc.head; p; p = p->next)
+ l = &palloc.head;
+ for(p = *l; p != nil; p = p->next){
if(p->color == color)
break;
+ l = &p->next;
+ }
ct = PG_NOFLUSH;
- if(p == 0) {
- p = palloc.head;
+ if(p == nil) {
+ l = &palloc.head;
+ p = *l;
p->color = color;
ct = PG_NEWCOL;
}
- pageunchain(p);
-
- lock(p);
- if(p->ref != 0)
- panic("newpage: p->ref %d != 0", p->ref);
+ *l = p->next;
+ p->next = nil;
+ palloc.freecount--;
+ unlock(&palloc);
- uncachepage(p);
- p->ref++;
+ p->ref = 1;
p->va = va;
p->modref = 0;
for(i = 0; i < MAXMACH; i++)
p->cachectl[i] = ct;
- unlock(p);
- unlock(&palloc);
if(clear) {
k = kmap(p);
@@ -208,12 +223,6 @@ newpage(int clear, Segment **s, uintptr va)
return p;
}
-int
-ispages(void*)
-{
- return palloc.freecount >= swapalloc.highwater;
-}
-
void
putpage(Page *p)
{
@@ -221,29 +230,12 @@ putpage(Page *p)
putswap(p);
return;
}
-
- lock(&palloc);
- lock(p);
-
- if(p->ref == 0)
- panic("putpage");
-
- if(--p->ref > 0) {
- unlock(p);
- unlock(&palloc);
+ if(p->image != nil) {
+ decref(p);
return;
}
-
- if(p->image && p->image != &swapimage)
- pagechaintail(p);
- else
- pagechainhead(p);
-
- if(palloc.r.p != 0)
- wakeup(&palloc.r);
-
- unlock(p);
- unlock(&palloc);
+ if(decref(p) == 0)
+ freepages(p, p, 1);
}
Page*
@@ -253,19 +245,15 @@ auxpage(void)
lock(&palloc);
p = palloc.head;
- if(palloc.freecount < swapalloc.highwater) {
+ if(p == nil || palloc.freecount < swapalloc.highwater) {
unlock(&palloc);
- return 0;
+ return nil;
}
- pageunchain(p);
-
- lock(p);
- if(p->ref != 0)
- panic("auxpage");
- p->ref++;
- uncachepage(p);
- unlock(p);
+ palloc.head = p->next;
+ p->next = nil;
+ palloc.freecount--;
unlock(&palloc);
+ p->ref = 1;
return p;
}
@@ -283,115 +271,81 @@ copypage(Page *f, Page *t)
}
void
-uncachepage(Page *p) /* Always called with a locked page */
+cachepage(Page *p, Image *i)
{
- Page **l, *f;
+ Page **h;
+
+ lock(i);
+ p->image = i;
+ h = &PGHASH(i, p->daddr);
+ p->next = *h;
+ *h = p;
+ incref(i);
+ i->pgref++;
+ unlock(i);
+}
+
+void
+uncachepage(Page *p)
+{
+ Page **l, *x;
Image *i;
i = p->image;
- if(i == 0)
+ if(i == nil)
return;
- lock(&palloc.hashlock);
- l = &pghash(p->daddr);
- for(f = *l; f; f = f->hash) {
- if(f == p) {
- *l = p->hash;
- break;
+ lock(i);
+ if(p->image != i){
+ unlock(i);
+ return;
+ }
+ l = &PGHASH(i, p->daddr);
+ for(x = *l; x != nil; x = x->next) {
+ if(x == p){
+ *l = p->next;
+ p->next = nil;
+ p->image = nil;
+ p->daddr = ~0;
+ i->pgref--;
+ unlock(i);
+ putimage(i);
+ return;
}
- l = &f->hash;
+ l = &x->next;
}
- unlock(&palloc.hashlock);
- p->image = 0;
- p->daddr = 0;
-
- lock(i);
- i->pgref--;
unlock(i);
- putimage(i);
}
-void
-cachepage(Page *p, Image *i)
+Page*
+lookpage(Image *i, uintptr daddr)
{
- Page **l;
-
- /* If this ever happens it should be fixed by calling
- * uncachepage instead of panic. I think there is a race
- * with pio in which this can happen. Calling uncachepage is
- * correct - I just wanted to see if we got here.
- */
- if(p->image)
- panic("cachepage");
+ Page *p;
lock(i);
- i->ref++;
- i->pgref++;
+ for(p = PGHASH(i, daddr); p != nil; p = p->next) {
+ if(p->daddr == daddr) {
+ incref(p);
+ unlock(i);
+ return p;
+ }
+ }
unlock(i);
- lock(&palloc.hashlock);
- p->image = i;
- l = &pghash(p->daddr);
- p->hash = *l;
- *l = p;
- unlock(&palloc.hashlock);
+ return nil;
}
void
cachedel(Image *i, uintptr daddr)
{
- Page *f;
-
-retry:
- lock(&palloc.hashlock);
- for(f = pghash(daddr); f; f = f->hash) {
- if(f->image == i && f->daddr == daddr) {
- unlock(&palloc.hashlock);
-
- lock(f);
- if(f->image != i || f->daddr != daddr) {
- unlock(f);
- goto retry;
- }
- uncachepage(f);
- unlock(f);
+ Page *p;
- return;
- }
+ while((p = lookpage(i, daddr)) != nil){
+ uncachepage(p);
+ putpage(p);
}
- unlock(&palloc.hashlock);
}
-Page *
-lookpage(Image *i, uintptr daddr)
-{
- Page *f;
-
-retry:
- lock(&palloc.hashlock);
- for(f = pghash(daddr); f; f = f->hash) {
- if(f->image == i && f->daddr == daddr) {
- unlock(&palloc.hashlock);
-
- lock(&palloc);
- lock(f);
- if(f->image != i || f->daddr != daddr) {
- unlock(f);
- unlock(&palloc);
- goto retry;
- }
- if(++f->ref == 1)
- pageunchain(f);
- unlock(&palloc);
- unlock(f);
-
- return f;
- }
- }
- unlock(&palloc.hashlock);
-
- return 0;
-}
Pte*
ptecpy(Pte *old)
@@ -403,14 +357,11 @@ ptecpy(Pte *old)
dst = &new->pages[old->first-old->pages];
new->first = dst;
for(src = old->first; src <= old->last; src++, dst++)
- if(*src) {
+ if(*src != nil) {
if(onswap(*src))
dupswap(*src);
- else {
- lock(*src);
- (*src)->ref++;
- unlock(*src);
- }
+ else
+ incref(*src);
new->last = dst;
*dst = *src;
}
@@ -432,39 +383,35 @@ ptealloc(void)
void
freepte(Segment *s, Pte *p)
{
- int ref;
void (*fn)(Page*);
- Page *pt, **pg, **ptop;
+ Page **pg, **ptop;
switch(s->type&SG_TYPE) {
case SG_PHYSICAL:
fn = s->pseg->pgfree;
ptop = &p->pages[PTEPERTAB];
- if(fn) {
+ if(fn != nil) {
for(pg = p->pages; pg < ptop; pg++) {
- if(*pg == 0)
+ if(*pg == nil)
continue;
(*fn)(*pg);
- *pg = 0;
+ *pg = nil;
}
break;
}
for(pg = p->pages; pg < ptop; pg++) {
- pt = *pg;
- if(pt == 0)
- continue;
- lock(pt);
- ref = --pt->ref;
- unlock(pt);
- if(ref == 0)
- free(pt);
+ if(*pg != nil) {
+ if(decref(*pg) == 0)
+ free(*pg);
+ *pg = nil;
+ }
}
break;
default:
for(pg = p->first; pg <= p->last; pg++)
- if(*pg) {
+ if(*pg != nil) {
putpage(*pg);
- *pg = 0;
+ *pg = nil;
}
}
free(p);
@@ -503,7 +450,7 @@ checkpagerefs(void)
nwrong = 0;
for(i=0; i<np; i++){
if(palloc.pages[i].ref != ref[i]){
- iprint("page %#p ref %d actual %lud\n",
+ iprint("page %#p ref %ld actual %lud\n",
palloc.pages[i].pa, palloc.pages[i].ref, ref[i]);
ref[i] = 1;
nwrong++;
diff --git a/sys/src/9/port/pgrp.c b/sys/src/9/port/pgrp.c
index 8fb3e1fa0..eb65c8adf 100644
--- a/sys/src/9/port/pgrp.c
+++ b/sys/src/9/port/pgrp.c
@@ -148,10 +148,8 @@ pgrpcpy(Pgrp *to, Pgrp *from)
/*
* Allocate mount ids in the same sequence as the parent group
*/
- lock(&mountid);
for(m = order; m; m = m->order)
- m->copy->mountid = mountid.ref++;
- unlock(&mountid);
+ m->copy->mountid = incref(&mountid);
wunlock(&from->ns);
}
diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h
index 1d427cfc6..58c82c6a8 100644
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -60,7 +60,6 @@ typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*);
struct Ref
{
- Lock;
long ref;
};
@@ -151,7 +150,8 @@ struct Block
struct Chan
{
- Ref; /* the Lock in this Ref is also Chan's lock */
+ Ref;
+ Lock;
Chan* next; /* allocation */
Chan* link;
vlong offset; /* in fd */
@@ -311,19 +311,16 @@ enum
struct Page
{
- Lock;
+ Ref;
+ Page *next; /* Free list or Hash chains */
uintptr pa; /* Physical address in memory */
uintptr va; /* Virtual address for user */
uintptr daddr; /* Disc address on swap */
- ulong gen; /* Generation counter for swap */
- ushort ref; /* Reference count */
+ Image *image; /* Associated text or swap image */
+ ushort refage; /* Swap reference age */
char modref; /* Simulated modify/reference bits */
char color; /* Cache coloring */
char cachectl[MAXMACH]; /* Cache flushing control for putmmu */
- Image *image; /* Associated text or swap image */
- Page *next; /* Lru free list */
- Page *prev;
- Page *hash; /* Image hash chains */
};
struct Swapalloc
@@ -340,20 +337,6 @@ struct Swapalloc
ulong xref; /* Ref count for all map refs >= 255 */
}swapalloc;
-struct Image
-{
- Ref;
- long pgref; /* number of cached pages (pgref <= ref) */
- Chan *c; /* channel to text file, nil when not used */
- Qid qid; /* Qid for page cache coherence */
- ulong dev; /* Device id of owning channel */
- ushort type; /* Device type of owning channel */
- Segment *s; /* TEXT segment for image if running */
- Image *hash; /* Qid hash chains */
- Image *next; /* Free list */
- char notext; /* no file associated */
-};
-
struct Pte
{
Page *pages[PTEPERTAB]; /* Page map for this chunk of pte */
@@ -405,7 +388,7 @@ struct Sema
struct Segment
{
Ref;
- QLock lk;
+ QLock;
ushort steal; /* Page stealer lock */
ushort type; /* segment type */
uintptr base; /* virtual base */
@@ -436,10 +419,29 @@ enum
};
#define REND(p,s) ((p)->rendhash[(s)&((1<<RENDLOG)-1)])
#define MOUNTH(p,qid) ((p)->mnthash[(qid).path&((1<<MNTLOG)-1)])
+#define PGHASH(i,daddr) ((i)->pghash[((daddr)>>PGSHIFT)&(PGHSIZE-1)])
+
+struct Image
+{
+ Ref;
+ Lock;
+ Chan *c; /* channel to text file, nil when not used */
+ Qid qid; /* Qid for page cache coherence */
+ ulong dev; /* Device id of owning channel */
+ ushort type; /* Device type of owning channel */
+ char notext; /* no file associated */
+ Segment *s; /* TEXT segment for image if running */
+ Image *hash; /* Qid hash chains */
+ Image *next; /* Free list */
+ long pgref; /* number of cached pages (pgref <= ref) */
+ Page *pghash[PGHSIZE]; /* page cache */
+};
+
struct Pgrp
{
- Ref; /* also used as a lock when mounting */
+ Ref;
+ Lock;
int noattach;
ulong pgrpid;
QLock debug; /* single access via devproc.c */
@@ -449,7 +451,8 @@ struct Pgrp
struct Rgrp
{
- Ref; /* the Ref's lock is also the Rgrp's lock */
+ Ref;
+ Lock;
Proc *rendhash[RENDHASH]; /* Rendezvous tag hash */
};
@@ -476,6 +479,7 @@ struct Evalue
struct Fgrp
{
Ref;
+ Lock;
Chan **fd;
int nfd; /* number allocated */
int maxfd; /* highest fd in use */
@@ -497,13 +501,10 @@ struct Palloc
{
Lock;
Pallocmem mem[4];
- Page *head; /* most recently used */
- Page *tail; /* least recently used */
+ Page *head; /* freelist head */
ulong freecount; /* how many pages on free list now */
Page *pages; /* array of all pages */
ulong user; /* how many user pages */
- Page *hash[PGHSIZE];
- Lock hashlock;
Rendez r; /* Sleep for free mem */
QLock pwait; /* Queue of procs waiting for memory */
};
@@ -772,6 +773,7 @@ extern Palloc palloc;
extern Queue* serialoq;
extern char* statename[];
extern Image swapimage;
+extern Image fscache;
extern char* sysname;
extern uint qiomaxatomic;
extern char* sysctab[];
diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h
index a3cb639ac..626ec3eab 100644
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -202,7 +202,6 @@ int okaddr(uintptr, ulong, int);
int openmode(ulong);
Block* packblock(Block*);
Block* padblock(Block*, int);
-void pageunchain(Page*);
void pagechainhead(Page*);
void pageinit(void);
ulong pagenumber(Page*);
diff --git a/sys/src/9/port/proc.c b/sys/src/9/port/proc.c
index b01ff6129..bd787572b 100644
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -1350,13 +1350,12 @@ procflushseg(Segment *s)
return;
/*
- * wait for all processors to take a clock interrupt
+ * wait for all other processors to take a clock interrupt
* and flush their mmu's
*/
for(nm = 0; nm < conf.nmach; nm++)
- if(MACHP(nm) != m)
- while(MACHP(nm)->flushmmu)
- sched();
+ while(m->machno != nm && MACHP(nm)->flushmmu)
+ sched();
}
void
@@ -1514,10 +1513,10 @@ killbig(char *why)
l = 0;
for(i=1; i<NSEG; i++) {
s = p->seg[i];
- if(s == 0 || !canqlock(&s->lk))
+ if(s == nil || !canqlock(s))
continue;
l += (ulong)mcountseg(s);
- qunlock(&s->lk);
+ qunlock(s);
}
qunlock(&p->seglock);
if(l > max && ((p->procmode&0222) || strcmp(eve, p->user)!=0)) {
@@ -1537,9 +1536,9 @@ killbig(char *why)
kp->procctl = Proc_exitbig;
for(i = 0; i < NSEG; i++) {
s = kp->seg[i];
- if(s != 0 && canqlock(&s->lk)) {
+ if(s != nil && canqlock(s)) {
mfreeseg(s, s->base, (s->top - s->base)/BY2PG);
- qunlock(&s->lk);
+ qunlock(s);
}
}
qunlock(&kp->seglock);
diff --git a/sys/src/9/port/segment.c b/sys/src/9/port/segment.c
index cc813df62..f876e2462 100644
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -5,9 +5,7 @@
#include "fns.h"
#include "../port/error.h"
-static void imagereclaim(void);
-
-#include "io.h"
+int imagereclaim(int);
/*
* Attachable segment types
@@ -25,6 +23,7 @@ static Lock physseglock;
static struct Imagealloc
{
Lock;
+ Image *list;
Image *free;
Image *hash[IHASHSIZE];
QLock ireclaim; /* mutex on reclaiming free images */
@@ -37,13 +36,14 @@ initseg(void)
{
Image *i, *ie;
- imagealloc.free = xalloc(conf.nimage*sizeof(Image));
- if(imagealloc.free == nil)
+ imagealloc.list = xalloc(conf.nimage*sizeof(Image));
+ if(imagealloc.list == nil)
panic("initseg: no memory for Image");
- ie = &imagealloc.free[conf.nimage-1];
- for(i = imagealloc.free; i < ie; i++)
+ ie = &imagealloc.list[conf.nimage-1];
+ for(i = imagealloc.list; i < ie; i++)
i->next = i+1;
- i->next = 0;
+ i->next = nil;
+ imagealloc.free = imagealloc.list;
}
Segment *
@@ -55,7 +55,9 @@ newseg(int type, uintptr base, ulong size)
if(size > (SEGMAPSIZE*PTEPERTAB))
error(Enovmem);
- s = smalloc(sizeof(Segment));
+ s = malloc(sizeof(Segment));
+ if(s == nil)
+ error(Enomem);
s->ref = 1;
s->type = type;
s->base = base;
@@ -66,7 +68,11 @@ newseg(int type, uintptr base, ulong size)
mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB;
if(mapsize > nelem(s->ssegmap)){
- s->map = smalloc(mapsize*sizeof(Pte*));
+ s->map = malloc(mapsize*sizeof(Pte*));
+ if(s->map == nil){
+ free(s);
+ error(Enomem);
+ }
s->mapsize = mapsize;
}
else{
@@ -83,41 +89,33 @@ putseg(Segment *s)
Pte **pp, **emap;
Image *i;
- if(s == 0)
+ if(s == nil)
return;
i = s->image;
- if(i != 0) {
+ if(i != nil) {
lock(i);
- lock(s);
- if(i->s == s && s->ref == 1)
- i->s = 0;
+ if(decref(s) != 0){
+ unlock(i);
+ return;
+ }
+ if(i->s == s)
+ i->s = nil;
unlock(i);
- }
- else
- lock(s);
-
- s->ref--;
- if(s->ref != 0) {
- unlock(s);
- return;
- }
- unlock(s);
-
- qlock(&s->lk);
- if(i)
putimage(i);
+ } else if(decref(s) != 0)
+ return;
emap = &s->map[s->mapsize];
for(pp = s->map; pp < emap; pp++)
- if(*pp)
+ if(*pp != nil)
freepte(s, *pp);
- qunlock(&s->lk);
if(s->map != s->ssegmap)
free(s->map);
- if(s->profile != 0)
+ if(s->profile != nil)
free(s->profile);
+
free(s);
}
@@ -129,11 +127,10 @@ relocateseg(Segment *s, uintptr offset)
endpte = &s->map[s->mapsize];
for(p = s->map; p < endpte; p++) {
- if(*p == 0)
+ if((pte = *p) == nil)
continue;
- pte = *p;
for(pg = pte->first; pg <= pte->last; pg++) {
- if(x = *pg)
+ if((x = *pg) != nil)
x->va += offset;
}
}
@@ -149,9 +146,9 @@ dupseg(Segment **seg, int segno, int share)
SET(n);
s = seg[segno];
- qlock(&s->lk);
+ qlock(s);
if(waserror()){
- qunlock(&s->lk);
+ qunlock(s);
nexterror();
}
switch(s->type&SG_TYPE) {
@@ -174,7 +171,7 @@ dupseg(Segment **seg, int segno, int share)
if(segno == TSEG){
n = data2txt(s);
poperror();
- qunlock(&s->lk);
+ qunlock(s);
return n;
}
@@ -190,20 +187,20 @@ dupseg(Segment **seg, int segno, int share)
}
size = s->mapsize;
for(i = 0; i < size; i++)
- if(pte = s->map[i])
+ if((pte = s->map[i]) != nil)
n->map[i] = ptecpy(pte);
n->flushme = s->flushme;
if(s->ref > 1)
procflushseg(s);
poperror();
- qunlock(&s->lk);
+ qunlock(s);
return n;
sameseg:
incref(s);
poperror();
- qunlock(&s->lk);
+ qunlock(s);
return s;
}
@@ -219,7 +216,7 @@ segpage(Segment *s, Page *p)
off = p->va - s->base;
pte = &s->map[off/PTEMAPMEM];
- if(*pte == 0)
+ if(*pte == nil)
*pte = ptealloc();
pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];
@@ -250,14 +247,11 @@ attachimage(int type, Chan *c, uintptr base, ulong len)
}
}
- /*
- * imagereclaim dumps pages from the free list which are cached by image
- * structures. This should free some image structures.
- */
- while(!(i = imagealloc.free)) {
+ /* dump pages of inactive images to free image structures */
+ while((i = imagealloc.free) == nil) {
unlock(&imagealloc);
- imagereclaim();
- if(!imagealloc.free){
+ imagereclaim(1000);
+ if(imagealloc.free == nil){
freebroken(); /* can use the memory */
resrcwait("no image after reclaim");
}
@@ -276,15 +270,15 @@ attachimage(int type, Chan *c, uintptr base, ulong len)
*l = i;
found:
+ unlock(&imagealloc);
if(i->c == nil){
i->c = c;
c->flag &= ~CCACHE;
incref(c);
}
- unlock(&imagealloc);
- if(i->s == 0) {
- i->ref++;
+ if(i->s == nil) {
+ incref(i);
if(waserror()) {
unlock(i);
putimage(i);
@@ -300,55 +294,38 @@ found:
return i;
}
-static struct {
- int calls; /* times imagereclaim was called */
- int loops; /* times the main loop was run */
- uvlong ticks; /* total time in the main loop */
- uvlong maxt; /* longest time in main loop */
-} irstats;
+extern int pagereclaim(Image*, int); /* page.c */
-static void
-imagereclaim(void)
+int
+imagereclaim(int min)
{
- int n;
- Page *p, *x;
- uvlong ticks;
+ static Image *i, *ie;
+ int j, n;
- irstats.calls++;
- /* Somebody is already cleaning the page cache */
- if(!canqlock(&imagealloc.ireclaim))
- return;
-
- lock(&palloc);
- ticks = fastticks(nil);
+ eqlock(&imagealloc.ireclaim);
+ if(i == nil){
+ i = imagealloc.list;
+ ie = &imagealloc.list[conf.nimage];
+ }
n = 0;
- /*
- * All the pages with images backing them are at the
- * end of the list (see putpage) so start there and work
- * backward.
- */
- for(p = palloc.tail; p && p->image && (n<1000 || !imagealloc.free); p = x) {
- x = p->prev;
- if(p->ref == 0 && canlock(p)) {
- if(p->ref == 0 && p->image && !p->image->notext) {
- n++;
- uncachepage(p);
-
- /* move to head to maintain the invariant above */
- pageunchain(p);
- pagechainhead(p);
- }
- unlock(p);
+ for(j = 0; j < conf.nimage; j++, i++){
+ if(i >= ie)
+ i = imagealloc.list;
+ if(i->ref == 0)
+ continue;
+ /*
+ * if there are no free image structures, only
+ * reclaim pages from inactive images.
+ */
+ if(imagealloc.free != nil || i->ref == i->pgref){
+ n += pagereclaim(i, min - n);
+ if(n >= min)
+ break;
}
}
- ticks = fastticks(nil) - ticks;
- unlock(&palloc);
- irstats.loops++;
- irstats.ticks += ticks;
- if(ticks > irstats.maxt)
- irstats.maxt = ticks;
- //print("T%llud+", ticks);
qunlock(&imagealloc.ireclaim);
+
+ return n;
}
void
@@ -356,28 +333,31 @@ putimage(Image *i)
{
Image *f, **l;
Chan *c;
+ int r;
- if(i->notext)
+ if(i->notext){
+ decref(i);
return;
+ }
c = nil;
lock(i);
- if(--i->ref == i->pgref){
+ r = decref(i);
+ if(r == i->pgref){
/*
* all remaining references to this image are from the
- * page cache now. close the channel as we can reattach
- * the chan on attachimage()
+ * page cache, so close the chan.
*/
c = i->c;
i->c = nil;
}
- if(i->ref == 0){
+ if(r == 0){
l = &ihash(i->qid.path);
mkqid(&i->qid, ~0, ~0, QTFILE);
unlock(i);
lock(&imagealloc);
- for(f = *l; f; f = f->hash) {
+ for(f = *l; f != nil; f = f->hash) {
if(f == i) {
*l = i->hash;
break;
@@ -389,7 +369,7 @@ putimage(Image *i)
unlock(&imagealloc);
} else
unlock(i);
- if(c)
+ if(c != nil)
ccloseq(c); /* does not block */
}
@@ -403,18 +383,18 @@ ibrk(uintptr addr, int seg)
Pte **map;
s = up->seg[seg];
- if(s == 0)
+ if(s == nil)
error(Ebadarg);
if(addr == 0)
return s->base;
- qlock(&s->lk);
+ qlock(s);
/* We may start with the bss overlapping the data */
if(addr < s->base) {
- if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) {
- qunlock(&s->lk);
+ if(seg != BSEG || up->seg[DSEG] == nil || addr < up->seg[DSEG]->base) {
+ qunlock(s);
error(Enovmem);
}
addr = s->base;
@@ -429,29 +409,29 @@ ibrk(uintptr addr, int seg)
* already by another proc and is past the validaddr stage.
*/
if(s->ref > 1){
- qunlock(&s->lk);
+ qunlock(s);
error(Einuse);
}
mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
s->top = newtop;
s->size = newsize;
- qunlock(&s->lk);
+ qunlock(s);
flushmmu();
return 0;
}
for(i = 0; i < NSEG; i++) {
ns = up->seg[i];
- if(ns == 0 || ns == s)
+ if(ns == nil || ns == s)
continue;
if(newtop >= ns->base && newtop < ns->top) {
- qunlock(&s->lk);
+ qunlock(s);
error(Esoverlap);
}
}
if(newsize > (SEGMAPSIZE*PTEPERTAB)) {
- qunlock(&s->lk);
+ qunlock(s);
error(Enovmem);
}
mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB;
@@ -466,33 +446,34 @@ ibrk(uintptr addr, int seg)
s->top = newtop;
s->size = newsize;
- qunlock(&s->lk);
+ qunlock(s);
return 0;
}
/*
- * called with s->lk locked
+ * called with s locked
*/
int
mcountseg(Segment *s)
{
int i, j, pages;
- Page **map;
+ Page *pg;
pages = 0;
for(i = 0; i < s->mapsize; i++){
- if(s->map[i] == 0)
+ if(s->map[i] == nil)
continue;
- map = s->map[i]->pages;
- for(j = 0; j < PTEPERTAB; j++)
- if(map[j])
+ for(j = 0; j < PTEPERTAB; j++){
+ pg = s->map[i]->pages[j];
+ if(!pagedout(pg))
pages++;
+ }
}
return pages;
}
/*
- * called with s->lk locked
+ * called with s locked
*/
void
mfreeseg(Segment *s, uintptr start, int pages)
@@ -500,59 +481,39 @@ mfreeseg(Segment *s, uintptr start, int pages)
int i, j, size;
uintptr soff;
Page *pg;
- Page *list;
+
+ /*
+ * We want to zero s->map[i]->page[j] and putpage(pg),
+ * but we have to make sure other processors flush the
+ * entry from their TLBs before the page is freed.
+ */
+ if(s->ref > 1)
+ procflushseg(s);
soff = start-s->base;
j = (soff&(PTEMAPMEM-1))/BY2PG;
size = s->mapsize;
- list = nil;
for(i = soff/PTEMAPMEM; i < size; i++) {
if(pages <= 0)
- break;
- if(s->map[i] == 0) {
+ return;
+ if(s->map[i] == nil) {
pages -= PTEPERTAB-j;
j = 0;
continue;
}
while(j < PTEPERTAB) {
pg = s->map[i]->pages[j];
- /*
- * We want to zero s->map[i]->page[j] and putpage(pg),
- * but we have to make sure other processors flush the
- * entry from their TLBs before the page is freed.
- * We construct a list of the pages to be freed, zero
- * the entries, then (below) call procflushseg, and call
- * putpage on the whole list.
- *
- * Swapped-out pages don't appear in TLBs, so it's okay
- * to putswap those pages before procflushseg.
- */
- if(pg){
- if(onswap(pg))
- putswap(pg);
- else{
- pg->next = list;
- list = pg;
- }
- s->map[i]->pages[j] = 0;
+ if(pg != nil){
+ s->map[i]->pages[j] = nil;
+ putpage(pg);
}
if(--pages == 0)
- goto out;
+ return;
j++;
}
j = 0;
}
-out:
- /* flush this seg in all other processes */
- if(s->ref > 1)
- procflushseg(s);
-
- /* free the pages */
- for(pg = list; pg != nil; pg = list){
- list = list->next;
- putpage(pg);
- }
}
Segment*
@@ -565,7 +526,7 @@ isoverlap(Proc *p, uintptr va, uintptr len)
newtop = va+len;
for(i = 0; i < NSEG; i++) {
ns = p->seg[i];
- if(ns == 0)
+ if(ns == nil)
continue;
if((newtop > ns->base && newtop <= ns->top) ||
(va >= ns->base && va < ns->top))
@@ -594,7 +555,6 @@ addphysseg(Physseg* new)
unlock(&physseglock);
return -1;
}
-
*ps = *new;
unlock(&physseglock);
@@ -700,13 +660,13 @@ found:
void
pteflush(Pte *pte, int s, int e)
{
+ Page *pg;
int i;
- Page *p;
for(i = s; i < e; i++) {
- p = pte->pages[i];
- if(pagedout(p) == 0)
- memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl));
+ pg = pte->pages[i];
+ if(!pagedout(pg))
+ memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
}
}
@@ -741,7 +701,7 @@ syssegflush(va_list list)
pe = PGROUND(pe);
}
if(pe == ps) {
- qunlock(&s->lk);
+ qunlock(s);
error(Ebadarg);
}
@@ -755,7 +715,7 @@ syssegflush(va_list list)
if(len > 0 && addr < s->top)
goto more;
- qunlock(&s->lk);
+ qunlock(s);
}
flushmmu();
return 0;
@@ -767,7 +727,7 @@ segclock(uintptr pc)
Segment *s;
s = up->seg[TSEG];
- if(s == 0 || s->profile == 0)
+ if(s == nil || s->profile == nil)
return;
s->profile[0] += TK2MS(1);
diff --git a/sys/src/9/port/swap.c b/sys/src/9/port/swap.c
index c51417520..ff2694f25 100644
--- a/sys/src/9/port/swap.c
+++ b/sys/src/9/port/swap.c
@@ -18,19 +18,7 @@ static int swopen;
static Page **iolist;
static int ioptr;
-static ulong genage, genclock, gencount;
-static uvlong gensum;
-
-static void
-gentick(void)
-{
- genclock++;
- if(gencount)
- genage = gensum / gencount;
- else
- genage = 0;
- gensum = gencount = 0;
-}
+static ushort ageclock;
void
swapinit(void)
@@ -59,13 +47,10 @@ newswap(void)
unlock(&swapalloc);
return ~0;
}
-
look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
- if(look == 0)
- panic("inconsistent swap");
-
+ if(look == nil)
+ look = memchr(swapalloc.swmap, 0, swapalloc.last-swapalloc.swmap);
*look = 2; /* ref for pte + io transaction */
-
swapalloc.last = look;
swapalloc.free--;
unlock(&swapalloc);
@@ -91,17 +76,12 @@ putswap(Page *p)
if(*idx == 255) {
*idx = 0;
swapalloc.free++;
- if(idx < swapalloc.last)
- swapalloc.last = idx;
}
}
}
} else {
- if(--(*idx) == 0) {
+ if(--(*idx) == 0)
swapalloc.free++;
- if(idx < swapalloc.last)
- swapalloc.last = idx;
- }
}
unlock(&swapalloc);
}
@@ -131,18 +111,40 @@ swapcount(uintptr daddr)
void
kickpager(void)
{
- static int started;
+ static Ref started;
- if(started)
+ if(started.ref || incref(&started) != 1)
wakeup(&swapalloc.r);
- else {
+ else
kproc("pager", pager, 0);
- started = 1;
+}
+
+extern int pagereclaim(Image*,int); /* page.c */
+extern int imagereclaim(int); /* segment.c */
+
+static int
+reclaim(void)
+{
+ int n;
+
+ for(;;){
+ if((n = pagereclaim(&fscache, 1000)) > 0) {
+ if(0) print("reclaim: %d fscache\n", n);
+ } else if((n = pagereclaim(&swapimage, 1000)) > 0) {
+ if(0) print("reclaim: %d swap\n", n);
+ } else if((n = imagereclaim(1000)) > 0) {
+ if(0) print("reclaim: %d image\n", n);
+ }
+ if(!needpages(nil))
+ return 1; /* have pages, done */
+ if(n == 0)
+ return 0; /* didnt reclaim, need to swap */
+ sched();
}
}
static void
-pager(void *junk)
+pager(void*)
{
int i;
Segment *s;
@@ -153,86 +155,86 @@ pager(void *junk)
while(waserror())
;
-loop:
- up->psstate = "Idle";
- wakeup(&palloc.r);
- sleep(&swapalloc.r, needpages, 0);
-
- while(needpages(junk)) {
- if(swapimage.c && swapalloc.free) {
- p++;
- if(p >= ep){
- p = proctab(0);
- gentick();
- }
- if(p->state == Dead || p->noswap)
- continue;
+ for(;;){
+ up->psstate = "Reclaim";
+ if(reclaim()){
+ up->psstate = "Idle";
+ wakeup(&palloc.r);
+ sleep(&swapalloc.r, needpages, nil);
+ continue;
+ }
- if(!canqlock(&p->seglock))
- continue; /* process changing its segments */
+ if(swapimage.c == nil || swapalloc.free == 0){
+ killbig("out of memory");
+ freebroken(); /* can use the memory */
+ sched();
+ continue;
+ }
- for(i = 0; i < NSEG; i++) {
- if(!needpages(junk)){
- qunlock(&p->seglock);
- goto loop;
- }
+ p++;
+ if(p >= ep){
+ p = proctab(0);
+ ageclock++;
+ }
+
+ if(p->state == Dead || p->noswap)
+ continue;
- if(s = p->seg[i]) {
- switch(s->type&SG_TYPE) {
- default:
- break;
- case SG_TEXT:
- pageout(p, s);
- break;
- case SG_DATA:
- case SG_BSS:
- case SG_STACK:
- case SG_SHARED:
- up->psstate = "Pageout";
- pageout(p, s);
- if(ioptr != 0) {
- up->psstate = "I/O";
- executeio();
- }
- break;
- }
+ if(!canqlock(&p->seglock))
+ continue; /* process changing its segments */
+
+ up->psstate = "Pageout";
+ for(i = 0; i < NSEG; i++) {
+ if((s = p->seg[i]) != nil) {
+ switch(s->type&SG_TYPE) {
+ default:
+ break;
+ case SG_TEXT:
+ pageout(p, s);
+ break;
+ case SG_DATA:
+ case SG_BSS:
+ case SG_STACK:
+ case SG_SHARED:
+ pageout(p, s);
+ break;
}
}
- qunlock(&p->seglock);
- } else {
- killbig("out of memory");
- freebroken(); /* can use the memory */
- sched();
+ }
+ qunlock(&p->seglock);
+
+ if(ioptr > 0) {
+ up->psstate = "I/O";
+ executeio();
}
}
- goto loop;
}
static void
pageout(Proc *p, Segment *s)
{
int type, i, size;
- ulong age;
+ short age;
Pte *l;
Page **pg, *entry;
- if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */
+ if(!canqlock(s)) /* We cannot afford to wait, we will surely deadlock */
return;
if(s->steal) { /* Protected by /dev/proc */
- qunlock(&s->lk);
+ qunlock(s);
return;
}
if(!canflush(p, s)) { /* Able to invalidate all tlbs with references */
- qunlock(&s->lk);
+ qunlock(s);
putseg(s);
return;
}
if(waserror()) {
- qunlock(&s->lk);
+ qunlock(s);
putseg(s);
return;
}
@@ -248,30 +250,19 @@ pageout(Proc *p, Segment *s)
entry = *pg;
if(pagedout(entry))
continue;
-
if(entry->modref & PG_REF) {
entry->modref &= ~PG_REF;
- entry->gen = genclock;
+ entry->refage = ageclock;
+ continue;
}
-
- if(genclock < entry->gen)
- age = ~(entry->gen - genclock);
- else
- age = genclock - entry->gen;
- gensum += age;
- gencount++;
- if(age <= genage)
+ age = (short)(ageclock - entry->refage);
+ if(age < 16)
continue;
-
pagepte(type, pg);
-
- if(ioptr >= conf.nswppo)
- goto out;
}
}
-out:
poperror();
- qunlock(&s->lk);
+ qunlock(s);
putseg(s);
}
@@ -281,14 +272,8 @@ canflush(Proc *p, Segment *s)
int i;
Proc *ep;
- lock(s);
- if(s->ref == 1) { /* Easy if we are the only user */
- s->ref++;
- unlock(s);
+ if(incref(s) == 2) /* Easy if we are the only user */
return canpage(p);
- }
- s->ref++;
- unlock(s);
/* Now we must do hardwork to ensure all processes which have tlb
* entries for this segment will be flushed if we succeed in paging it out
@@ -317,13 +302,16 @@ pagepte(int type, Page **pg)
switch(type) {
case SG_TEXT: /* Revert to demand load */
putpage(outp);
- *pg = 0;
+ *pg = nil;
break;
case SG_DATA:
case SG_BSS:
case SG_STACK:
case SG_SHARED:
+ if(ioptr >= conf.nswppo)
+ break;
+
/*
* get a new swap address with swapcount 2, one for the pte
* and one extra ref for us while we write the page to disk
@@ -335,8 +323,6 @@ pagepte(int type, Page **pg)
/* clear any pages referring to it from the cache */
cachedel(&swapimage, daddr);
- lock(outp);
-
/* forget anything that it used to cache */
uncachepage(outp);
@@ -348,7 +334,6 @@ pagepte(int type, Page **pg)
outp->daddr = daddr;
cachepage(outp, &swapimage);
*pg = (Page*)(daddr|PG_ONSWAP);
- unlock(outp);
/* Add page to IO transaction list */
iolist[ioptr++] = outp;
@@ -365,44 +350,34 @@ pagersummary(void)
ioptr);
}
-static int
-pageiocomp(void *a, void *b)
-{
- Page *p1, *p2;
-
- p1 = *(Page **)a;
- p2 = *(Page **)b;
- if(p1->daddr > p2->daddr)
- return 1;
- else
- return -1;
-}
-
static void
executeio(void)
{
- Page *out;
+ Page *outp;
int i, n;
Chan *c;
char *kaddr;
KMap *k;
c = swapimage.c;
- qsort(iolist, ioptr, sizeof iolist[0], pageiocomp);
for(i = 0; i < ioptr; i++) {
if(ioptr > conf.nswppo)
panic("executeio: ioptr %d > %d", ioptr, conf.nswppo);
- out = iolist[i];
+ outp = iolist[i];
+
+ assert(outp->ref > 0);
+ assert(outp->image == &swapimage);
+ assert(outp->daddr != ~0);
- /* only write when swap address still referenced */
- if(swapcount(out->daddr) > 1){
- k = kmap(out);
+ /* only write when swap address still in use */
+ if(swapcount(outp->daddr) > 1){
+ k = kmap(outp);
kaddr = (char*)VA(k);
if(waserror())
- panic("executeio: page out I/O error");
+ panic("executeio: page outp I/O error");
- n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
+ n = devtab[c->type]->write(c, kaddr, BY2PG, outp->daddr);
if(n != BY2PG)
nexterror();
@@ -411,10 +386,10 @@ executeio(void)
}
/* drop our extra swap reference */
- putswap((Page*)out->daddr);
+ putswap((Page*)outp->daddr);
/* Free up the page after I/O */
- putpage(out);
+ putpage(outp);
}
ioptr = 0;
}
@@ -432,7 +407,7 @@ setswapchan(Chan *c)
Dir d;
int n;
- if(swapimage.c) {
+ if(swapimage.c != nil) {
if(swapalloc.free != conf.nswap){
cclose(c);
error(Einuse);
@@ -461,9 +436,3 @@ setswapchan(Chan *c)
c->flag &= ~CCACHE;
swapimage.c = c;
}
-
-int
-swapfull(void)
-{
- return swapalloc.free < conf.nswap/10;
-}
diff --git a/sys/src/9/port/sysproc.c b/sys/src/9/port/sysproc.c
index fbe4f2fbc..8b6cbeabf 100644
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -125,7 +125,7 @@ sysrfork(va_list list)
nexterror();
}
for(i = 0; i < NSEG; i++)
- if(up->seg[i])
+ if(up->seg[i] != nil)
p->seg[i] = dupseg(up->seg, i, n);
qunlock(&p->seglock);
poperror();
@@ -338,7 +338,7 @@ sysexec(va_list list)
nargs = 0;
if(indir){
argp = progarg;
- while(*argp){
+ while(*argp != nil){
a = *argp++;
nbytes += strlen(a) + 1;
nargs++;
@@ -402,7 +402,7 @@ sysexec(va_list list)
argp = argp0;
for(i=0; i<nargs; i++){
- if(indir && *argp==0) {
+ if(indir && *argp==nil) {
indir = 0;
argp = argp0;
}
@@ -436,20 +436,20 @@ sysexec(va_list list)
for(i = SSEG; i <= BSEG; i++) {
putseg(up->seg[i]);
/* prevent a second free if we have an error */
- up->seg[i] = 0;
+ up->seg[i] = nil;
}
for(i = ESEG+1; i < NSEG; i++) {
s = up->seg[i];
- if(s != 0 && (s->type&SG_CEXEC) != 0) {
+ if(s != nil && (s->type&SG_CEXEC) != 0) {
putseg(s);
- up->seg[i] = 0;
+ up->seg[i] = nil;
}
}
/*
* Close on exec
*/
- if((f = up->fgrp) != nil){
+ if((f = up->fgrp) != nil) {
for(i=0; i<=f->maxfd; i++)
fdclose(i, CCEXEC);
}
@@ -481,7 +481,7 @@ sysexec(va_list list)
* Move the stack
*/
s = up->seg[ESEG];
- up->seg[ESEG] = 0;
+ up->seg[ESEG] = nil;
s->base = USTKTOP-USTKSIZE;
s->top = USTKTOP;
relocateseg(s, USTKTOP-tstk);
@@ -570,7 +570,7 @@ syssleep(va_list list)
ms = va_arg(list, long);
if(ms <= 0) {
- if (up->edf && (up->edf->flags & Admitted))
+ if (up->edf != nil && (up->edf->flags & Admitted))
edfyield();
else
yield();
@@ -597,7 +597,7 @@ sysexits(va_list list)
char buf[ERRMAX];
status = va_arg(list, char*);
- if(status){
+ if(status != nil){
if(waserror())
status = inval;
else{
@@ -714,7 +714,7 @@ sysnotify(va_list list)
{
int (*f)(void*, char*);
f = va_arg(list, void*);
- if(f != 0)
+ if(f != nil)
validaddr((uintptr)f, sizeof(void*), 0);
up->notify = f;
return 0;
@@ -723,7 +723,7 @@ sysnotify(va_list list)
uintptr
sysnoted(va_list list)
{
- if(va_arg(list, int) !=NRSTR && !up->notified)
+ if(va_arg(list, int) != NRSTR && !up->notified)
error(Egreg);
return 0;
}
@@ -738,7 +738,7 @@ syssegbrk(va_list list)
addr = va_arg(list, uintptr);
for(i = 0; i < NSEG; i++) {
s = up->seg[i];
- if(s == 0 || addr < s->base || addr >= s->top)
+ if(s == nil || addr < s->base || addr >= s->top)
continue;
switch(s->type&SG_TYPE) {
case SG_TEXT:
@@ -783,14 +783,14 @@ syssegdetach(va_list list)
nexterror();
}
- s = 0;
+ s = nil;
for(i = 0; i < NSEG; i++)
- if(s = up->seg[i]) {
- qlock(&s->lk);
+ if((s = up->seg[i]) != nil) {
+ qlock(s);
if((addr >= s->base && addr < s->top) ||
(s->top == s->base && addr == s->base))
goto found;
- qunlock(&s->lk);
+ qunlock(s);
}
error(Ebadarg);
@@ -800,11 +800,11 @@ found:
* Check we are not detaching the initial stack segment.
*/
if(s == up->seg[SSEG]){
- qunlock(&s->lk);
+ qunlock(s);
error(Ebadarg);
}
- up->seg[i] = 0;
- qunlock(&s->lk);
+ up->seg[i] = nil;
+ qunlock(s);
putseg(s);
qunlock(&up->seglock);
poperror();
@@ -830,12 +830,12 @@ syssegfree(va_list list)
from = PGROUND(from);
if(to > s->top) {
- qunlock(&s->lk);
+ qunlock(s);
error(Ebadarg);
}
mfreeseg(s, from, (to - from) / BY2PG);
- qunlock(&s->lk);
+ qunlock(s);
flushmmu();
return 0;
}
@@ -858,7 +858,7 @@ sysrendezvous(va_list list)
l = &REND(up->rgrp, tag);
lock(up->rgrp);
- for(p = *l; p; p = p->rendhash) {
+ for(p = *l; p != nil; p = p->rendhash) {
if(p->rendtag == tag) {
*l = p->rendhash;
val = p->rendval;