// Copyright (c) 2023-2026 Chris (boreddevnl) // This software is released under the GNU General Public License v3.0. See LICENSE file for details. // This header needs to maintain in any file it is present in, as per the GPL license terms. #ifndef SPINLOCK_H #define SPINLOCK_H #include // Simple test-and-set spinlock for x86_64 SMP. // Uses 'lock xchg' for acquire and a plain store for release. // Includes 'pause' to reduce bus contention while spinning. typedef volatile uint32_t spinlock_t; #define SPINLOCK_INIT 0 static inline void spinlock_acquire(spinlock_t *lock) { while (1) { // Try to set the lock from 0 -> 1 uint32_t prev; asm volatile("lock xchgl %0, %1" : "=r"(prev), "+m"(*lock) : "0"((uint32_t)1) : "memory"); if (prev == 0) return; // We got the lock // Spin with pause (reduces power and bus traffic) while (*lock) { asm volatile("pause" ::: "memory"); } } } static inline void spinlock_release(spinlock_t *lock) { asm volatile("" ::: "memory"); // compiler barrier *lock = 0; } // Try to acquire without blocking. Returns 1 if acquired, 0 if not. static inline int spinlock_try(spinlock_t *lock) { uint32_t prev; asm volatile("lock xchgl %0, %1" : "=r"(prev), "+m"(*lock) : "0"((uint32_t)1) : "memory"); return (prev == 0); } // IRQ-safe spinlock: saves flags, disables interrupts, then acquires. // Use when the lock may be contended from interrupt context. 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"); } #endif