#ifndef SPINLOCK_H #define SPINLOCK_H #include typedef struct { volatile uint32_t ticket; volatile uint32_t serving; } spinlock_t; #define SPINLOCK_INIT { .ticket = 0, .serving = 0 } static inline void spinlock_acquire(spinlock_t* lock) { uint32_t my_ticket = __atomic_fetch_add(&lock->ticket, 1, __ATOMIC_RELAXED); while (__atomic_load_n(&lock->serving, __ATOMIC_ACQUIRE) != my_ticket) asm volatile("pause"); } static inline void spinlock_release(spinlock_t* lock) { __atomic_fetch_add(&lock->serving, 1, __ATOMIC_RELEASE); } static inline int spinlock_try_acquire(spinlock_t* lock) { uint32_t serving = __atomic_load_n(&lock->serving, __ATOMIC_RELAXED); uint32_t ticket = __atomic_load_n(&lock->ticket, __ATOMIC_RELAXED); if (serving != ticket) return 0; uint32_t expected = serving; return __atomic_compare_exchange_n(&lock->ticket, &expected, serving + 1, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); } static inline uint64_t spinlock_acquire_irqsave(spinlock_t* lock) { uint64_t flags; asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory"); spinlock_acquire(lock); return flags; } static inline void spinlock_release_irqrestore(spinlock_t* lock, uint64_t flags) { spinlock_release(lock); asm volatile("push %0; popfq" :: "r"(flags) : "memory", "cc"); } #endif