#include "spinlock.h"

void spinlock_init(spinlock_t *lock) {
    atomic_flag_clear(&lock->flag);
}

void spinlock_acquire_or_wait(spinlock_t *lock) {
    while (atomic_flag_test_and_set_explicit(&lock->flag, memory_order_acquire))
        asm volatile("pause" ::: "memory");
}

void spinlock_drop(spinlock_t *lock) {
    atomic_flag_clear_explicit(&lock->flag, memory_order_release);
}

void spinlock_acquire_irqsave(spinlock_t *lock, uint64_t *flags) {
    uint64_t f;
    asm volatile("pushfq; pop %0; cli" : "=r"(f) :: "memory");
    *flags = f;
    spinlock_acquire_or_wait(lock);
}

void spinlock_release_irqrestore(spinlock_t *lock, uint64_t flags) {
    spinlock_drop(lock);
    asm volatile("push %0; popfq" :: "r"(flags) : "memory", "cc");
}