xref: /DragonOS/kernel/src/common/spinlock.h (revision 2813126e3190c9b3c1a836a647b259a7adbe0cf3)
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 <common/glib.h>
13 #include <process/preempt.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 /**
26  * @brief 自旋锁加锁
27  *
28  * @param lock
29  */
30 void spin_lock(spinlock_t *lock)
31 {
32     __asm__ __volatile__("1:    \n\t"
33                          "lock decb %0   \n\t" // 尝试-1
34                          "jns 3f    \n\t"      // 加锁成功,跳转到步骤3
35                          "2:    \n\t"          // 加锁失败,稍后再试
36                          "pause \n\t"
37                          "cmpb $0, %0   \n\t"
38                          "jle   2b  \n\t" // 若锁被占用,则继续重试
39                          "jmp 1b    \n\t" // 尝试加锁
40                          "3:"
41                          : "=m"(lock->lock)::"memory");
42     preempt_disable();
43 }
44 
45 /**
46  * @brief 自旋锁解锁
47  *
48  * @param lock
49  */
50 void spin_unlock(spinlock_t *lock)
51 {
52     preempt_enable();
53     __asm__ __volatile__("movb $1, %0   \n\t"
54                          : "=m"(lock->lock)::"memory");
55 }
56 
57 /**
58  * @brief 初始化自旋锁
59  *
60  * @param lock
61  */
62 void spin_init(spinlock_t *lock)
63 {
64     barrier();
65     lock->lock = 1;
66     barrier();
67 }
68 
69 /**
70  * @brief 自旋锁加锁(不改变自旋锁持有计数)
71  *
72  * @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误
73  */
74 void spin_lock_no_preempt(spinlock_t *lock)
75 {
76     __asm__ __volatile__("1:    \n\t"
77                          "lock decb %0   \n\t" // 尝试-1
78                          "jns 3f    \n\t"      // 加锁成功,跳转到步骤3
79                          "2:    \n\t"          // 加锁失败,稍后再试
80                          "pause \n\t"
81                          "cmpb $0, %0   \n\t"
82                          "jle   2b  \n\t" // 若锁被占用,则继续重试
83                          "jmp 1b    \n\t" // 尝试加锁
84                          "3:"
85                          : "=m"(lock->lock)::"memory");
86 }
87 /**
88  * @brief 自旋锁解锁(不改变自旋锁持有计数)
89  *
90  * @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误
91  */
92 void spin_unlock_no_preempt(spinlock_t *lock)
93 {
94     __asm__ __volatile__("movb $1, %0   \n\t"
95                          : "=m"(lock->lock)::"memory");
96 }
97 
98 /**
99  * @brief 尝试加锁
100  *
101  * @param lock
102  * @return long 锁变量的值(1为成功加锁,0为加锁失败)
103  */
104 long spin_trylock(spinlock_t *lock)
105 {
106     uint64_t tmp_val = 0;
107     preempt_disable();
108     // 交换tmp_val和lock的值,若tmp_val==1则证明加锁成功
109     asm volatile("lock xchg %%bx, %1  \n\t" // 确保只有1个进程能得到锁
110                  : "=q"(tmp_val), "=m"(lock->lock)
111                  : "b"(0)
112                  : "memory");
113     if (!tmp_val)
114         preempt_enable();
115     return tmp_val;
116 }
117 
118 // 保存当前rflags的值到变量x内并关闭中断
119 #define local_irq_save(x) __asm__ __volatile__("pushfq ; popq %0 ; cli" \
120                                                : "=g"(x)::"memory")
121 // 恢复先前保存的rflags的值x
122 #define local_irq_restore(x) __asm__ __volatile__("pushq %0 ; popfq" ::"g"(x) \
123                                                   : "memory")
124 #define local_irq_disable() cli();
125 #define local_irq_enable() sti();
126 
127 /**
128  * @brief 保存中断状态,关闭中断,并自旋锁加锁
129  *
130  */
131 #define spin_lock_irqsave(lock, flags) \
132     do                                 \
133     {                                  \
134         local_irq_save(flags);         \
135         spin_lock(lock);               \
136     } while (0)
137 
138 /**
139  * @brief 恢复rflags以及中断状态并解锁自旋锁
140  *
141  */
142 #define spin_unlock_irqrestore(lock, flags) \
143     do                                      \
144     {                                       \
145         spin_unlock(lock);                  \
146         local_irq_restore(flags);           \
147     } while (0)
148 
149 /**
150  * @brief 关闭中断并加锁
151  *
152  */
153 #define spin_lock_irq(lock)  \
154     do                       \
155     {                        \
156         local_irq_disable(); \
157         spin_lock(lock);     \
158     } while (0)
159 
160 /**
161  * @brief 解锁并开启中断
162  *
163  */
164 #define spin_unlock_irq(lock) \
165     do                        \
166     {                         \
167         spin_unlock(lock);    \
168         local_irq_enable();   \
169     } while (0)
170 
171 /**
172  * @brief 判断自旋锁是否已经加锁
173  *
174  * @param lock 待判断的自旋锁
175  * @return true 已经加锁
176  * @return false 尚未加锁
177  */
178 static inline bool spin_is_locked(const spinlock_t *lock)
179 {
180     int x = READ_ONCE(lock->lock);
181     return (x == 0) ? true : false;
182 }
183 
184 #define assert_spin_locked(lock) BUG_ON(!spin_is_locked(lock))