Avoid holding locks too long in imagereclaim, and avoid rescheduling if it does happen. [rsc] --rw-rw-r-- M 23749 glenda sys 28702 Jan 31 18:16 sys/src/9/port/proc.c /n/sourcesdump/2006/0131/plan9/sys/src/9/port/proc.c:122,128 - /n/sourcesdump/2006/0201/plan9/sys/src/9/port/proc.c:122,146 getcallerpc(&p+2)); if(up){ - if(up->nlocks.ref && up->state != Moribund && up->delaysched < 20){ + /* + * Delay the sched until the process gives up the locks + * it is holding. This avoids dumb lock loops. + * Don't delay if the process is Moribund. + * It called sched to die. + * But do sched eventually. This avoids a missing unlock + * from hanging the entire kernel. + * But don't reschedule procs holding palloc or procalloc. + * Those are far too important to be holding while asleep. + * + * This test is not exact. There can still be a few instructions + * in the middle of taslock when a process holds a lock + * but Lock.p has not yet been initialized. + */ + if(up->nlocks.ref) + if(up->state != Moribund) + if(up->delaysched < 20 + || palloc.Lock.p == up + || procalloc.Lock.p == up){ up->delaysched++; delayedscheds++; return; [rsc] --rw-rw-r-- M 23749 glenda sys 13939 Jan 31 18:16 sys/src/9/port/segment.c /n/sourcesdump/2006/0131/plan9/sys/src/9/port/segment.c:320,325 - /n/sourcesdump/2006/0201/plan9/sys/src/9/port/segment.c:320,326 static void imagereclaim(void) { + int n; Page *p; uvlong ticks; /n/sourcesdump/2006/0131/plan9/sys/src/9/port/segment.c:330,339 - /n/sourcesdump/2006/0201/plan9/sys/src/9/port/segment.c:331,348 lock(&palloc); ticks = fastticks(nil); - for(p = palloc.head; p; p = p->next) { - if(p->ref == 0 && p->image && canlock(p)) { - if(p->ref == 0) + 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; p = p->prev) { + if(p->ref == 0 && canlock(p)) { + if(p->ref == 0) { + n++; uncachepage(p); + } unlock(p); } }