File indexing completed on 2026-07-16 08:37:25
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef UPB_PORT_ATOMIC_H_
0009 #define UPB_PORT_ATOMIC_H_
0010
0011 #include "upb/port/def.inc"
0012
0013 #ifdef UPB_USE_C11_ATOMICS
0014
0015
0016 #include <stdatomic.h>
0017 #include <stdbool.h>
0018
0019
0020 #define upb_Atomic_Init(addr, val) atomic_init(addr, val)
0021 #define upb_Atomic_Load(addr, order) atomic_load_explicit(addr, order)
0022 #define upb_Atomic_Store(addr, val, order) \
0023 atomic_store_explicit(addr, val, order)
0024 #define upb_Atomic_Exchange(addr, val, order) \
0025 atomic_exchange_explicit(addr, val, order)
0026 #define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \
0027 success_order, failure_order) \
0028 atomic_compare_exchange_strong_explicit(addr, expected, desired, \
0029 success_order, failure_order)
0030 #define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \
0031 failure_order) \
0032 atomic_compare_exchange_weak_explicit(addr, expected, desired, \
0033 success_order, failure_order)
0034
0035 #elif defined(UPB_USE_MSC_ATOMICS)
0036 #include <intrin.h>
0037 #include <stdbool.h>
0038 #include <stdint.h>
0039
0040 #define upb_Atomic_Init(addr, val) (*(addr) = val)
0041
0042 #if defined(_WIN64)
0043
0044
0045 #pragma intrinsic(_InterlockedExchange64)
0046 #define upb_Atomic_Store(addr, val, order) \
0047 (void)_InterlockedExchange64((uint64_t volatile *)addr, (uint64_t)val)
0048
0049 #pragma intrinsic(_InterlockedCompareExchange64)
0050 static uintptr_t upb_Atomic_LoadMsc(uint64_t volatile *addr) {
0051
0052
0053 return _InterlockedCompareExchange64(addr, 0xDEADC0DEBAADF00D,
0054 0xDEADC0DEBAADF00D);
0055 }
0056
0057
0058 #if __STDC_VERSION__ >= 201112L
0059 #define upb_Atomic_Load(addr, order) \
0060 _Generic(addr, \
0061 UPB_ATOMIC(uintptr_t) *: upb_Atomic_LoadMsc( \
0062 (uint64_t volatile *)(addr)), \
0063 default: (void *)upb_Atomic_LoadMsc((uint64_t volatile *)(addr)))
0064
0065 #define upb_Atomic_Exchange(addr, val, order) \
0066 _Generic(addr, \
0067 UPB_ATOMIC(uintptr_t) *: _InterlockedExchange64( \
0068 (uint64_t volatile *)(addr), (uint64_t)val), \
0069 default: (void *)_InterlockedExchange64((uint64_t volatile *)addr, \
0070 (uint64_t)val))
0071 #else
0072
0073
0074 #define upb_Atomic_Load(addr, order) \
0075 (void *)upb_Atomic_LoadMsc((uint64_t volatile *)(addr))
0076
0077 #define upb_Atomic_Exchange(addr, val, order) \
0078 (void *)_InterlockedExchange64((uint64_t volatile *)addr, (uint64_t)val)
0079 #endif
0080
0081 #pragma intrinsic(_InterlockedCompareExchange64)
0082 static bool upb_Atomic_CompareExchangeMscP(uint64_t volatile *addr,
0083 uint64_t *expected,
0084 uint64_t desired) {
0085 uint64_t expect_val = *expected;
0086 uint64_t actual_val =
0087 _InterlockedCompareExchange64(addr, desired, expect_val);
0088 if (expect_val != actual_val) {
0089 *expected = actual_val;
0090 return false;
0091 }
0092 return true;
0093 }
0094
0095 #define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \
0096 success_order, failure_order) \
0097 upb_Atomic_CompareExchangeMscP((uint64_t volatile *)addr, \
0098 (uint64_t *)expected, (uint64_t)desired)
0099
0100 #define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \
0101 failure_order) \
0102 upb_Atomic_CompareExchangeMscP((uint64_t volatile *)addr, \
0103 (uint64_t *)expected, (uint64_t)desired)
0104
0105 #else
0106 #pragma intrinsic(_InterlockedExchange)
0107 #define upb_Atomic_Store(addr, val, order) \
0108 (void)_InterlockedExchange((uint32_t volatile *)addr, (uint32_t)val)
0109
0110 #pragma intrinsic(_InterlockedCompareExchange)
0111 static uintptr_t upb_Atomic_LoadMsc(uint32_t volatile *addr) {
0112
0113
0114 return _InterlockedCompareExchange(addr, 0xDEADC0DE, 0xDEADC0DE);
0115 }
0116
0117
0118 #if __STDC_VERSION__ >= 201112L
0119 #define upb_Atomic_Load(addr, order) \
0120 _Generic(addr, \
0121 UPB_ATOMIC(uintptr_t) *: upb_Atomic_LoadMsc( \
0122 (uint32_t volatile *)(addr)), \
0123 default: (void *)upb_Atomic_LoadMsc((uint32_t volatile *)(addr)))
0124
0125 #define upb_Atomic_Exchange(addr, val, order) \
0126 _Generic(addr, \
0127 UPB_ATOMIC(uintptr_t) *: _InterlockedExchange( \
0128 (uint32_t volatile *)(addr), (uint32_t)val), \
0129 default: (void *)_InterlockedExchange64((uint32_t volatile *)addr, \
0130 (uint32_t)val))
0131 #else
0132 #define upb_Atomic_Load(addr, order) \
0133 (void *)upb_Atomic_LoadMsc((uint32_t volatile *)(addr))
0134
0135 #define upb_Atomic_Exchange(addr, val, order) \
0136 (void *)_InterlockedExchange((uint32_t volatile *)addr, (uint32_t)val)
0137 #endif
0138
0139 #pragma intrinsic(_InterlockedCompareExchange)
0140 static bool upb_Atomic_CompareExchangeMscP(uint32_t volatile *addr,
0141 uint32_t *expected,
0142 uint32_t desired) {
0143 uint32_t expect_val = *expected;
0144 uint32_t actual_val = _InterlockedCompareExchange(addr, desired, expect_val);
0145 if (expect_val != actual_val) {
0146 *expected = actual_val;
0147 return false;
0148 }
0149 return true;
0150 }
0151
0152 #define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \
0153 success_order, failure_order) \
0154 upb_Atomic_CompareExchangeMscP((uint32_t volatile *)addr, \
0155 (uint32_t *)expected, (uint32_t)desired)
0156
0157 #define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \
0158 failure_order) \
0159 upb_Atomic_CompareExchangeMscP((uint32_t volatile *)addr, \
0160 (uint32_t *)expected, (uint32_t)desired)
0161 #endif
0162
0163 #else
0164
0165 #if !defined(UPB_SUPPRESS_MISSING_ATOMICS)
0166
0167 #error Your compiler does not support atomic instructions, which UPB uses. If you do not use UPB on multiple threads, you can suppress this error by defining UPB_SUPPRESS_MISSING_ATOMICS.
0168 #endif
0169
0170 #include <string.h>
0171
0172 #define upb_Atomic_Init(addr, val) (*addr = val)
0173 #define upb_Atomic_Load(addr, order) (*addr)
0174 #define upb_Atomic_Store(addr, val, order) (*(addr) = val)
0175
0176 UPB_INLINE void* _upb_NonAtomic_Exchange(void* addr, void* value) {
0177 void* old;
0178 memcpy(&old, addr, sizeof(value));
0179 memcpy(addr, &value, sizeof(value));
0180 return old;
0181 }
0182
0183 #define upb_Atomic_Exchange(addr, val, order) _upb_NonAtomic_Exchange(addr, val)
0184
0185
0186 UPB_INLINE bool _upb_NonAtomic_CompareExchangeStrongP(void* addr,
0187 void* expected,
0188 void* desired) {
0189 if (memcmp(addr, expected, sizeof(desired)) == 0) {
0190 memcpy(addr, &desired, sizeof(desired));
0191 return true;
0192 } else {
0193 memcpy(expected, addr, sizeof(desired));
0194 return false;
0195 }
0196 }
0197
0198 #define upb_Atomic_CompareExchangeStrong(addr, expected, desired, \
0199 success_order, failure_order) \
0200 _upb_NonAtomic_CompareExchangeStrongP((void*)addr, (void*)expected, \
0201 (void*)desired)
0202 #define upb_Atomic_CompareExchangeWeak(addr, expected, desired, success_order, \
0203 failure_order) \
0204 upb_Atomic_CompareExchangeStrong(addr, expected, desired, 0, 0)
0205
0206 #endif
0207
0208 #include "upb/port/undef.inc"
0209
0210 #endif