/* * This file implements spinlocks. It makes heavy use of GCC's atomic built-ins * for syncronisation. The spinlocks have some simple mechanisms for preventing * deadlocks. Each spinlock knowns which CPU/task is holding it, and can allow * that CPU/task to acquire it multiple times and safely release it. */ #include #include #include /* Check if already holding */ static inline int holding(Spinlock *lock) { return (lock->locked && lock->owner == current); } /* Initialise a lock */ void init_lock(Spinlock *lock) { lock->locked = 0; lock->usage = 0; } /* Acquire a lock */ void acquire(Spinlock *lock) { if (!holding(lock)) { while (__atomic_test_and_set(&lock->locked, __ATOMIC_ACQUIRE)) asm volatile("pause"); lock->owner = current; } __atomic_add_fetch(&lock->usage, 1, __ATOMIC_RELAXED); } /* Release a lock */ void release(Spinlock *lock) { ASSERT(holding(lock)); if (!__atomic_sub_fetch(&lock->usage, 1, __ATOMIC_RELAXED)) { __atomic_clear(&lock->locked, __ATOMIC_RELEASE); lock->owner = NULL; } }