spinlock.h 4.4 KB

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