My Kernel v0.1.0
spinlock.h
1#pragma once
2
9#include <kernel/cpu.h>
10#include <kernel/types.h>
11
12#ifdef CONFIG_SPINLOCK_DEBUG
13#include <kernel/logger.h>
14#include <kernel/timer.h>
15#endif
16
17#include <utils/compiler.h>
18#include <utils/macro.h>
19
20#include <stdbool.h>
21
22/* Default timeout: 30s */
23#define SPINLOCK_DEBUG_STALL_TIMEOUT MS(30)
24
29typedef struct spinlock {
30 bool locked;
31#ifdef SPINLOCK_DEBUG
33 vaddr_t owner;
34#endif
36
38#define __SPINLOCK_INIT \
39 { \
40 .locked = false \
41 }
42#define SPINLOCK_INIT ((spinlock_t)__SPINLOCK_INIT)
43
45#define __INIT_SPINLOCK(_lock) _lock = __SPINLOCK_INIT
46#define INIT_SPINLOCK(_lock) _lock = SPINLOCK_INIT
47
49#define DECLARE_SPINLOCK(_lock) spinlock_t _lock = SPINLOCK_INIT
50
51#ifdef CONFIG_SPINLOCK_DEBUG
52
54static ALWAYS_INLINE spinlock_t *
55__spinlock_acquire(spinlock_t *lock, vaddr_t owner)
56{
57 time_t start = timer_get_ms();
58
59 while (__atomic_test_and_set(&lock->locked, __ATOMIC_ACQUIRE)) {
60 if (timer_get_ms() - start > SPINLOCK_DEBUG_STALL_TIMEOUT) {
61 WARN("stall detected on spinlock (owner: %ps)",
62 (void *)lock->owner);
63 start = timer_get_ms();
64 }
65 }
66
67 lock->owner = owner;
68
69 return lock;
70}
71
72#else
73
75static ALWAYS_INLINE spinlock_t *
76__spinlock_acquire(spinlock_t *lock, vaddr_t owner)
77{
78 UNUSED(owner);
79
80 WAIT_FOR(!__atomic_test_and_set(&lock->locked, __ATOMIC_ACQUIRE));
81
82 return lock;
83}
84
85#endif
86
87#define spinlock_acquire(lock) __spinlock_acquire(lock, __THIS_IP)
88
90static ALWAYS_INLINE void spinlock_release(spinlock_t *lock)
91{
92 __atomic_clear(&lock->locked, __ATOMIC_RELEASE);
93}
94
95typedef struct {
96 spinlock_t *lock;
97 bool done;
98} scope_lock_t;
99
100static inline scope_lock_t scope_lock_constructor(spinlock_t *lock)
101{
102 return (scope_lock_t){
103 .lock = __spinlock_acquire(lock, __RET_IP),
104 .done = false,
105 };
106}
107
108static inline void scope_lock_destructor(scope_lock_t *guard)
109{
110 spinlock_release(guard->lock);
111}
112
129#define locked_scope(_lock) \
130 for (scope_lock_t guard CLEANUP(scope_lock_destructor) = \
131 scope_lock_constructor(_lock); \
132 !guard.done; guard.done = true)
static ALWAYS_INLINE spinlock_t * __spinlock_acquire(spinlock_t *lock, vaddr_t owner)
Try to acquire a spinlock, or wait until it is free.
Definition: spinlock.h:76
static ALWAYS_INLINE void spinlock_release(spinlock_t *lock)
Release a spinlock for others to take it.
Definition: spinlock.h:90
static time_t timer_get_ms(void)
Definition: timer.h:77
#define WAIT_FOR(_cond)
Loop infinitely while the condition _cond is not met.
Definition: macro.h:15
#define UNUSED(_x)
Avoid compiler warning when not using a symbol.
Definition: macro.h:35
Spinlock.
Definition: spinlock.h:29