although they are old and depricated, follow through with adding ticket locks to the fs kernel/amd64 port as they've now been properly tested. they should be replaced soon with mcs locks or another scalable lock. Reference: /n/atom/patch/applied/fstiklock Date: Mon Apr 14 07:16:21 CES 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/fs/amd64/arch.c Mon Apr 14 07:15:20 2014 +++ /sys/src/fs/amd64/arch.c Mon Apr 14 07:15:21 2014 @@ -531,7 +531,7 @@ kbdinit(); - if((p = getconf("console")) == 0 || cistrcmp(p, "cga") == 0) + if((p = getconf("console")) == nil || cistrcmp(p, "cga") == 0) return; port = strtoul(p, &p, 0); @@ -565,7 +565,7 @@ /* * Always called splhi(). */ - if((p = getconf("reset")) && cistrcmp(p, "manual") == 0){ + if((p = getconf("reset")) != nil && cistrcmp(p, "manual") == 0){ predawn = 1; print("\nHit Reset\n"); for(;;); --- /sys/src/fs/amd64/trap.c Mon Apr 14 07:15:22 2014 +++ /sys/src/fs/amd64/trap.c Mon Apr 14 07:15:23 2014 @@ -413,14 +413,18 @@ static void faultamd64(Ureg* ureg, void*) { + char *text; int pid; - u64int addr; + uintptr addr; addr = getcr2(); pid = -1; - if(up) + text = ""; + if(up){ pid = up->pid; - panic("cpu%d: fault with up %d; pc %#p addr %#p\n", m->machno, pid, ureg->ip, addr); + text = up->text; + } + panic("cpu%d: %d:%s fault: pc %#p addr %#p\n", m->machno, pid, text, ureg->ip, addr); } /* --- /sys/src/fs/amd64/archdat.h Mon Apr 14 07:15:24 2014 +++ /sys/src/fs/amd64/archdat.h Mon Apr 14 07:15:25 2014 @@ -29,6 +29,7 @@ NPGSZ = 4, }; +#ifdef taslock struct Lock { u32int* sbsem; /* addr of sync bus semaphore */ @@ -39,6 +40,18 @@ User *p; char isilock; }; +#else +#define CACHELINESZ 64 +struct Lock +{ + uchar pad[CACHELINESZ*2]; + Mpl sr; + int isilock; + uintptr pc; + User *p; + Mach *m; +}; +#endif enum { MAXBANK = 8, @@ -130,6 +143,7 @@ int lastintr; int spuriousintr; + int ilockdepth; MMMU; --- /sys/src/fs/amd64/lapic.c Mon Apr 14 07:15:27 2014 +++ /sys/src/fs/amd64/lapic.c Mon Apr 14 07:15:28 2014 @@ -217,7 +217,7 @@ lapiconline(void) { Apic *apic; - u64int tsc; + u64int tsc, tcc; u32int dfr, ver; int apicno, nlvt; @@ -290,20 +290,20 @@ */ lapicrput(Tdc, DivX1); lapicrput(Tlvt, Im); - tsc = rdtsc() + m->cpuhz/10; + tsc = rdtsc() + m->cpuhz/100; lapicrput(Tic, 0xffffffff); while(rdtsc() < tsc) - ; + pause(); - apic->hz = (0xffffffff-lapicrget(Tcc))*10; + apic->hz = (0xffffffff-(tcc=lapicrget(Tcc)))*100; apic->max = apic->hz/HZ; apic->min = apic->hz/(100*HZ); apic->div = ((m->cpuhz/apic->max)+HZ/2)/HZ; - if(m->machno == 0 || DBGFLG){ - print("lapic%d: hz %lld max %lld min %lld div %lld\n", apicno, - apic->hz, apic->max, apic->min, apic->div); + if(1||m->machno == 0 || DBGFLG){ + print("lapic%d: hz %lld max %lld min %lld div %lld tcc %.8llux\n", apicno, + apic->hz, apic->max, apic->min, apic->div, tcc); } /* --- /sys/src/fs/amd64/tiklock.c Thu Jan 1 00:00:00 1970 +++ /sys/src/fs/amd64/tiklock.c Mon Apr 14 07:15:28 2014 @@ -0,0 +1,415 @@ +#include "all.h" + +#define iprint(...) print(__VA_ARGS__) + +typedef struct Glares Glares; +typedef struct Glaring Glaring; + +struct Glaring +{ + Lock* l; + ulong ticks; + ulong lastlock; + uint key; + uintptr lpc; + uintptr pc; + uint n; + int ok; + int shown; +}; + +struct Glares +{ + Glaring instance[30]; + uint next; + uint total; +}; + +static Glares glares[MACHMAX]; /* per core, to avoid lock */ +static int lockdebug; +static uint spinbackoff; + +#define Thdb 1 +#define Ttlb 2 +#define Tmagicmask 0xff0000ff + +/* fixme; mechanism is broken */ +void +printlocks(User *up) +{ + int i; + + for(i = 0; i < up->nlock; i++){ + print("%#p:%#p", up->lstack[i], up->pstack[i]); + if((i%4) == 0) + print("\n"); + } + if(i>0 && i%4) + print("\n"); +} + +static void +dumpaproc(User *p) +{ + dotrace(p->pid); +} + +static int +tqisfree(u32int *key) +{ + uchar *p; + + p = (uchar *)key; + return (p[Ttlb]^p[Thdb]) == 0; +} + +/* increment tail and return the old value for user. */ +static int +tqtailinc(u32int *keyaddr) +{ + uchar *p; + + p = (uchar *)keyaddr; + return xaddb(&p[Ttlb]); +} + +/* increment head, releasing the lock for the next in line */ +static int +tqheadinc(uint *keyaddr) +{ + uchar *p; + + p = (uchar *)keyaddr; + return xaddb(&p[Thdb]); +} + +/* + * attempt to increment tail by one and maintain head + * such that tail == head + 1, indicating ownership. + */ +static int +tqcanlock(uint *keyaddr) +{ + u32int key, nkey; + uchar *tl; + + nkey = key = *keyaddr; + if(!tqisfree(&key)) + return 0; + tl = (uchar *)&nkey + Ttlb; + *tl += 1; + return cas32((u32int*)keyaddr, key, nkey); +} + +static uint +tqmagic(uint key) +{ + return key & Tmagicmask; +} + +static uint +tqhead(uint *key) +{ + uchar *p; + + p = (uchar *)key; + return p[Thdb]; +} + +static uint +tqtail(uint *key) +{ + uchar *p; + + p = (uchar *)key; + return p[Ttlb]; +} + +/* + * head and tail are really one byte wide, but uchar + * subtraction math isn't doing the right wrap + * delta calculation like uints do. + */ +static uint +tqdelta(uint tl, uint hd) +{ + if(tl >= hd) + return tl - hd; + return 0x100 - hd + tl; +} + +/* + * Return the page aligned key offset in the Lock. + */ +static void * +tqkey(Lock *l) +{ + uintptr key; + + key = ROUNDUP((uintptr)l, CACHELINESZ); + key += CACHELINESZ - sizeof (uint); + return (void*)key; +} + +void +showlockloops(void) +{ + int machno, i, p; + Glares *mg; + Glaring *g; + + p = 0; + for(machno = 0; machno < nelem(glares); machno++){ + mg = glares + machno; + for(i = 0; i < nelem(mg->instance); i++){ + g = mg->instance + i; + if(g->l == nil) + break; + if(!g->shown){ + g->shown = 0; + iprint("cpu%d: %d: l=%#p lpc=%#p pc=%#p n=%ud ok=%d\n", + machno, i, g->l, g->lpc, g->pc, g->n, g->ok); + } + p++; + } + } + if(p == 0) + iprint("no loops\n"); +} + +static void +lockcrash(Lock *l, uintptr pc, char *why) +{ + User *p; + + p = l->p; + if(lockdebug > 1){ + dumpaproc(u); + if(p != nil) + dumpaproc(p); + } + showlockloops(); + panic("cpu%d: %s lock %#p key %#p pc %#p proc %ud held by pc %#p proc %ud\n", + m->machno, why, l, tqkey(l), pc, u->pid, l->pc, p? p->pid: 0); +} + +/* + * A "lock loop" is excessive delay in obtaining a spin lock: + * it could be long delay through contention (ie, inefficient but harmless), + * or a real deadlock (a programming error); + * record them for later analysis to discover which. + * Don't print them at the time, or the harmless cases become deadly. + */ +static Glaring* +lockloop(Glaring *og, Lock *l, uintptr pc) +{ + int i; + Glares *mg; + Glaring *g; + Mpl s; + + s = splhi(); + if(l->m == MACHP(m->machno)) + lockcrash(l, pc, "deadlock/abandoned"); /* recovery is impossible */ + mg = &glares[m->machno]; + for(i = 0; i < nelem(mg->instance); i++){ + g = mg->instance + i; + if(g->l == nil) + break; + if(g->l == l && g->lpc == l->pc && g->pc == pc){ + g->ok = 0; + if(og == g){ + if((long)(Ticks - g->lastlock) >= 60*HZ) + lockcrash(l, pc, "stuck"); /* too long: we're doomed, i tell ye */ + }else{ + g->lastlock = Ticks; + g->n++; + g->shown = 0; + } + splx(s); + return g; + } + } + i = mg->next; + g = mg->instance + i; + g->ticks = Ticks; + g->lastlock = g->ticks; + g->l = l; + g->pc = pc; + g->lpc = l->pc; + g->n = 1; + g->ok = 0; + g->shown = 0; + if(++i >= nelem(mg->instance)) + i = 0; + mg->next = i; + mg->total++; + splx(s); + if(islo() && u != nil) + print("cpu%d: pid %d slow locks: %d\n", m->machno, u->pid, glares[m->machno].total); + if(lockdebug) + lockcrash(l, pc, "stuck"); + return g; +} + +static int +lock0(Lock *l, uintptr pc) +{ + int i, j; + uint mytl, hd, n, *key, ct; + Glaring *g; + + key = tqkey(l); + i = 0; + g = nil; + mytl = tqtailinc(key); + hd = tqhead(key); + if(hd == mytl) + goto out; +// if(kproflock) +// kproflock(pc); + for (;; i++) { + n = tqdelta(mytl, hd) - 1; + for (j = 0; j < spinbackoff*n; j++) + ; + if(i > 100*1000*1000) { + g = lockloop(g, l, pc); + i = 0; + } + lfence(); + ct = *key; + hd = tqhead(&ct); + if(hd == mytl) + break; + if(tqmagic(ct) != 0) { + for(;;){ + iprint("lock miskey %ud pc %#p->%#p\n", + ct, pc, l->pc); + hexdump(l, 64); + delay(5000); + } + } + } +out: + l->pc = pc; + l->p = u; + l->isilock = 0; + l->m = MACHP(m->machno); + if(g != nil) + g->ok = 1; /* recovered */ + return i > 0; +} + +int +lockpc(Lock *l, uintptr pc) +{ + int n; + + if(u != nil) + u->nlock++; + n = lock0(l, pc); +// if(u != nil) +// u->lastlock = l; + return n; +} + +void +lock(Lock *l) +{ + lockpc(l, getcallerpc(&l)); +} + +void +ilockpc(Lock *l, uintptr pc) +{ + Mpl s; + + s = splhi(); + lock0(l, pc); +// if(u != nil) +// u->lastilock = l; +// m->ilockdepth++; + l->isilock = 1; + l->sr = s; +} + +void +ilock(Lock *l) +{ + ilockpc(l, getcallerpc(&l)); +} + +int +canlock(Lock *l) +{ + uintptr pc; + + pc = getcallerpc(&l); + + if(u != nil) + u->nlock++; + if(tqcanlock(tqkey(l)) == 0) { + if(u != nil) + u->nlock--; + return 0; + } + l->pc = pc; + l->p = u; + l->m = MACHP(m->machno); + l->isilock = 0; + return 1; +} + +static void +unlock0(Lock *l, uintptr pc) +{ + uint *key; + + key = tqkey(l); + if(tqisfree(key)) + panic("unlock: not locked: pc %#p\n", pc); + if(l->isilock) + panic("unlock of ilock: pc %#p, held by %#p\n", pc, l->pc); + if(l->p != u) + panic("unlock: u changed: pc %#p, acquired at pc %#p, lock p %#p, unlock u %#p\n", pc, l->pc, l->p, u); + l->m = nil; + l->p = nil; + coherence(); + tqheadinc(key); +} + +void +unlock(Lock *l) +{ + uintptr pc; + + pc = getcallerpc(&l); + unlock0(l, pc); + if(u && --u->nlock == 0 && u->delaysched && islo()) { + /* + * Call sched if the need arose while locks were held + * But, don't do it from interrupt routines, hence the islo() test + */ + sched(); + } +} + +void +iunlock(Lock *l) +{ + uintptr pc; + Mpl s; + + pc = getcallerpc(&l); + if(!l->isilock) + panic("iunlock of lock: pc %#p, held by %#p\n", pc, l->pc); + if(islo()) + panic("iunlock while lo: pc %#p, held by %#p\n", pc, l->pc); + l->isilock = 0; + s = l->sr; + unlock0(l, pc); +// m->ilockdepth--; +// if(up) +// up->lastilock = nil; + splx(s); +}