vpx_atomics.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright (c) 2017 The WebM project authors. All Rights Reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #ifndef VPX_VPX_UTIL_VPX_ATOMICS_H_
  11. #define VPX_VPX_UTIL_VPX_ATOMICS_H_
  12. #include "./vpx_config.h"
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif // __cplusplus
  16. #if CONFIG_OS_SUPPORT && CONFIG_MULTITHREAD
  17. // Look for built-in atomic support. We cannot use <stdatomic.h> or <atomic>
  18. // since neither is guaranteed to exist on both C and C++ platforms, and we need
  19. // to back the atomic type with the same type (g++ needs to be able to use
  20. // gcc-built code). g++ 6 doesn't support _Atomic as a keyword and can't use the
  21. // stdatomic.h header. Even if both <stdatomic.h> and <atomic> existed it's not
  22. // guaranteed that atomic_int is the same type as std::atomic_int.
  23. // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932#c13.
  24. #if !defined(__has_builtin)
  25. #define __has_builtin(x) 0 // Compatibility with non-clang compilers.
  26. #endif // !defined(__has_builtin)
  27. #if (__has_builtin(__atomic_load_n)) || \
  28. (defined(__GNUC__) && \
  29. (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
  30. // For GCC >= 4.7 and Clang versions that support __atomic builtins, use those.
  31. #define VPX_USE_ATOMIC_BUILTINS
  32. #else
  33. // Use platform-specific asm barriers.
  34. #if defined(_MSC_VER)
  35. // TODO(pbos): This assumes that newer versions of MSVC are building with the
  36. // default /volatile:ms (or older, where this is always true. Consider adding
  37. // support for using <atomic> instead of stdatomic.h when building C++11 under
  38. // MSVC. It's unclear what to do for plain C under /volatile:iso (inline asm?),
  39. // there're no explicit Interlocked* functions for only storing or loading
  40. // (presumably because volatile has historically implied that on MSVC).
  41. //
  42. // For earlier versions of MSVC or the default /volatile:ms volatile int are
  43. // acquire/release and require no barrier.
  44. #define vpx_atomic_memory_barrier() \
  45. do { \
  46. } while (0)
  47. #else
  48. #if ARCH_X86 || ARCH_X86_64
  49. // Use a compiler barrier on x86, no runtime penalty.
  50. #define vpx_atomic_memory_barrier() __asm__ __volatile__("" ::: "memory")
  51. #elif ARCH_ARM
  52. #define vpx_atomic_memory_barrier() __asm__ __volatile__("dmb ish" ::: "memory")
  53. #elif ARCH_MIPS
  54. #define vpx_atomic_memory_barrier() __asm__ __volatile__("sync" ::: "memory")
  55. #else
  56. #error Unsupported architecture!
  57. #endif // ARCH_X86 || ARCH_X86_64
  58. #endif // defined(_MSC_VER)
  59. #endif // atomic builtin availability check
  60. // These are wrapped in a struct so that they are not easily accessed directly
  61. // on any platform (to discourage programmer errors by setting values directly).
  62. // This primitive MUST be initialized using vpx_atomic_init or VPX_ATOMIC_INIT
  63. // (NOT memset) and accessed through vpx_atomic_ functions.
  64. typedef struct vpx_atomic_int {
  65. volatile int value;
  66. } vpx_atomic_int;
  67. #define VPX_ATOMIC_INIT(num) \
  68. { num }
  69. // Initialization of an atomic int, not thread safe.
  70. static INLINE void vpx_atomic_init(vpx_atomic_int *atomic, int value) {
  71. atomic->value = value;
  72. }
  73. static INLINE void vpx_atomic_store_release(vpx_atomic_int *atomic, int value) {
  74. #if defined(VPX_USE_ATOMIC_BUILTINS)
  75. __atomic_store_n(&atomic->value, value, __ATOMIC_RELEASE);
  76. #else
  77. vpx_atomic_memory_barrier();
  78. atomic->value = value;
  79. #endif // defined(VPX_USE_ATOMIC_BUILTINS)
  80. }
  81. static INLINE int vpx_atomic_load_acquire(const vpx_atomic_int *atomic) {
  82. #if defined(VPX_USE_ATOMIC_BUILTINS)
  83. return __atomic_load_n(&atomic->value, __ATOMIC_ACQUIRE);
  84. #else
  85. int v = atomic->value;
  86. vpx_atomic_memory_barrier();
  87. return v;
  88. #endif // defined(VPX_USE_ATOMIC_BUILTINS)
  89. }
  90. #undef VPX_USE_ATOMIC_BUILTINS
  91. #undef vpx_atomic_memory_barrier
  92. #endif /* CONFIG_OS_SUPPORT && CONFIG_MULTITHREAD */
  93. #ifdef __cplusplus
  94. } // extern "C"
  95. #endif // __cplusplus
  96. #endif // VPX_VPX_UTIL_VPX_ATOMICS_H_