AAX SDK  2.4.1
Avid Audio Extensions Development Kit
AAX_Atomic.h
Go to the documentation of this file.
1 /*================================================================================================*/
2 /*
3  * Copyright 2013-2015, 2018 by Avid Technology, Inc.
4  * All rights reserved.
5  *
6  * CONFIDENTIAL: This document contains confidential information. Do not
7  * read or examine this document unless you are an Avid Technology employee
8  * or have signed a non-disclosure agreement with Avid Technology which protects
9  * the confidentiality of this document. DO NOT DISCLOSE ANY INFORMATION
10  * CONTAINED IN THIS DOCUMENT TO ANY THIRD-PARTY WITHOUT THE PRIOR WRITTEN CONSENT
11  * OF Avid Technology, INC.
12  *
13  */
14 
20 /*================================================================================================*/
21 
22 
23 #pragma once
24 
25 #ifndef _AAX_ATOMIC_H_
26 #define _AAX_ATOMIC_H_
27 
28 #include "AAX.h"
29 #include <stdint.h>
30 
31 #if (!defined AAX_PointerSize)
32 #error Undefined pointer size
33 #endif
34 
35 
37 uint32_t AAX_CALLBACK AAX_Atomic_IncThenGet_32(uint32_t & ioData);
38 
40 uint32_t AAX_CALLBACK AAX_Atomic_DecThenGet_32(uint32_t & ioData);
41 
44  volatile uint32_t& ioValue,
45  uint32_t inExchangeValue);
46 
49  volatile uint64_t& ioValue,
50  uint64_t inExchangeValue);
51 
53 template<typename TPointer> TPointer* AAX_CALLBACK AAX_Atomic_Exchange_Pointer(TPointer*& ioValue, TPointer* inExchangeValue)
54 {
55 #if (AAX_PointerSize == AAXPointer_64bit)
56  return (TPointer*)AAX_Atomic_Exchange_64(*(uint64_t*)(void*)&ioValue, (uint64_t)inExchangeValue);
57 #elif (AAX_PointerSize == AAXPointer_32bit)
58  return (TPointer*)AAX_Atomic_Exchange_32(*(uint32_t*)(void*)&ioValue, (uint32_t)inExchangeValue);
59 #else
60 #error Unsupported pointer size
61 #endif
62 }
63 
66  volatile uint32_t & ioValue,
67  uint32_t inCompareValue,
68  uint32_t inExchangeValue);
69 
72  volatile uint64_t& ioValue,
73  uint64_t inCompareValue,
74  uint64_t inExchangeValue);
75 
77 template<typename TPointer> bool AAX_CALLBACK AAX_Atomic_CompareAndExchange_Pointer(TPointer*& ioValue, TPointer* inCompareValue, TPointer* inExchangeValue)
78 {
79 #if (AAX_PointerSize == AAXPointer_64bit)
80  return AAX_Atomic_CompareAndExchange_64(*(uint64_t*)(void*)&ioValue, (uint64_t)inCompareValue, (uint64_t)inExchangeValue);
81 #elif (AAX_PointerSize == AAXPointer_32bit)
82  return AAX_Atomic_CompareAndExchange_32(*(uint32_t*)(void*)&ioValue, (uint32_t)inCompareValue, (uint32_t)inExchangeValue);
83 #else
84 #error Unsupported pointer size
85 #endif
86 }
87 
89 template<typename TPointer> TPointer* AAX_CALLBACK AAX_Atomic_Load_Pointer(TPointer const * const volatile * inValue);
90 
91 
92 
93 //TODO: Update all atomic function implementatons with proper acquire/release semantics
94 
95 
96 // GCC/LLVM
97 #if defined(__GNUC__)
98 
99 // These intrinsics require GCC 4.2 or later
100 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
101 
102 inline uint32_t AAX_CALLBACK
103 AAX_Atomic_IncThenGet_32(uint32_t& ioData)
104 {
105  return __sync_add_and_fetch(&ioData, 1);
106 }
107 
108 inline uint32_t AAX_CALLBACK
109 AAX_Atomic_DecThenGet_32(uint32_t& ioData)
110 {
111  return __sync_sub_and_fetch(&ioData, 1);
112 }
113 
114 inline uint32_t
116  volatile uint32_t& ioValue,
117  uint32_t inExchangeValue)
118 {
119  return __sync_lock_test_and_set(&ioValue, inExchangeValue);
120 }
121 
122 inline uint64_t
124  volatile uint64_t& ioValue,
125  uint64_t inExchangeValue)
126 {
127  return __sync_lock_test_and_set(&ioValue, inExchangeValue);
128 }
129 
130 inline bool
132  volatile uint32_t & ioValue,
133  uint32_t inCompareValue,
134  uint32_t inExchangeValue)
135 {
136  return __sync_bool_compare_and_swap(&ioValue, inCompareValue, inExchangeValue);
137 }
138 
139 inline bool
141  volatile uint64_t& ioValue,
142  uint64_t inCompareValue,
143  uint64_t inExchangeValue)
144 {
145  return __sync_bool_compare_and_swap(&ioValue, inCompareValue, inExchangeValue);
146 }
147 
148 //TODO: Add GCC version check and alternative implementations for GCC versions that do not support __atomic_load
149 template<typename TPointer>
150 inline TPointer*
151 AAX_Atomic_Load_Pointer(TPointer const * const volatile * inValue)
152 {
153  TPointer* value;
154  __atomic_load(const_cast<TPointer * volatile *>(inValue), &(value), __ATOMIC_ACQUIRE);
155  return value;
156 }
157 
158 #else // (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
159 #error This file requires GCC 4.2 or later
160 #endif // (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
161 // End GCC/LLVM
162 
163 
164 
165 
166 
167 // Visual C
168 #elif defined(_MSC_VER)
169 
170 #ifndef __INTRIN_H_
171 #include <intrin.h>
172 #endif
173 
174 #pragma intrinsic( _InterlockedIncrement, \
175  _InterlockedDecrement, \
176  _InterlockedExchange, \
177  _InterlockedCompareExchange, \
178  _InterlockedCompareExchange64)
179 
180 inline uint32_t AAX_CALLBACK
181 AAX_Atomic_IncThenGet_32(register uint32_t& ioData)
182 {
183  return static_cast<uint32_t>(_InterlockedIncrement((volatile long*)&ioData));
184 }
185 
186 inline uint32_t AAX_CALLBACK
187 AAX_Atomic_DecThenGet_32(register uint32_t& ioData)
188 {
189  return static_cast<uint32_t>(_InterlockedDecrement((volatile long*)&ioData));
190 }
191 
192 inline uint32_t
194  volatile uint32_t& ioDestination,
195  uint32_t inExchangeValue)
196 {
197  return static_cast<uint32_t>(_InterlockedExchange((volatile long*)&ioDestination, (long)inExchangeValue));
198 }
199 
200 #if (AAX_PointerSize == AAXPointer_64bit)
201 
202 #pragma intrinsic( _InterlockedExchange64, \
203  _InterlockedOr64)
204 
205 inline uint64_t
207  volatile uint64_t& ioValue,
208  uint64_t inExchangeValue)
209 {
210  return static_cast<uint64_t>(_InterlockedExchange64((volatile __int64*)&ioValue, (__int64)inExchangeValue));
211 }
212 
213 template<typename TPointer>
214 inline TPointer*
215 AAX_Atomic_Load_Pointer(TPointer const * const volatile * inValue)
216 {
217 // Itanium supports acquire semantics
218 #if (_M_IA64)
219  return reinterpret_cast<TPointer*>(_InterlockedOr64_acq(const_cast<__int64 volatile *>(reinterpret_cast<const __int64 volatile *>(inValue)), 0x0000000000000000));
220 #else
221  return reinterpret_cast<TPointer*>(_InterlockedOr64(const_cast<__int64 volatile *>(reinterpret_cast<const __int64 volatile *>(inValue)), 0x0000000000000000));
222 #endif
223 }
224 
225 #elif (AAX_PointerSize == AAXPointer_32bit)
226 
227 #pragma intrinsic( _InterlockedOr )
228 
229 // _InterlockedExchange64 is not available on 32-bit Pentium in Visual C
230 inline uint64_t
232  volatile uint64_t& ioValue,
233  uint64_t inExchangeValue)
234 {
235  for(;;)
236  {
237  uint64_t result = ioValue;
238  if(AAX_Atomic_CompareAndExchange_64(ioValue, result, inExchangeValue))
239  {
240  return result;
241  }
242  }
243 
244  return 0; // will never get here
245 }
246 
247 template<typename TPointer>
248 inline TPointer*
249 AAX_Atomic_Load_Pointer(TPointer const * const volatile * inValue)
250 {
251  return reinterpret_cast<TPointer*>(_InterlockedOr(const_cast<long volatile *>(reinterpret_cast<const long volatile *>(inValue)), 0x00000000));
252 }
253 
254 #endif
255 
256 inline bool
258  uint32_t volatile & ioValue,
259  uint32_t inCompareValue,
260  uint32_t inExchangeValue)
261 {
262  return static_cast<uint32_t>(_InterlockedCompareExchange((volatile long*)&ioValue, (long)inExchangeValue, (long)inCompareValue)) == inCompareValue;
263 }
264 
265 inline bool
267  volatile uint64_t& ioValue,
268  uint64_t inCompareValue,
269  uint64_t inExchangeValue)
270 {
271  return static_cast<uint64_t>(_InterlockedCompareExchange64((volatile __int64*)&ioValue, (__int64)inExchangeValue, (__int64)inCompareValue)) == inCompareValue;
272 }
273 
274 // End Visual C
275 
276 
277 
278 
279 
280 #else // Not Visual C or GCC/LLVM
281 #error Provide an atomic operation implementation for this compiler
282 #endif // Compiler version check
283 
284 #endif // #ifndef _AAX_ATOMIC_H_
Various utility definitions for AAX.
#define AAX_CALLBACK
Definition: AAX.h:285
TPointer *AAX_CALLBACK AAX_Atomic_Exchange_Pointer(TPointer *&ioValue, TPointer *inExchangeValue)
Perform an exchange operation on a pointer value.
Definition: AAX_Atomic.h:53
uint64_t AAX_CALLBACK AAX_Atomic_Exchange_64(volatile uint64_t &ioValue, uint64_t inExchangeValue)
Return the original value of ioValue and then set it to inExchangeValue.
uint32_t AAX_CALLBACK AAX_Atomic_Exchange_32(volatile uint32_t &ioValue, uint32_t inExchangeValue)
Return the original value of ioValue and then set it to inExchangeValue.
uint32_t AAX_CALLBACK AAX_Atomic_IncThenGet_32(uint32_t &ioData)
Increments a 32-bit value and returns the result.
bool AAX_CALLBACK AAX_Atomic_CompareAndExchange_32(volatile uint32_t &ioValue, uint32_t inCompareValue, uint32_t inExchangeValue)
Perform a compare and exchange operation on a 32-bit value.
bool AAX_CALLBACK AAX_Atomic_CompareAndExchange_Pointer(TPointer *&ioValue, TPointer *inCompareValue, TPointer *inExchangeValue)
Perform a compare and exchange operation on a pointer value.
Definition: AAX_Atomic.h:77
uint32_t AAX_CALLBACK AAX_Atomic_DecThenGet_32(uint32_t &ioData)
Decrements a 32-bit value and returns the result.
bool AAX_CALLBACK AAX_Atomic_CompareAndExchange_64(volatile uint64_t &ioValue, uint64_t inCompareValue, uint64_t inExchangeValue)
Perform a compare and exchange operation on a 64-bit value.
TPointer *AAX_CALLBACK AAX_Atomic_Load_Pointer(TPointer const *const volatile *inValue)
Atomically loads a pointer value.