spinlock.h 4.4 KB

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