spinlock.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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. void spin_unlock(spinlock_t *lock)
  51. {
  52. preempt_enable();
  53. __asm__ __volatile__("movq $1, %0 \n\t"
  54. : "=m"(lock->lock)::"memory");
  55. }
  56. /**
  57. * @brief 尝试加锁
  58. *
  59. * @param lock
  60. * @return long 锁变量的值(1为成功加锁,0为加锁失败)
  61. */
  62. long spin_trylock(spinlock_t *lock)
  63. {
  64. uint64_t tmp_val = 0;
  65. preempt_disable();
  66. // 交换tmp_val和lock的值,若tmp_val==1则证明加锁成功
  67. asm volatile("lock xchgq %0, %1 \n\t" // 确保只有1个进程能得到锁
  68. : "=q"(tmp_val), "=m"(lock->lock)
  69. : "0"(0)
  70. : "memory");
  71. if (!tmp_val)
  72. preempt_enable();
  73. return tmp_val;
  74. }
  75. // 保存当前rflags的值到变量x内并关闭中断
  76. #define local_irq_save(x) __asm__ __volatile__("pushfq ; popq %0 ; cli" \
  77. : "=g"(x)::"memory")
  78. // 恢复先前保存的rflags的值x
  79. #define local_irq_restore(x) __asm__ __volatile__("pushq %0 ; popfq" ::"g"(x) \
  80. : "memory")
  81. #define local_irq_disable() cli();
  82. #define local_irq_enable() sti();
  83. /**
  84. * @brief 保存中断状态,关闭中断,并自旋锁加锁
  85. *
  86. */
  87. #define spin_lock_irqsave(lock, flags) \
  88. do \
  89. { \
  90. local_irq_save(flags); \
  91. spin_lock(lock); \
  92. } while (0)
  93. /**
  94. * @brief 恢复rflags以及中断状态并解锁自旋锁
  95. *
  96. */
  97. #define spin_unlock_irqrestore(lock, flags) \
  98. do \
  99. { \
  100. spin_unlock(lock); \
  101. local_irq_restore(flags); \
  102. } while (0)
  103. /**
  104. * @brief 关闭中断并加锁
  105. *
  106. */
  107. #define spin_lock_irq(lock) \
  108. do \
  109. { \
  110. local_irq_disable(); \
  111. spin_lock(lock); \
  112. } while (0)
  113. /**
  114. * @brief 解锁并开启中断
  115. *
  116. */
  117. #define spin_unlock_irq(lock) \
  118. do \
  119. { \
  120. spin_unlock(lock); \
  121. local_irq_enable(); \
  122. } while (0)