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