void exit(int ispanic) { int ms, once; lock(&active); if(ispanic) active.ispanic = ispanic; else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) active.ispanic = 0; once = active.machs & (1<<m->machno); active.machs &= ~(1<<m->machno); active.exiting = 1; unlock(&active); if(once) print("cpu%d: exiting\n", m->machno); spllo(); for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); if(active.machs == 0 && consactive() == 0) break; } if(active.ispanic && m->machno == 0){ if(cpuserver) delay(10000); else if(conf.monitor) for(;;); } else delay(1000); }
static void _kproftimer(uintptr_t pc) { if(kprof.time == 0) return; /* * if the pc corresponds to the idle loop, don't consider it. if(m->inidle) return; */ /* * if the pc is coming out of spllo or splx, * use the pc saved when we went splhi. */ if(pc>=PTR2UINT(spllo) && pc<=PTR2UINT(spldone)) pc = machp()->splpc; ilock(&kprof.l); kprof.buf[0] += TK2MS(1); if(kprof.minpc<=pc && pc<kprof.maxpc){ pc -= kprof.minpc; pc >>= LRES; kprof.buf[pc] += TK2MS(1); }else
static void shutdown(int ispanic) { int ms, once; lock(&active); if(ispanic) active.ispanic = ispanic; else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) active.ispanic = 0; once = active.machs & (1<<m->machno); active.machs &= ~(1<<m->machno); active.exiting = 1; unlock(&active); if(once) iprint("cpu%d: exiting\n", m->machno); spllo(); for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); if(active.machs == 0 && consactive() == 0) break; } delay(1000); }
static Ctlr* pnpprobe(SDev *sd) { ulong start; char *p; static int i; if(i > nprobe) return 0; p = probef[i++]; if(strlen(p) < 2) return 0; if(p[1] == '!') p += 2; start = TK2MS(MACHP(0)->ticks); if(waserror()){ print("#æ: pnpprobe failed in %lud ms: %s: %s\n", TK2MS(MACHP(0)->ticks) - start, probef[i-1], up->errstr); return nil; } sd = aoeprobe(p, sd); /* does a round of probing */ poperror(); print("#æ: pnpprobe established %s in %lud ms\n", probef[i-1], TK2MS(MACHP(0)->ticks) - start); return sd->ctlr; }
int etherrxpkt(int ctlrno, Etherpkt *pkt, int timo) { int n; Ctlr *ctlr; Block *b; ulong start; if((ctlr = attach(ctlrno)) == 0) return 0; start = m->ticks; while((b = qget(ctlr->iq)) == 0){ if(TK2MS(m->ticks - start) >= timo){ /* print("ether%d: rx timeout\n", ctlrno); */ return 0; } //delay(1); } n = BLEN(b); memmove(pkt, b->rp, n); freeb(b); return n; }
/* Acquire semaphore or timeout */ static int tsemacquire(Segment *s, long *addr, ulong ms) { int acquired; Sema phore; int timedout; ulong t; ulong tsemdbg; if(canacquire(addr)) return 1; if(ms == 0) return 0; acquired = 0; timedout = 0; semqueue(s, addr, &phore); for(;;){ phore.waiting = 1; coherence(); if(canacquire(addr)){ acquired = 1; break; } if(waserror()) break; t = m->ticks; tsleep(&phore, semawoke, &phore, ms); if((tsemdbg = TK2MS(m->ticks - t)) >= ms){ timedout = 1; poperror(); break; } ms -= TK2MS(m->ticks - t); poperror(); } semdequeue(s, &phore); coherence(); /* not strictly necessary due to lock in semdequeue */ if(!phore.waiting) semwakeup(s, addr, 1); if(timedout) return 0; if(!acquired) nexterror(); return 1; }
uintptr syssleep(va_list list) { long ms; ms = va_arg(list, long); if(ms <= 0) { if (up->edf != nil && (up->edf->flags & Admitted)) edfyield(); else yield(); } else { if(ms < TK2MS(1)) ms = TK2MS(1); tsleep(&up->sleep, return0, 0, ms); } return 0; }
static void shutdown(int ispanic) { int ms, once; lock(&active); if(ispanic) active.ispanic = ispanic; else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) active.ispanic = 0; once = active.machs & (1<<m->machno); /* * setting exiting will make hzclock() on each processor call exit(0), * which calls shutdown(0) and arch->reset(), which on mp systems is * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap * processors (to permit a reboot). clearing our bit in machs avoids * calling exit(0) from hzclock() on this processor. */ active.machs &= ~(1<<m->machno); active.exiting = 1; unlock(&active); if(once) iprint("cpu%d: exiting\n", m->machno); /* wait for any other processors to shutdown */ spllo(); for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); if(active.machs == 0 && consactive() == 0) break; } if(active.ispanic){ if(!cpuserver) for(;;) halt(); if(getconf("*debug")) delay(5*60*1000); else delay(10000); }else delay(1000); }
static void ethercheck(Ether *ether) { if (ether->starttime != 0 && TK2MS(MACHP(0)->ticks)/1000 - ether->starttime > Etherstuck) { etheractive(ether); if (ether->ctlrno == 0) /* only complain about main ether */ iprint("#l%d: ethernet stuck\n", ether->ctlrno); } }
long syssleep(ulong *arg) { int n; n = arg[0]; if(n <= 0) { if (up->edf && (up->edf->flags & Admitted)) edfyield(); else yield(); return 0; } if(n < TK2MS(1)) n = TK2MS(1); tsleep(&up->sleep, return0, 0, n); return 0; }
static void _kproftimer(ulong pc) { extern void spldone(void); if(kprof.time == 0) return; /* * if the pc is coming out of spllo or splx, * use the pc saved when we went splhi. */ if(pc>=(ulong)spllo && pc<=(ulong)spldone) pc = m->splpc; kprof.buf[0] += TK2MS(1); if(kprof.minpc<=pc && pc<kprof.maxpc){ pc -= kprof.minpc; pc >>= LRES; kprof.buf[pc] += TK2MS(1); }else
void tsleep(void*, int (*fn)(void*), void *v, int msec) { int x; ulong start; x = spllo(); for(start = m->ticks; TK2MS(m->ticks - start) < msec && !fn(v); ) ; splx(x); }
static void fakeintrs(Alarm *) { int ctlrno; Ether *eth; for(ctlrno = 0; ctlrno < MaxEther; ctlrno++) { eth = ðer[ctlrno]; if (eth->interrupt) eth->interrupt(nil, eth); } alarm(TK2MS(1), fakeintrs, nil); }
/* * get info about card */ static void slotinfo(PCMslot *pp) { uchar isr; isr = rdreg(pp, Ris); pp->occupied = (isr & (3<<2)) == (3<<2); pp->powered = isr & (1<<6); pp->battery = (isr & 3) == 3; pp->wrprot = isr & (1<<4); pp->busy = isr & (1<<5); pp->msec = TK2MS(MACHP(0)->ticks); }
static void shutdown(int ispanic) { Mach *m = machp(); int ms, once; lock(&active); if(ispanic) active.ispanic = ispanic; else if(m->machno == 0 && m->online == 0) active.ispanic = 0; once = m->online; m->online = 0; adec(&active.nonline); active.exiting = 1; unlock(&active); if(once) iprint("cpu%d: exiting\n", m->machno); spllo(); for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); if(active.nonline == 0) break; } if(active.ispanic && m->machno == 0){ if(cpuserver) delay(30000); else for(;;) halt(); } else delay(1000); }
static void shutdown(int ispanic) { int ms, once; lock(&active); if(ispanic) active.ispanic = ispanic; else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) active.ispanic = 0; once = active.machs & (1<<m->machno); /* * setting exiting will make hzclock() on each processor call exit(0), * which calls shutdown(0) and idles non-bootstrap cpus and returns * on bootstrap processors (to permit a reboot). clearing our bit * in machs avoids calling exit(0) from hzclock() on this processor. */ active.machs &= ~(1<<m->machno); active.exiting = 1; unlock(&active); if(once) { delay(m->machno*1000); /* stagger them */ iprint("cpu%d: exiting\n", m->machno); } spllo(); if (m->machno == 0) ms = 5*1000; else ms = 2*1000; for(; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); if(active.machs == 0 && consactive() == 0) break; } delay(500); }
static void profclock(Ureg *ur, Timer *) { Tos *tos; if(up == nil || up->state != Running) return; /* user profiling clock */ if(userureg(ur)){ tos = (Tos*)(USTKTOP-sizeof(Tos)); tos->clock += TK2MS(1); segclock(userpc(ur)); } }
void shutdown(int ispanic) { int ms, once; lock(&active); if(ispanic) active.ispanic = ispanic; else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0) active.ispanic = 0; once = active.machs & (1<<m->machno); active.machs &= ~(1<<m->machno); active.exiting = 1; unlock(&active); if(once) print("cpu%d: exiting\n", m->machno); spllo(); for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ delay(TK2MS(2)); if(active.machs == 0 && consactive() == 0) break; } #ifdef notdef if(active.ispanic && m->machno == 0){ if(cpuserver) delay(30000); else for(;;) halt(); } else #endif /* notdef */ delay(1000); }
static void profclock(Ureg *ur, Timer *ti) { Mach *m = machp(); Tos *tos; if(m->externup == nil || m->externup->state != Running) return; /* user profiling clock */ if(userureg(ur)){ tos = (Tos*)(USTKTOP-sizeof(Tos)); tos->clock += TK2MS(1); segclock(userpc(ur)); } }
static int wait(RingBuf* ring, uchar owner, int timo) { ulong start; start = m->ticks; while(TK2MS(m->ticks - start) < timo){ if(ring->owner != owner) return 1; /* * idling here cuts time to load 9pc.gz in a parallels vm * from 4 minutes to about 1 second. */ idle(); } return 0; }
/* * called by any source of pointer data */ void mousetrack(int b, int x, int y, int isdelta) { int lastb; ulong msec; Pointer e; if(isdelta){ x += mouse.x; y += mouse.y; } msec = TK2MS(MACHP(0)->ticks); if(b && (mouse.b ^ b)&0x1f){ if(msec - mouse.msec < 300 && mouse.lastb == b && abs(mouse.x - x) < 12 && abs(mouse.y - y) < 12) b |= 1<<8; mouse.lastb = b & 0x1f; mouse.msec = msec; } if(x == mouse.x && y == mouse.y && mouse.b == b) return; lastb = mouse.b; mouse.x = x; mouse.y = y; mouse.b = b; mouse.msec = msec; if(!ptrq.full && lastb != b){ e = mouse.Pointer; ptrq.clicks[ptrq.wr] = e; if(++ptrq.wr >= Nevent) ptrq.wr = 0; if(ptrq.wr == ptrq.rd) ptrq.full = 1; } mouse.modify = 1; ptrq.put++; wakeup(&ptrq.r); drawactive(1); /* TO DO: cursor update */ }
/* * look for a card whose version contains 'idstr' */ static int pcmcia_pcmspecial(char *idstr, ISAConf *isa) { PCMslot *pp; extern char *strstr(char*, char*); int enabled; for(pp = slot; pp < lastslot; pp++){ if(pp->special) continue; /* already taken */ /* * make sure we don't power on cards when we already know what's * in them. We'll reread every two minutes if necessary */ enabled = 0; if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000){ increfp(pp); enabled++; } if(pp->occupied) { if(strstr(pp->verstr, idstr)){ if (!enabled){ enabled = 1; increfp(pp); } if(isa == 0 || pcmio(pp->slotno, isa) == 0){ pp->special = 1; return pp->slotno; } } } else pp->special = 1; if (enabled) decrefp(pp); } return -1; }
static int32_t consread(Chan *c, void *buf, int32_t n, int64_t off) { Proc *up = externup(); uint64_t l; Mach *mp; char *b, *bp, *s, *e; char tmp[512]; /* Qswap is 381 bytes at clu */ int i, k, id; int32_t offset; if(n <= 0) return n; offset = off; switch((uint32_t)c->qid.path){ case Qdir: return devdirread(c, buf, n, consdir, nelem(consdir), devgen); case Qcons: error(Egreg); case Qcputime: k = offset; if(k >= 6*NUMSIZE) return 0; if(k+n > 6*NUMSIZE) n = 6*NUMSIZE - k; /* easiest to format in a separate buffer and copy out */ for(i=0; i<6 && NUMSIZE*i<k+n; i++){ l = up->time[i]; if(i == TReal) l = sys->ticks - l; l = TK2MS(l); readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); } memmove(buf, tmp+k, n); return n; case Qkmesg: /* * This is unlocked to avoid tying up a process * that's writing to the buffer. kmesg.n never * gets smaller, so worst case the reader will * see a slurred buffer. */ if(off >= kmesg.n) n = 0; else{ if(off+n > kmesg.n) n = kmesg.n - off; memmove(buf, kmesg.buf+off, n); } return n; case Qkprint: error(Egreg); case Qpgrpid: return readnum(offset, buf, n, up->pgrp->pgrpid, NUMSIZE); case Qpid: return readnum(offset, buf, n, up->pid, NUMSIZE); case Qppid: return readnum(offset, buf, n, up->parentpid, NUMSIZE); case Qtime: return readtime(offset, buf, n); case Qbintime: return readbintime(buf, n); case Qhostowner: return readstr(offset, buf, n, eve); case Qhostdomain: return readstr(offset, buf, n, hostdomain); case Quser: return readstr(offset, buf, n, up->user); case Qnull: return 0; case Qsysstat: n = MACHMAX*(NUMSIZE*11+2+1); b = smalloc(n + 1); /* +1 for NUL */ bp = b; e = bp + n; for(id = 0; id < MACHMAX; id++) if((mp = sys->machptr[id]) != nil && mp->online){ readnum(0, bp, NUMSIZE, mp->machno, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, sys->load, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, (mp->perf.avg_inidle*100)/mp->perf.period, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, (mp->perf.avg_inintr*100)/mp->perf.period, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, 0, NUMSIZE); /* sched # */ bp += NUMSIZE; bp = strecpy(bp, e, rolename[mp->NIX.nixtype]); *bp++ = '\n'; } if(waserror()){ free(b); nexterror(); } n = readstr(offset, buf, n, b); free(b); poperror(); return n; case Qswap: tmp[0] = 0; s = seprintpagestats(tmp, tmp + sizeof tmp); s = seprintphysstats(s, tmp + sizeof tmp); b = buf; l = s - tmp; i = readstr(offset, b, l, tmp); b += i; n -= i; if(offset > l) offset -= l; else offset = 0; return i + mallocreadsummary(c, b, n, offset); case Qsysname: if(sysname == nil) return 0; return readstr(offset, buf, n, sysname); case Qrandom: return randomread(buf, n); case Qurandom: return urandomread(buf, n); case Qdrivers: return devtabread(c, buf, n, off); case Qzero: memset(buf, 0, n); return n; case Qosversion: snprint(tmp, sizeof tmp, "2000"); n = readstr(offset, buf, n, tmp); return n; case Qdebug: s = seprint(tmp, tmp + sizeof tmp, "locks %lu\n", lockstats.locks); s = seprint(s, tmp + sizeof tmp, "glare %lu\n", lockstats.glare); s = seprint(s, tmp + sizeof tmp, "inglare %lu\n", lockstats.inglare); s = seprint(s, tmp + sizeof tmp, "qlock %lu\n", qlockstats.qlock); seprint(s, tmp + sizeof tmp, "qlockq %lu\n", qlockstats.qlockq); return readstr(offset, buf, n, tmp); break; case Qsyscall: snprint(tmp, sizeof tmp, "%s", printallsyscalls ? "on" : "off"); return readstr(offset, buf, n, tmp); break; default: print("consread %#llx\n", c->qid.path); error(Egreg); } return -1; /* never reached */ }
static long consread(struct chan *c, void *buf, long n, int64_t off) { ERRSTACK(1); uint32_t l; #if 0 Mach *mp; #endif char *b, *bp, ch; char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */ int i, k, id, send; int64_t offset = off; #if 0 extern char configfile[]; #endif if (n <= 0) return n; switch ((uint32_t) c->qid.path) { case Qdir: return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen); case Qcons: qlock(&(&kbd)->qlock); if (waserror()) { qunlock(&(&kbd)->qlock); nexterror(); } while (!qcanread(lineq)) { if (qread(kbdq, &ch, 1) == 0) continue; send = 0; if (ch == 0) { /* flush output on rawoff -> rawon */ if (kbd.x > 0) send = !qcanread(kbdq); } else if (kbd.raw) { kbd.line[kbd.x++] = ch; send = !qcanread(kbdq); } else { switch (ch) { case '\b': if (kbd.x > 0) kbd.x--; break; case 0x15: /* ^U */ kbd.x = 0; break; case '\n': case 0x04: /* ^D */ send = 1; default: if (ch != 0x04) kbd.line[kbd.x++] = ch; break; } } if (send || kbd.x == sizeof kbd.line) { qwrite(lineq, kbd.line, kbd.x); kbd.x = 0; } } n = qread(lineq, buf, n); qunlock(&(&kbd)->qlock); poperror(); return n; #if 0 case Qcputime: k = offset; if (k >= 6 * NUMSIZE) return 0; if (k + n > 6 * NUMSIZE) n = 6 * NUMSIZE - k; /* easiest to format in a separate buffer and copy out */ for (i = 0; i < 6 && NUMSIZE * i < k + n; i++) { l = current->time[i]; if (i == TReal) l = MACHP(0)->ticks - l; l = TK2MS(l); consreadnum(0, tmp + NUMSIZE * i, NUMSIZE, l, NUMSIZE); } memmove(buf, tmp + k, n); return n; #endif case Qkmesg: /* * This is unlocked to avoid tying up a process * that's writing to the buffer. kmesg.n never * gets smaller, so worst case the reader will * see a slurred buffer. */ if (off >= kmesg.n) n = 0; else { if (off + n > kmesg.n) n = kmesg.n - off; memmove(buf, kmesg.buf + off, n); } return n; case Qkprint: return qread(kprintoq, buf, n); case Qpgrpid: return consreadnum((uint32_t) offset, buf, n, current->pgrp->pgrpid, NUMSIZE); case Qpid: return consreadnum((uint32_t) offset, buf, n, current->pid, NUMSIZE); case Qppid: return consreadnum((uint32_t) offset, buf, n, current->ppid, NUMSIZE); case Qtime: return readtime((uint32_t) offset, buf, n); case Qbintime: return readbintime(buf, n); case Qhostowner: return consreadstr((uint32_t) offset, buf, n, eve); case Qhostdomain: return consreadstr((uint32_t) offset, buf, n, hostdomain); case Quser: return consreadstr((uint32_t) offset, buf, n, current->user); case Qnull: return 0; #if 0 case Qconfig: return consreadstr((uint32_t) offset, buf, n, configfile); case Qsysstat: b = kzmalloc(conf.nmach * (NUMSIZE * 11 + 1) + 1, 0); /* +1 for NUL */ bp = b; for (id = 0; id < 32; id++) { if (active.machs & (1 << id)) { mp = MACHP(id); consreadnum(0, bp, NUMSIZE, id, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, mp->cs, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, mp->intr, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, mp->load, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, (mp->perf.avg_inidle * 100) / mp->perf.period, NUMSIZE); bp += NUMSIZE; consreadnum(0, bp, NUMSIZE, (mp->perf.avg_inintr * 100) / mp->perf.period, NUMSIZE); bp += NUMSIZE; *bp++ = '\n'; } } if (waserror()) { kfree(b); nexterror(); } n = consreadstr((uint32_t) offset, buf, n, b); kfree(b); poperror(); return n; case Qswap: snprintf(tmp, sizeof tmp, "%lud memory\n" "%d pagesize\n" "%lud kernel\n" "%lud/%lud user\n" "%lud/%lud swap\n" "%lud/%lud kernel malloc\n" "%lud/%lud kernel draw\n", conf.npage * BY2PG, BY2PG, conf.npage - conf.upages, palloc.user - palloc.freecount, palloc.user, conf.nswap - swapalloc.free, conf.nswap, mainmem->cursize, mainmem->maxsize, imagmem->cursize, imagmem->maxsize); return consreadstr((uint32_t) offset, buf, n, tmp); #endif case Qsysname: if (sysname == NULL) return 0; return consreadstr((uint32_t) offset, buf, n, sysname); case Qdrivers: b = kzmalloc(READSTR, 0); if (b == NULL) error(ENOMEM, "allocation for /dev/drivers read failed"); k = 0; for (int i = 0; &devtab[i] < __devtabend; i++) k += snprintf(b + k, READSTR - k, "#%s\n", devtab[i].name); if (waserror()) { kfree(b); nexterror(); } n = consreadstr((uint32_t) offset, buf, n, b); kfree(b); poperror(); return n; case Qklog: //return qread(klogq, buf, n); /* the queue gives us some elasticity for log reading. */ if (!logqueue) logqueue = qopen(1 << 20, 0, 0, 0); if (logqueue) { int ret; /* atomic sets/gets are not that important in this case. */ reading_kmesg = 1; qwrite(logqueue, logbuffer, index); index = 0; ret = qread(logqueue, buf, n); reading_kmesg = 0; return ret; } break; case Qzero: memset(buf, 0, n); return n; case Qosversion: snprintf(tmp, sizeof tmp, "2000"); n = consreadstr((uint32_t) offset, buf, n, tmp); return n; default: printd("consread %#llux\n", c->qid.path); error(EINVAL, "bad QID in consread"); } return -1; /* never reached */ }
static void etheractive(Ether *ether) { ether->starttime = TK2MS(MACHP(0)->ticks)/1000; }
static long consread(Chan *c, void *buf, long n, vlong offset) { int l; Osenv *o; int ch, eol, i; char *p, tmp[128]; char *cbuf = buf; if(n <= 0) return n; o = up->env; switch((ulong)c->qid.path){ case Qdir: return devdirread(c, buf, n, consdir, nelem(consdir), devgen); case Qsysctl: return readstr(offset, buf, n, VERSION); case Qcons: case Qkeyboard: qlock(&kbd); if(waserror()) { qunlock(&kbd); nexterror(); } if(kbd.raw || kbd.kbdr) { if(qcanread(lineq)) n = qread(lineq, buf, n); else { /* read as much as possible */ do { i = qread(kbdq, cbuf, n); cbuf += i; n -= i; } while(n>0 && qcanread(kbdq)); n = cbuf - (char*)buf; } } else { while(!qcanread(lineq)) { qread(kbdq, &kbd.line[kbd.x], 1); ch = kbd.line[kbd.x]; eol = 0; switch(ch){ case '\b': if(kbd.x) kbd.x--; break; case 0x15: kbd.x = 0; break; case '\n': case 0x04: eol = 1; default: kbd.line[kbd.x++] = ch; break; } if(kbd.x == sizeof(kbd.line) || eol) { if(ch == 0x04) kbd.x--; qwrite(lineq, kbd.line, kbd.x); kbd.x = 0; } } n = qread(lineq, buf, n); } qunlock(&kbd); poperror(); return n; case Qscancode: if(offset == 0) return readstr(0, buf, n, kscanid); else return qread(kscanq, buf, n); case Qtime: snprint(tmp, sizeof(tmp), "%.lld", (vlong)mseconds()*1000); return readstr(offset, buf, n, tmp); case Qhostowner: return readstr(offset, buf, n, eve); case Quser: return readstr(offset, buf, n, o->user); case Qjit: snprint(tmp, sizeof(tmp), "%d", cflag); return readstr(offset, buf, n, tmp); case Qnull: return 0; case Qmsec: return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE); case Qsysname: if(sysname == nil) return 0; return readstr(offset, buf, n, sysname); case Qnotquiterandom: genrandom(buf, n); return n; case Qrandom: return randomread(buf, n); case Qmemory: return poolread(buf, n, offset); case Qdrivers: p = malloc(READSTR); if(p == nil) error(Enomem); l = 0; for(i = 0; devtab[i] != nil; i++) l += snprint(p+l, READSTR-l, "#%C %s\n", devtab[i]->dc, devtab[i]->name); if(waserror()){ free(p); nexterror(); } n = readstr(offset, buf, n, p); free(p); poperror(); return n; case Qklog: return qread(klogq, buf, n); case Qkprint: rlock(&kprintq); if(waserror()){ runlock(&kprintq); nexterror(); } n = qread(kprintq.q, buf, n); poperror(); runlock(&kprintq); return n; default: print("consread %llud\n", c->qid.path); error(Egreg); } return -1; /* never reached */ }
vlong osusectime(void) { return (((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)))*1000); }
vlong mseconds(void) { return ((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks))); }
/* * Check all frames on device and resend any frames that have been * outstanding for 200% of the device round trip time average. */ static void aoesweepproc(void*) { ulong i, tx, timeout, nbc; vlong starttick; enum { Nms = 100, Nbcms = 30*1000, }; /* magic */ uchar *ea; Aoeata *a; Aoedev *d; Devlink *l; Frame *f, *e; nbc = Nbcms/Nms; loop: if(nbc-- == 0){ if(rediscover && !waserror()){ discover(0xffff, 0xff); poperror(); } nbc = Nbcms/Nms; } starttick = MACHP(0)->ticks; rlock(&devs); for(d = devs.d; d; d = d->next){ if(!canqlock(d)) continue; if(!UP(d)){ qunlock(d); continue; } tx = 0; f = d->frames; e = f + d->nframes; for (; f < e; f++){ if(f->tag == Tfree) continue; l = f->dl; timeout = l->rttavg << 1; i = tsince(f->tag); if(i < timeout) continue; if(d->nout == d->maxout){ if(d->maxout > 1) d->maxout--; d->lastwadj = MACHP(0)->ticks; } a = (Aoeata*)f->hdr; if(a->scnt > Dbcnt / Aoesectsz && ++f->nl->lostjumbo > (d->nframes << 1)){ ea = f->dl->eatab[f->eaidx]; eventlog("%æ: jumbo failure on %s:%E; lba%lld\n", d, f->nl->path, ea, f->lba); d->maxbcnt = Dbcnt; d->flag &= ~Djumbo; } resend(d, f); if(tx++ == 0){ if((l->rttavg <<= 1) > Rtmax) l->rttavg = Rtmax; eventlog("%æ: rtt %ldms\n", d, TK2MS(l->rttavg)); } } if(d->nout == d->maxout && d->maxout < d->nframes && TK2MS(MACHP(0)->ticks - d->lastwadj) > 10*1000){ /* more magic */ d->maxout++; d->lastwadj = MACHP(0)->ticks; } qunlock(d); } runlock(&devs); i = Nms - TK2MS(MACHP(0)->ticks - starttick); if(i > 0) tsleep(&up->sleep, return0, 0, i); goto loop; }
static long consread(Chan *c, void *buf, long n, vlong off) { ulong l; Mach *mp; char *b, *bp; char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */ int i, k, id; vlong offset = off; extern char configfile[]; if(n <= 0) return n; switch((ulong)c->qid.path){ case Qdir: return devdirread(c, buf, n, consdir, nelem(consdir), devgen); case Qcons: error(Egreg); case Qcputime: k = offset; if(k >= 6*NUMSIZE) return 0; if(k+n > 6*NUMSIZE) n = 6*NUMSIZE - k; /* easiest to format in a separate buffer and copy out */ for(i=0; i<6 && NUMSIZE*i<k+n; i++){ l = up->time[i]; if(i == TReal) l = MACHP(0)->ticks - l; l = TK2MS(l); readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); } memmove(buf, tmp+k, n); return n; case Qkmesg: /* * This is unlocked to avoid tying up a process * that's writing to the buffer. kmesg.n never * gets smaller, so worst case the reader will * see a slurred buffer. */ if(off >= kmesg.n) n = 0; else{ if(off+n > kmesg.n) n = kmesg.n - off; memmove(buf, kmesg.buf+off, n); } return n; case Qkprint: return qread(kprintoq, buf, n); case Qpgrpid: return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); case Qpid: return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); case Qppid: return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); case Qtime: return readtime((ulong)offset, buf, n); case Qbintime: return readbintime(buf, n); case Qhostowner: return readstr((ulong)offset, buf, n, eve); case Qhostdomain: return readstr((ulong)offset, buf, n, hostdomain); case Quser: return readstr((ulong)offset, buf, n, up->user); case Qnull: return 0; case Qconfig: return readstr((ulong)offset, buf, n, configfile); case Qsysstat: b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1); /* +1 for NUL */ bp = b; for(id = 0; id < 32; id++) { if(active.machs & (1<<id)) { mp = MACHP(id); readnum(0, bp, NUMSIZE, id, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->load, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, (mp->perf.avg_inidle*100)/mp->perf.period, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, (mp->perf.avg_inintr*100)/mp->perf.period, NUMSIZE); bp += NUMSIZE; *bp++ = '\n'; } } if(waserror()){ free(b); nexterror(); } n = readstr((ulong)offset, buf, n, b); free(b); poperror(); return n; case Qswap: snprint(tmp, sizeof tmp, "%lud memory\n" "%d pagesize\n" "%lud kernel\n" "%lud/%lud user\n" "%lud/%lud swap\n" "%lud/%lud kernel malloc\n" "%lud/%lud kernel draw\n", conf.npage*BY2PG, BY2PG, conf.npage-conf.upages, palloc.user-palloc.freecount, palloc.user, conf.nswap-swapalloc.free, conf.nswap, mainmem->cursize, mainmem->maxsize, imagmem->cursize, imagmem->maxsize); return readstr((ulong)offset, buf, n, tmp); case Qsysname: if(sysname == nil) return 0; return readstr((ulong)offset, buf, n, sysname); case Qrandom: return randomread(buf, n); case Qdrivers: b = smalloc(READSTR); k = 0; for(i = 0; devtab[i] != nil; i++) k += snprint(b+k, READSTR-k, "#%C %s\n", devtab[i]->dc, devtab[i]->name); if(waserror()){ free(b); nexterror(); } n = readstr((ulong)offset, buf, n, b); poperror(); free(b); return n; case Qzero: memset(buf, 0, n); return n; case Qmordor: error("one does not simply read from mordor"); return 0; case Qosversion: snprint(tmp, sizeof tmp, "2000"); n = readstr((ulong)offset, buf, n, tmp); return n; default: print("consread %#llux\n", c->qid.path); error(Egreg); } return -1; /* never reached */ }