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