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