1 /**
2  * @file spinlock.h
3  * @author fslongjin (longjin@RinGoTek.cn)
4  * @brief 自旋锁
5  * @version 0.1
6  * @date 2022-04-07
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 #pragma once
12 #include <asm/irqflags.h>
13 #include <common/glib.h>
14 #include <debug/bug.h>
15 
16 /**
17  * @brief 定义自旋锁结构体
18  *
19  */
20 typedef struct
21 {
22     int8_t lock; // 1:unlocked 0:locked
23 } spinlock_t;
24 
25 extern void __arch_spin_lock(spinlock_t *lock);
26 extern void __arch_spin_unlock(spinlock_t *lock);
27 
28 extern void __arch_spin_lock_no_preempt(spinlock_t *lock);
29 extern void __arch_spin_unlock_no_preempt(spinlock_t *lock);
30 
31 extern long __arch_spin_trylock(spinlock_t *lock);
32 
33 /**
34  * @brief 自旋锁加锁
35  *
36  * @param lock
37  */
spin_lock(spinlock_t * lock)38 void spin_lock(spinlock_t *lock)
39 {
40     __arch_spin_lock(lock);
41 }
42 
43 /**
44  * @brief 自旋锁解锁
45  *
46  * @param lock
47  */
spin_unlock(spinlock_t * lock)48 void spin_unlock(spinlock_t *lock)
49 {
50     __arch_spin_unlock(lock);
51 }
52 
53 /**
54  * @brief 初始化自旋锁
55  *
56  * @param lock
57  */
spin_init(spinlock_t * lock)58 void spin_init(spinlock_t *lock)
59 {
60     barrier();
61     lock->lock = 1;
62     barrier();
63 }
64 
65 /**
66  * @brief 自旋锁加锁(不改变自旋锁持有计数)
67  *
68  * @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误
69  */
spin_lock_no_preempt(spinlock_t * lock)70 void spin_lock_no_preempt(spinlock_t *lock)
71 {
72     __arch_spin_lock_no_preempt(lock);
73 }
74 
75 /**
76  * @brief 自旋锁解锁(不改变自旋锁持有计数)
77  *
78  * @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误
79  */
spin_unlock_no_preempt(spinlock_t * lock)80 void spin_unlock_no_preempt(spinlock_t *lock)
81 {
82     __arch_spin_unlock_no_preempt(lock);
83 }
84 
85 /**
86  * @brief 尝试加锁
87  *
88  * @param lock
89  * @return long 锁变量的值(1为成功加锁,0为加锁失败)
90  */
spin_trylock(spinlock_t * lock)91 long spin_trylock(spinlock_t *lock)
92 {
93     return __arch_spin_trylock(lock);
94 }
95 
96 /**
97  * @brief 保存中断状态,关闭中断,并自旋锁加锁
98  *
99  */
100 #define spin_lock_irqsave(lock, flags)                                                                                 \
101     do                                                                                                                 \
102     {                                                                                                                  \
103         local_irq_save(flags);                                                                                         \
104         spin_lock(lock);                                                                                               \
105     } while (0)
106 
107 /**
108  * @brief 恢复rflags以及中断状态并解锁自旋锁
109  *
110  */
111 #define spin_unlock_irqrestore(lock, flags)                                                                            \
112     do                                                                                                                 \
113     {                                                                                                                  \
114         spin_unlock(lock);                                                                                             \
115         local_irq_restore(flags);                                                                                      \
116     } while (0)
117 
118 /**
119  * @brief 关闭中断并加锁
120  *
121  */
122 #define spin_lock_irq(lock)                                                                                            \
123     do                                                                                                                 \
124     {                                                                                                                  \
125         local_irq_disable();                                                                                           \
126         spin_lock(lock);                                                                                               \
127     } while (0)
128 
129 /**
130  * @brief 解锁并开启中断
131  *
132  */
133 #define spin_unlock_irq(lock)                                                                                          \
134     do                                                                                                                 \
135     {                                                                                                                  \
136         spin_unlock(lock);                                                                                             \
137         local_irq_enable();                                                                                            \
138     } while (0)
139 
140 /**
141  * @brief 判断自旋锁是否已经加锁
142  *
143  * @param lock 待判断的自旋锁
144  * @return true 已经加锁
145  * @return false 尚未加锁
146  */
spin_is_locked(const spinlock_t * lock)147 static inline bool spin_is_locked(const spinlock_t *lock)
148 {
149     int x = READ_ONCE(lock->lock);
150     return (x == 0) ? true : false;
151 }
152 
153 #define assert_spin_locked(lock) BUG_ON(!spin_is_locked(lock))