cmpxchg.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #pragma once
  2. #include <common/compiler.h>
  3. #include <arch/x86_64/asm/asm.h>
  4. /**
  5. * @brief 通过extern不存在的函数,来让编译器报错。以防止不符合要求的代码的产生。
  6. */
  7. extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size for cmpxchg");
  8. // 定义常量:操作符涉及到的字节数
  9. #define __X86_CASE_B 1
  10. #define __X86_CASE_W 2
  11. #define __X86_CASE_L 4
  12. #define __X86_CASE_Q 8
  13. /**
  14. * @brief lock cmpxchg指令的包装。
  15. * 将_ptr指向的值与old_ptr指向的值做比较,如果相等,则将_new指向的值,加载到_ptr指向的值中。
  16. */
  17. #define __raw_try_cmpxchg(_ptr, _old_ptr, _new, size) \
  18. ({ \
  19. bool is_success = false; \
  20. typeof(_ptr) _old = (typeof(_ptr))(_old_ptr); \
  21. typeof(*(_ptr)) __old = *_old; \
  22. typeof(*(_ptr)) __new = (_new); \
  23. switch (size) \
  24. { \
  25. case __X86_CASE_B: \
  26. { \
  27. volatile uint8_t *__ptr = (volatile uint8_t *)(_ptr); \
  28. asm volatile("lock cmpxchgb %[new], %[ptr]\n\t" \
  29. : CC_OUT(z)(is_success), \
  30. [ptr] "+m"(*__ptr), \
  31. [old] "+a"(__old) \
  32. : [new] "q"(__new) \
  33. : "memory"); \
  34. break; \
  35. } \
  36. case __X86_CASE_W: \
  37. { \
  38. volatile uint16_t *__ptr = (volatile uint16_t *)(_ptr); \
  39. asm volatile("lock cmpxchgw %[new], %[ptr]\n\t" \
  40. : CC_OUT(z)(is_success), \
  41. [ptr] "+m"(*__ptr), \
  42. [old] "+a"(__old) \
  43. : [new] "q"(__new) \
  44. : "memory"); \
  45. break; \
  46. } \
  47. case __X86_CASE_L: \
  48. { \
  49. volatile uint32_t *__ptr = (volatile uint32_t *)(_ptr); \
  50. asm volatile("lock cmpxchgl %[new], %[ptr]\n\t" \
  51. : CC_OUT(z)(is_success), \
  52. [ptr] "+m"(*__ptr), \
  53. [old] "+a"(__old) \
  54. : [new] "q"(__new) \
  55. : "memory"); \
  56. break; \
  57. } \
  58. case __X86_CASE_Q: \
  59. { \
  60. volatile uint64_t *__ptr = (volatile uint64_t *)(_ptr); \
  61. asm volatile("lock cmpxchgq %[new], %[ptr]\n\t" \
  62. : CC_OUT(z)(is_success), \
  63. [ptr] "+m"(*__ptr), \
  64. [old] "+a"(__old) \
  65. : [new] "q"(__new) \
  66. : "memory"); \
  67. break; \
  68. } \
  69. default: \
  70. __cmpxchg_wrong_size(); \
  71. } \
  72. if (unlikely(is_success == false)) \
  73. *_old = __old; \
  74. likely(is_success); \
  75. })
  76. #define arch_try_cmpxchg(ptr, old_ptr, new_ptr) \
  77. __raw_try_cmpxchg((ptr), (old_ptr), (new_ptr), sizeof(*ptr))