1/* @title: Raw Spinlock */
2#pragma once
3#include <asm.h>
4#include <compiler.h>
5#include <stdatomic.h>
6#include <stdbool.h>
7#include <stdint.h>
8
9struct raw_spinlock {
10 _Atomic uint8_t state;
11};
12
13#define RAW_SPINLOCK_INIT ((struct raw_spinlock) {.state = ATOMIC_VAR_INIT(0)})
14#define RAW_SPINLOCK_DEFINE(id) struct raw_spinlock id = RAW_SPINLOCK_INIT
15
16static inline void raw_spinlock_init(struct raw_spinlock *lock) {
17 atomic_store_explicit(&lock->state, 0, memory_order_relaxed);
18}
19
20static inline bool __warn_unused_result
21raw_spin_trylock(struct raw_spinlock *lock) {
22 uint8_t expected = 0;
23 return atomic_compare_exchange_strong_explicit(
24 &lock->state, &expected, 1, memory_order_acquire, memory_order_relaxed);
25}
26
27static inline void raw_spin_lock(struct raw_spinlock *lock) {
28 while (true) {
29 if (raw_spin_trylock(lock))
30 return;
31
32 while (atomic_load_explicit(&lock->state, memory_order_relaxed) != 0)
33 cpu_relax();
34 }
35}
36
37static inline void raw_spin_unlock(struct raw_spinlock *lock) {
38 atomic_store_explicit(&lock->state, 0, memory_order_release);
39}
40
41/* whether interrupts were enabled on entry */
42static inline bool __warn_unused_result
43raw_spin_lock_irq_disable(struct raw_spinlock *lock) {
44 bool irqs_were_enabled = are_interrupts_enabled();
45 disable_interrupts();
46 raw_spin_lock(lock);
47 return irqs_were_enabled;
48}
49
50static inline void raw_spin_unlock_irq_restore(struct raw_spinlock *lock,
51 bool irqs_were_enabled) {
52 raw_spin_unlock(lock);
53 if (irqs_were_enabled)
54 enable_interrupts();
55}
56