void lock_acquire(struct lock *lock) { if(!lock_do_i_hold(lock)) { spinlock_acquire(&lock->spin_lock); while(spinlock_data_testandset(&lock->lk_busy) != 0) { wchan_sleep(lock->lk_wchan, &lock->spin_lock); } lock->lk_cpu = curcpu; lock->lk_thread = curthread; spinlock_release(&lock->spin_lock); } }
/* * Get the lock. * * First disable interrupts (otherwise, if we get a timer interrupt we * might come back to this lock and deadlock), then use a machine-level * atomic operation to wait for the lock to be free. */ void spinlock_acquire(struct spinlock *lk) { struct cpu *mycpu; splraise(IPL_NONE, IPL_HIGH); /* this must work before curcpu initialization */ if (CURCPU_EXISTS()) { mycpu = curcpu->c_self; if (lk->lk_holder == mycpu) { panic("Deadlock on spinlock %p\n", lk); } } else { mycpu = NULL; } while (1) { /* * Do test-test-and-set, that is, read first before * doing test-and-set, to reduce bus contention. * * Test-and-set is a machine-level atomic operation * that writes 1 into the lock word and returns the * previous value. If that value was 0, the lock was * previously unheld and we now own it. If it was 1, * we don't. */ if (spinlock_data_get(&lk->lk_lock) != 0) { continue; } if (spinlock_data_testandset(&lk->lk_lock) != 0) { continue; } break; } lk->lk_holder = mycpu; }