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