bpf_atomic.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
  3. #ifndef BPF_ATOMIC_H
  4. #define BPF_ATOMIC_H
  5. #include <vmlinux.h>
  6. #include <bpf/bpf_helpers.h>
  7. #include "bpf_experimental.h"
  8. extern bool CONFIG_X86_64 __kconfig __weak;
  9. /*
  10. * __unqual_typeof(x) - Declare an unqualified scalar type, leaving
  11. * non-scalar types unchanged,
  12. *
  13. * Prefer C11 _Generic for better compile-times and simpler code. Note: 'char'
  14. * is not type-compatible with 'signed char', and we define a separate case.
  15. *
  16. * This is copied verbatim from kernel's include/linux/compiler_types.h, but
  17. * with default expression (for pointers) changed from (x) to (typeof(x)0).
  18. *
  19. * This is because LLVM has a bug where for lvalue (x), it does not get rid of
  20. * an extra address_space qualifier, but does in case of rvalue (typeof(x)0).
  21. * Hence, for pointers, we need to create an rvalue expression to get the
  22. * desired type. See https://github.com/llvm/llvm-project/issues/53400.
  23. */
  24. #define __scalar_type_to_expr_cases(type) \
  25. unsigned type : (unsigned type)0, signed type : (signed type)0
  26. #define __unqual_typeof(x) \
  27. typeof(_Generic((x), \
  28. char: (char)0, \
  29. __scalar_type_to_expr_cases(char), \
  30. __scalar_type_to_expr_cases(short), \
  31. __scalar_type_to_expr_cases(int), \
  32. __scalar_type_to_expr_cases(long), \
  33. __scalar_type_to_expr_cases(long long), \
  34. default: (typeof(x))0))
  35. /* No-op for BPF */
  36. #define cpu_relax() ({})
  37. #define READ_ONCE(x) (*(volatile typeof(x) *)&(x))
  38. #define WRITE_ONCE(x, val) ((*(volatile typeof(x) *)&(x)) = (val))
  39. #define cmpxchg(p, old, new) __sync_val_compare_and_swap((p), old, new)
  40. #define try_cmpxchg(p, pold, new) \
  41. ({ \
  42. __unqual_typeof(*(pold)) __o = *(pold); \
  43. __unqual_typeof(*(p)) __r = cmpxchg(p, __o, new); \
  44. if (__r != __o) \
  45. *(pold) = __r; \
  46. __r == __o; \
  47. })
  48. #define try_cmpxchg_relaxed(p, pold, new) try_cmpxchg(p, pold, new)
  49. #define try_cmpxchg_acquire(p, pold, new) try_cmpxchg(p, pold, new)
  50. #define smp_mb() \
  51. ({ \
  52. volatile unsigned long __val; \
  53. __sync_fetch_and_add(&__val, 0); \
  54. })
  55. #define smp_rmb() \
  56. ({ \
  57. if (!CONFIG_X86_64) \
  58. smp_mb(); \
  59. else \
  60. barrier(); \
  61. })
  62. #define smp_wmb() \
  63. ({ \
  64. if (!CONFIG_X86_64) \
  65. smp_mb(); \
  66. else \
  67. barrier(); \
  68. })
  69. /* Control dependency provides LOAD->STORE, provide LOAD->LOAD */
  70. #define smp_acquire__after_ctrl_dep() ({ smp_rmb(); })
  71. #define smp_load_acquire(p) \
  72. ({ \
  73. __unqual_typeof(*(p)) __v = READ_ONCE(*(p)); \
  74. if (!CONFIG_X86_64) \
  75. smp_mb(); \
  76. barrier(); \
  77. __v; \
  78. })
  79. #define smp_store_release(p, val) \
  80. ({ \
  81. if (!CONFIG_X86_64) \
  82. smp_mb(); \
  83. barrier(); \
  84. WRITE_ONCE(*(p), val); \
  85. })
  86. #define smp_cond_load_relaxed_label(p, cond_expr, label) \
  87. ({ \
  88. typeof(p) __ptr = (p); \
  89. __unqual_typeof(*(p)) VAL; \
  90. for (;;) { \
  91. VAL = (__unqual_typeof(*(p)))READ_ONCE(*__ptr); \
  92. if (cond_expr) \
  93. break; \
  94. cond_break_label(label); \
  95. cpu_relax(); \
  96. } \
  97. (typeof(*(p)))VAL; \
  98. })
  99. #define smp_cond_load_acquire_label(p, cond_expr, label) \
  100. ({ \
  101. __unqual_typeof(*p) __val = \
  102. smp_cond_load_relaxed_label(p, cond_expr, label); \
  103. smp_acquire__after_ctrl_dep(); \
  104. (typeof(*(p)))__val; \
  105. })
  106. #define atomic_read(p) READ_ONCE((p)->counter)
  107. #define atomic_cond_read_relaxed_label(p, cond_expr, label) \
  108. smp_cond_load_relaxed_label(&(p)->counter, cond_expr, label)
  109. #define atomic_cond_read_acquire_label(p, cond_expr, label) \
  110. smp_cond_load_acquire_label(&(p)->counter, cond_expr, label)
  111. #define atomic_try_cmpxchg_relaxed(p, pold, new) \
  112. try_cmpxchg_relaxed(&(p)->counter, pold, new)
  113. #define atomic_try_cmpxchg_acquire(p, pold, new) \
  114. try_cmpxchg_acquire(&(p)->counter, pold, new)
  115. #endif /* BPF_ATOMIC_H */