#include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "io.h" #include "mem.h" void lock(Lock *l) { int i; ulong caller; caller = getcallerpc(&l); /* * Try the fast grab first */ loop: if(tas(l) == 0) { l->pc = caller; return; } for(i = 0; i < 1000000; i++) { if(tas(l) == 0) { l->pc = caller; return; } /* If we are spl low resched */ if(getstatus() & IFLAG) sched(); } l->sbsem = 0; print("lock loop 0x%lux called by 0x%lux held by pc 0x%lux\n", (ulong)l, caller, l->pc); goto loop; } void ilock(Lock *l) { l->sr = splhi(); lock(l); } void iunlock(Lock *l) { ulong sr; sr = l->sr; l->sbsem = 0; l->pc = 0; splx(sr); } int canlock(Lock *l) { if (tas(l) == 0) return 1; return 0; } void unlock(Lock *l) { l->pc = 0; l->sbsem = 0; } void qlock(QLock *q) { User *p; int i; lock(q); if(!q->locked){ q->locked = 1; unlock(q); goto out; } if(1 && u) { for(i=0; ihas.q[i] == q) { print("circular qlock by %d at 0x%lux (other 0x%lux, 0x%lux)\n", u->pid, getcallerpc(&q), u->has.pc[i], q->pc); dumpstack(u); break; } } p = q->tail; if(p == 0) q->head = u; else p->qnext = u; q->tail = u; u->qnext = 0; u->state = Queueing; u->has.want = q; unlock(q); sched(); u->has.want = 0; out: if(1 && u) { for(i=0; ihas.q[i] == 0) { u->has.q[i] = q; u->has.pc[i] = getcallerpc(&q); return; } print("NHAS(%d) too small\n", NHAS); } } int canqlock(QLock *q) { int i; lock(q); if(q->locked){ unlock(q); return 0; } q->locked = 1; unlock(q); if(1 && u) { for(i=0; ihas.q[i] == 0) { u->has.q[i] = q; u->has.pc[i] = getcallerpc(&q); return 1; } print("NHAS(%d) too small\n", NHAS); } return 1; } void qunlock(QLock *q) { User *p; int i; lock(q); p = q->head; if(p) { q->head = p->qnext; if(q->head == 0) q->tail = 0; unlock(q); ready(p); } else { q->locked = 0; unlock(q); } if(1 && u) { for(i=0; ihas.q[i] == q) { u->has.q[i] = 0; return; } panic("qunlock: not there %lux, called from %lux\n", (ulong)q, getcallerpc(&q)); } } /* * readers/writers lock * allows 1 writer or many readers */ void rlock(RWlock *l) { QLock *q; qlock(&l->wr); /* wait here for writers and exclusion */ q = &l->rd; /* first reader in, qlock(&l->rd) */ lock(q); q->locked = 1; l->nread++; unlock(q); qunlock(&l->wr); if(1 && u) { int i; int found; found = 0; for(i=0; ihas.q[i] == q){ print("circular rlock by %d at 0x%lux (other 0x%lux)\n", u->pid, getcallerpc(&l), u->has.pc[i]); dumpstack(u); } if(!found && u->has.q[i] == 0) { u->has.q[i] = q; u->has.pc[i] = getcallerpc(&l); found = 1; } } if(!found) print("NHAS(%d) too small\n", NHAS); } } void runlock(RWlock *l) { QLock *q; User *p; int n; q = &l->rd; lock(q); n = l->nread - 1; l->nread = n; if(n == 0) { /* last reader out, qunlock(&l->rd) */ p = q->head; if(p) { q->head = p->qnext; if(q->head == 0) q->tail = 0; unlock(q); ready(p); goto accounting; } q->locked = 0; } unlock(q); accounting: if(1 && u) { int i; for(i=0; ihas.q[i] == q) { u->has.q[i] = 0; return; } panic("runlock: not there %lux, called from %lux\n", (ulong)q, getcallerpc(&l)); } } void wlock(RWlock *l) { qlock(&l->wr); /* wait here for writers and exclusion */ qlock(&l->rd); /* wait here for last reader */ } void wunlock(RWlock *l) { qunlock(&l->rd); qunlock(&l->wr); }