static void imagereclaim(void) { Image *i; uvlong ticks0, ticks; irstats.calls++; /* Somebody is already cleaning the page cache */ if(!canqlock(&imagealloc.ireclaim)) return; DBG("imagereclaim maxt %ulld noluck %d nolock %d\n", irstats.maxt, irstats.noluck, irstats.nolock); ticks0 = fastticks(nil); if(!canlock(&imagealloc)){ /* never happen in the experiments I made */ qunlock(&imagealloc.ireclaim); return; } for(i = imagealloc.lru; i != nil; i = i->prev){ if(canlock(i)){ i->ref++; /* make sure it does not go away */ unlock(i); pagereclaim(i); lock(i); DBG("imagereclaim: image %p(c%p, r%d)\n", i, i->c, i->ref); if(i->ref == 1){ /* no pages referring to it, it's ours */ unlock(i); unlock(&imagealloc); putimage(i); break; }else --i->ref; unlock(i); } } if(i == nil){ irstats.noluck++; unlock(&imagealloc); } irstats.loops++; ticks = fastticks(nil) - ticks0; irstats.ticks += ticks; if(ticks > irstats.maxt) irstats.maxt = ticks; //print("T%llud+", ticks); qunlock(&imagealloc.ireclaim); }
void qunlock(QLock *q) { Proc *p; uint64_t t0; if(!canlock(&q->use)){ cycles(&t0); lock(&q->use); slockstat(getcallerpc(&q), t0); } if (q->locked == 0) print("qunlock called with qlock not held, from %#p\n", getcallerpc(&q)); p = q->head; if(p){ q->head = p->qnext; if(q->head == 0) q->tail = 0; unlock(&q->use); q->pc = p->qpc; ready(p); return; } q->locked = 0; q->pc = 0; unlock(&q->use); }
/* * Called from imagereclaim, to try to release Images. * The argument shows the preferred image to release pages from. * All images will be tried, from lru to mru. */ uint64_t pagereclaim(Image *i) { Page *p; uint64_t ticks; lock(&pga.l); ticks = fastticks(nil); /* * All the pages with images backing them are at the * end of the list (see putpage) so start there and work * backward. */ for(p = pga.pgsza[0].tail; p && p->image == i; p = p->prev){ if(p->ref == 0 && canlock(&p->l)){ if(p->ref == 0) { uncachepage(p); } unlock(&p->l); } } ticks = fastticks(nil) - ticks; unlock(&pga.l); return ticks; }
void _threadnote(void *v, char *s) { Proc *p; Note *n; _threaddebug(DBGNOTE, "Got note %s", s); // if(strncmp(s, "sys:", 4) == 0) // noted(NDFLT); // if(_threadexitsallstatus){ // _threaddebug(DBGNOTE, "Threadexitsallstatus = '%s'\n", _threadexitsallstatus); // _exits(_threadexitsallstatus); // } if(strcmp(s, "threadint")==0) noted(NCONT); p = _threadgetproc(); if(p == nil) noted(NDFLT); for(n=notes; n<enotes; n++) if(canlock(&n->inuse)) break; if(n==enotes) sysfatal("libthread: too many delayed notes"); utfecpy(n->s, n->s+ERRMAX, s); n->proc = p; p->pending = 1; if(!p->splhi) delayednotes(p, v); noted(NCONT); }
static void clockintr(Ureg*, void*) { Clock0link *lp; int losttick = 0; OstmrReg *ost = OSTMRREG; {static int tag, led; if(++tag >= HZ){ledset(led ^= 1);tag=0;}} m->ticks++; // ost->osmr[3] = ost->oscr + timer_incr[3]; /* restart the watchdog */ ost->osmr[0] += timer_incr[0]; /* advance the clock tick */ ost->ossr = (1<<0); /* Clear the SR */ while((ost->osmr[0] - ost->oscr) >= 0x80000000) { ost->osmr[0] += timer_incr[0]; losttick++; m->ticks++; } checkalarms(); if(canlock(&clock0lock)){ for(lp = clock0link; lp; lp = lp->link) if(lp->clock) lp->clock(); unlock(&clock0lock); } /* round robin time slice is done by trap.c and proc.c */ }
void runlock(RWlock *q) { Proc *p; uint64_t t0; if(!canlock(&q->use)){ cycles(&t0); lock(&q->use); slockstat(getcallerpc(&q), t0); } p = q->head; if(--(q->readers) > 0 || p == nil){ unlock(&q->use); return; } /* start waiting writer */ if(p->state != QueueingW) panic("runlock"); q->head = p->qnext; if(q->head == 0) q->tail = 0; q->writer = 1; unlock(&q->use); ready(p); }
static void myscreenputs(char *s, int n) { int i; Rune r; char buf[4]; if(!islo()) { /* don't deadlock trying to print in interrupt */ if(!canlock(&screenlock)) return; } else lock(&screenlock); while(n > 0){ i = chartorune(&r, s); if(i == 0){ s++; --n; continue; } memmove(buf, s, i); buf[i] = 0; n -= i; s += i; screenputc(buf); } unlock(&screenlock); }
/* * called every clock tick */ void checkalarms(void) { Proc *p; ulong now; now = MACHP(0)->ticks; if(talarm.list == 0 || canlock(&talarm) == 0) return; for(;;) { p = talarm.list; if(p == 0) break; if(p->twhen == 0) { talarm.list = p->tlink; p->trend = 0; continue; } if(now < p->twhen) break; wakeup(p->trend); talarm.list = p->tlink; p->trend = 0; } unlock(&talarm); }
void exit(int ispanic) { canlock(&active); active.machs &= ~(1<<m->machno); active.exiting = 1; unlock(&active); spllo(); print("cpu %d exiting\n", m->machno); do delay(100); while(consactive()); splhi(); delay(1000); /* give serial fifo time to finish flushing */ if (getconf("*debug") != nil) { USED(ispanic); delay(60*1000); /* give us time to read the screen */ } if(arch->coredetach) arch->coredetach(); setupboot(1); // set up to halt for (; ; ) firmware(); // on PC is just: //if (0) { // shutdown(ispanic); // arch->reset(); //} }
int canqlock(QLock *q) { if(!canlock(&q->use)) return 0; if(q->locked){ unlock(&q->use); return 0; } q->locked = 1; unlock(&q->use); return 1; }
int canqlock(QLock *q) { if(!canlock(&q->lock)) return 0; if(!q->locked){ q->locked = 1; unlock(&q->lock); return 1; } unlock(&q->lock); return 0; }
int canqlock(QLock *q) { if(!canlock(&q->use)) return 0; if(q->locked){ unlock(&q->use); return 0; } q->locked = 1; q->qpc = getcallerpc(&q); unlock(&q->use); return 1; }
static int iprintcanlock(Lock *l) { int i; for(i=0; i<1000; i++){ if(canlock(l)) return 1; if(l->m == machp()) return 0; microdelay(100); } return 0; }
void mpshutdown(void) { /* * To be done... */ if(!canlock(&mpshutdownlock)){ /* * If this processor received the CTRL-ALT-DEL from * the keyboard, acknowledge it. Send an INIT to self. */ #ifdef FIXTHIS if(lapicisr(VectorKBD)) lapiceoi(VectorKBD); #endif /* FIX THIS */ arch->introff(); idle(); } if(active.rebooting) return; print("apshutdown: active = %#8.8ux\n", active.machs); delay(1000); splhi(); arch->resetothers(); pcireset(); i8042reset(); /* * Often the BIOS hangs during restart if a conventional 8042 * warm-boot sequence is tried. The following is Intel specific and * seems to perform a cold-boot, but at least it comes back. * And sometimes there is no keyboard... * * The reset register (0xcf9) is usually in one of the bridge * chips. The actual location and sequence could be extracted from * ACPI but why bother, this is the end of the line anyway. */ print("no kbd; trying bios warm boot..."); *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */ outb(0xCF9, 0x02); outb(0xCF9, 0x06); print("can't reset\n"); for(;;) idle(); }
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 addwaitstat(uintptr_t pc, uint64_t t0, int type) { uint i; uint64_t w; if(waitstats.on == 0) return; cycles(&w); w -= t0; mfence(); for(i = 0; i < NWstats; i++) if(waitstats.pcs[i] == pc){ ainc(&waitstats.ns[i]); if(w > waitstats.wait[i]) waitstats.wait[i] = w; /* race but ok */ waitstats.total[i] += w; /* race but ok */ return; } if(!canlock(&waitstatslk)) return; for(i = 0; i < NWstats; i++) if(waitstats.pcs[i] == pc){ ainc(&waitstats.ns[i]); if(w > waitstats.wait[i]) waitstats.wait[i] = w; /* race but ok */ waitstats.total[i] += w; unlock(&waitstatslk); return; } for(i = 0; i < NWstats; i++) if(waitstats.pcs[i] == 0){ waitstats.ns[i] = 1; waitstats.type[i] = type; waitstats.wait[i] = w; waitstats.total[i] = w; mfence(); waitstats.pcs[i] = pc; waitstats.npcs++; break; } unlock(&waitstatslk); }
static void clockintr(Ureg*, void*) { Clock0link *lp; m->ticks++; checkalarms(); if(canlock(&clock0lock)){ for(lp = clock0link; lp; lp = lp->link) if (lp->clock) lp->clock(); unlock(&clock0lock); } intrclear(TIMERbit(0), 0); }
void qlock(QLock *q) { Proc *up = externup(); Proc *p; uint64_t t0; cycles(&t0); if(!islo() && machp()->ilockdepth != 0){ print("qlock with ilockdepth %d,", machp()->ilockdepth); stacksnippet(); } if(up != nil && up->nlocks) print("qlock: %#p: nlocks %d", getcallerpc(&q), up->nlocks); if(!canlock(&q->use)){ lock(&q->use); slockstat(getcallerpc(&q), t0); } qlockstats.qlock++; if(!q->locked) { q->locked = 1; q->pc = getcallerpc(&q); unlock(&q->use); return; } if(up == nil) panic("qlock"); qlockstats.qlockq++; p = q->tail; if(p == 0) q->head = up; else p->qnext = up; q->tail = up; up->qnext = 0; up->state = Queueing; up->qpc = getcallerpc(&q); if(up->trace) proctrace(up, SLock, 0); unlock(&q->use); sched(); lockstat(getcallerpc(&q), t0); }
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 pageunchain(Page *p) { Pgsza *pa; if(canlock(&pga.l)) panic("pageunchain"); pa = &pga.pgsza[p->pgszi]; if(p->prev) p->prev->next = p->next; else pa->head = p->next; if(p->next) p->next->prev = p->prev; else pa->tail = p->prev; p->prev = p->next = nil; pa->freecount--; }
/* * try to remove a process from a scheduling queue (called splhi) */ Proc* dequeueproc(Sched *sch, Schedq *rq, Proc *tp) { Proc *l, *p; if(!canlock(sch)) return nil; /* * the queue may have changed before we locked runq, * refind the target process. */ l = 0; for(p = rq->head; p; p = p->rnext){ if(p == tp) break; l = p; } /* * p->mach==0 only when process state is saved */ if(p == 0 || p->mach){ unlock(sch); return nil; } if(p->rnext == 0) rq->tail = l; if(l) l->rnext = p->rnext; else rq->head = p->rnext; if(rq->head == nil) sch->runvec &= ~(1<<(rq-sch->runq)); rq->n--; sch->nrdy--; if(p->state != Ready) print("dequeueproc %s %d %s\n", p->text, p->pid, statename[p->state]); unlock(sch); return p; }
void wunlock(RWlock *q) { Proc *p; uint64_t t0; if(!canlock(&q->use)){ cycles(&t0); lock(&q->use); slockstat(getcallerpc(&q), t0); } p = q->head; if(p == nil){ q->writer = 0; unlock(&q->use); return; } if(p->state == QueueingW){ /* start waiting writer */ q->head = p->qnext; if(q->head == nil) q->tail = nil; unlock(&q->use); ready(p); return; } if(p->state != QueueingR) panic("wunlock"); /* waken waiting readers */ while(q->head != nil && q->head->state == QueueingR){ p = q->head; q->head = p->qnext; q->readers++; ready(p); } if(q->head == nil) q->tail = nil; q->writer = 0; unlock(&q->use); }
/* same as rlock but punts if there are any writers waiting */ int canrlock(RWlock *q) { uint64_t t0; if(!canlock(&q->use)){ cycles(&t0); lock(&q->use); slockstat(getcallerpc(&q), t0); } qlockstats.rlock++; if(q->writer == 0 && q->head == nil){ /* no writer, go for it */ q->readers++; unlock(&q->use); return 1; } unlock(&q->use); return 0; }
void pagechainhead(Page *p) { Pgsza *pa; if(canlock(&pga.l)) panic("pagechainhead"); pa = &pga.pgsza[p->pgszi]; if(pa->head) { p->next = pa->head; pa->head->prev = p; } else { pa->tail = p; p->next = 0; } pa->head = p; p->prev = 0; pa->freecount++; }
static void vgascreenputs(char* s, int n) { int i; Rune r; char buf[4]; VGAscr *scr; Rectangle flushr; scr = &vgascreen[0]; if(!islo()){ /* * Don't deadlock trying to * print in an interrupt. */ if(!canlock(&vgascreenlock)) return; } else lock(&vgascreenlock); flushr = Rect(10000, 10000, -10000, -10000); while(n > 0){ i = chartorune(&r, s); if(i == 0){ s++; --n; continue; } memmove(buf, s, i); buf[i] = 0; n -= i; s += i; vgascreenputc(scr, buf, &flushr); } flushmemscreen(flushr); unlock(&vgascreenlock); }
void mpshutdown(void) { /* * To be done... */ if(!canlock(&mpshutdownlock)){ /* * If this processor received the CTRL-ALT-DEL from * the keyboard, acknowledge it. Send an INIT to self. */ #ifdef FIXTHIS if(lapicisr(VectorKBD)) lapiceoi(VectorKBD); #endif /* FIX THIS */ idle(); } print("apshutdown: active = 0x%2.2uX\n", active.machs); delay(1000); splhi(); /* * INIT all excluding self. */ lapicicrw(0, 0x000C0000|ApicINIT); #ifdef notdef /* * Often the BIOS hangs during restart if a conventional 8042 * warm-boot sequence is tried. The following is Intel specific and * seems to perform a cold-boot, but at least it comes back. */ *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */ outb(0xCF9, 0x02); outb(0xCF9, 0x06); #else pcireset(); i8042reset(); #endif /* notdef */ }
static void dofreestacks(void) { Stackfree *sf, *last, *next; if(stackfree==nil || !canlock(&stacklock)) return; for(last=nil,sf=stackfree; sf; last=sf,sf=next){ next = sf->next; if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH){ free(sf); if(last) last->next = next; else stackfree = next; sf = last; } } unlock(&stacklock); }
void wlock(RWlock *q) { Proc *up = externup(); Proc *p; uint64_t t0; cycles(&t0); if(!canlock(&q->use)){ lock(&q->use); slockstat(getcallerpc(&q), t0); } qlockstats.wlock++; if(q->readers == 0 && q->writer == 0){ /* noone waiting, go for it */ q->wpc = getcallerpc(&q); q->wproc = up; q->writer = 1; unlock(&q->use); return; } /* wait */ qlockstats.wlockq++; p = q->tail; if(up == nil) panic("wlock"); if(p == nil) q->head = up; else p->qnext = up; q->tail = up; up->qnext = 0; up->state = QueueingW; if(up->trace) proctrace(up, SLock, 0); unlock(&q->use); sched(); lockstat(getcallerpc(&q), t0); }
void threadexitsall(char *msg) { static int pid[1024]; int i, npid, mypid; Proc *p; if(msg == nil) msg = ""; /* * Only one guy, ever, gets to run this. * If two guys do it, inevitably they end up * tripping over each other in the underlying * C library exit() implementation, which is * trying to run the atexit handlers and apparently * not thread safe. This has been observed on * both Linux and OpenBSD. Sigh. */ { static Lock onelock; if(!canlock(&onelock)) _exits(threadexitsmsg); threadexitsmsg = msg; } if(msg == nil) msg = ""; mypid = getpid(); lock(&_threadprocslock); threadexitsmsg = msg; npid = 0; for(p=_threadprocs; p; p=p->next) if(p->osprocid != mypid && p->osprocid >= 1) pid[npid++] = p->osprocid; for(i=0; i<npid; i++) kill(pid[i], SIGUSR2); unlock(&_threadprocslock); exits(msg); }
void machinit(void) { Mach *m0; if (m == 0) { serialputc('?'); serialputc('m'); serialputc('0'); } if(machaddr[m->machno] != m) { serialputc('?'); serialputc('m'); serialputc('m'); } if (canlock(&testlock)) { serialputc('?'); serialputc('l'); panic("cpu%d: locks don't work", m->machno); } m->ticks = 1; m->perf.period = 1; m0 = MACHP(0); if (m->machno != 0) { /* synchronise with cpu 0 */ m->ticks = m0->ticks; m->fastclock = m0->fastclock; m->cpuhz = m0->cpuhz; m->delayloop = m0->delayloop; } if (m->machno != 0 && (m->fastclock == 0 || m->cpuhz == 0 || m->delayloop == 0)) panic("buggered cpu 0 Mach"); machon(m->machno); fpoff(); }