spinlock.h 4.8 KB

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