#include "types.h" #include "defs.h" #include "param.h" #include "x86.h" #include "memlayout.h" #include "mmu.h" #include "proc.h" #include "spinlock.h" void initlock(struct spinlock *lk, char *name) { lk->name = name; lk->locked = 0; lk->cpu = 0; } void acquire(struct spinlock *lk) { pushcli(); if(holding(lk)) panic("acquire"); { uint64 spins = 0; while(xchg(&lk->locked, 1) != 0){ if(++spins == 200000000ULL){ cprintf("acquire: stuck on \"%s\" held by cpu=%p pcs0=%p pcs1=%p pcs2=%p, acquirer cpu=%p\n", lk->name, lk->cpu, lk->pcs[0], lk->pcs[1], lk->pcs[2], mycpu()); panic("acquire: deadlock"); } } } __sync_synchronize(); lk->cpu = mycpu(); getcallerpcs(&lk, lk->pcs); } void release(struct spinlock *lk) { if(!holding(lk)) panic("release"); lk->pcs[0] = 0; lk->cpu = 0; __sync_synchronize(); asm volatile("movq $0, %0" : "+m" (lk->locked) : ); popcli(); } void getcallerpcs(void *v, addr_t pcs[]) { addr_t *rbp; asm volatile("mov %%rbp, %0" : "=r" (rbp)); getstackpcs(rbp, pcs); } void getstackpcs(addr_t *rbp, addr_t pcs[]) { int i; for(i = 0; i < 10; i++){ if(rbp == 0 || rbp < (addr_t*)KERNBASE || rbp == (addr_t*)0xffffffff) break; pcs[i] = rbp[1]; rbp = (addr_t*)rbp[0]; } for(; i < 10; i++) pcs[i] = 0; } int holding(struct spinlock *lock) { return lock->locked && lock->cpu == mycpu(); } void pushcli(void) { int eflags; eflags = readeflags(); cli(); if(mycpu() == 0){ extern uint64 kernel_fs_base; cprintf("pushcli: cpu==NULL cs=0x%p kernel_fs_base=0x%p actual_fs_base=0x%p\n", readcs(), kernel_fs_base, rdmsr(0xC0000100)); panic("pushcli: cpu is NULL"); } if(mycpu()->ncli == 0) mycpu()->intena = eflags & FL_IF; mycpu()->ncli += 1; } void popcli(void) { if(readeflags()&FL_IF) panic("popcli - interruptible"); if(--mycpu()->ncli < 0) panic("popcli"); if(mycpu()->ncli == 0 && mycpu()->intena) sti(); }