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))