LMMS
Loading...
Searching...
No Matches
Atomic.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the Water library.
5 Copyright (c) 2016 ROLI Ltd.
6 Copyright (C) 2017-2023 Filipe Coelho <falktx@falktx.com>
7
8 Permission is granted to use this software under the terms of the ISC license
9 http://www.isc.org/downloads/software-support-policy/isc-license/
10
11 Permission to use, copy, modify, and/or distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies.
14
15 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 OF THIS SOFTWARE.
22
23 ==============================================================================
24*/
25
26#ifndef WATER_ATOMIC_H_INCLUDED
27#define WATER_ATOMIC_H_INCLUDED
28
29#include "../water.h"
30
31#ifdef _MSC_VER
32# ifndef NOMINMAX
33# define NOMINMAX
34# endif
35# define WIN32_LEAN_AND_MEAN 1
36# include <winsock2.h>
37# include <windows.h>
38#endif
39
40#include <stdint.h>
41
42namespace water {
43
44#if defined(__clang__)
45# pragma clang diagnostic push
46# pragma clang diagnostic ignored "-Weffc++"
47#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
48# pragma GCC diagnostic push
49# pragma GCC diagnostic ignored "-Weffc++"
50#elif defined(_MSC_VER)
51# pragma warning (push)
52# pragma warning (disable: 4311) /* truncation warning */
53# ifdef CARLA_OS_64BIT
54# pragma intrinsic (_InterlockedExchange, \
55 _InterlockedExchange64, \
56 _InterlockedExchangeAdd, \
57 _InterlockedExchangeAdd64, \
58 _InterlockedIncrement, \
59 _InterlockedIncrement64, \
60 _InterlockedDecrement, \
61 _InterlockedDecrement64, \
62 _InterlockedCompareExchange, \
63 _InterlockedCompareExchange64, \
64 _ReadWriteBarrier)
65# else
66# pragma intrinsic (_InterlockedExchange, \
67 _InterlockedExchangeAdd, \
68 _InterlockedIncrement, \
69 _InterlockedDecrement, \
70 _InterlockedCompareExchange, \
71 _InterlockedCompareExchange64, \
72 _ReadWriteBarrier)
73# endif
74#endif
75
76#if defined(CARLA_OS_64BIT) || !defined(_MSC_VER)
77# define WATER_ATOMIC_64_SUPPORTED
78#endif
79
80#ifdef CARLA_OS_64BIT
81# define WATER_ALIGN_SIZE 8
82#else
83# define WATER_ALIGN_SIZE 4
84#endif
85
86//==============================================================================
93template <typename Type>
94class Atomic
95{
96public:
99 : value (0)
100 {
101 }
102
104 inline explicit Atomic (const Type initialValue) noexcept
105 : value (initialValue)
106 {
107 }
108
110 inline Atomic (const Atomic& other) noexcept
111 : value (other.get())
112 {
113 }
114
117 {
118#ifdef CARLA_PROPER_CPP11_SUPPORT
119 // This class can only be used for types which are 32 or 64 bits in size.
120 static_wassert (sizeof (Type) == 4 || sizeof (Type) == 8);
121#endif
122 }
123
126
128 inline Atomic& operator= (const Atomic& other) noexcept { exchange (other.get()); return *this; }
129
131 inline Atomic& operator= (const Type newValue) noexcept { exchange (newValue); return *this; }
132
134 void set (Type newValue) noexcept { exchange (newValue); }
135
137 Type exchange (Type value) noexcept;
138
140 Type operator+= (Type amountToAdd) noexcept;
141
143 Type operator-= (Type amountToSubtract) noexcept;
144
147
149 Type operator--() noexcept;
150
172 bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept;
173
192 Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept;
193
195 static void memoryBarrier() noexcept;
196
197 //==============================================================================
202 #ifdef _MSC_VER
203 __declspec (align (WATER_ALIGN_SIZE))
204 #else
206 #endif
207 mutable volatile Type value;
208
209private:
210 template <typename Dest, typename Source>
211 static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; }
212
213 static inline Type castFrom32Bit (int32 value) noexcept { return castTo <Type, int32> (value); }
214 static inline Type castFrom64Bit (int64 value) noexcept { return castTo <Type, int64> (value); }
215 static inline Type castFrom32Bit (uint32 value) noexcept { return castTo <Type, uint32> (value); }
216 static inline Type castFrom64Bit (uint64 value) noexcept { return castTo <Type, uint64> (value); }
217 static inline Type castFromLong (long value) noexcept { return castTo <Type, long> (value); }
218 static inline int32 castTo32Bit (Type value) noexcept { return castTo <int32, Type> (value); }
219 static inline int64 castTo64Bit (Type value) noexcept { return castTo <int64, Type> (value); }
220 static inline long castToLong (Type value) noexcept { return castTo <long, Type> (value); }
221
222 Type operator++ (int); // better to just use pre-increment with atomics..
223 Type operator-- (int);
224
226 template <typename ValueType>
227 inline ValueType negateValue (ValueType n) noexcept
228 {
229 return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n
230 : (sizeof (ValueType) == 2 ? (ValueType) -(short) n
231 : (sizeof (ValueType) == 4 ? (ValueType) -(int) n
232 : ((ValueType) -(int64) n)));
233 }
234
236 template <typename PointerType>
237 inline PointerType* negateValue (PointerType* n) noexcept
238 {
239 return reinterpret_cast<PointerType*> (-reinterpret_cast<pointer_sized_int> (n));
240 }
241};
242
243//==============================================================================
244template<>
246{
247 #ifdef CARLA_PROPER_CPP11_SUPPORT
248 static_wassert (sizeof (int32) == 4);
249 #endif
250 #ifdef _MSC_VER
251 return castFromLong (_InterlockedExchangeAdd (reinterpret_cast<volatile long*> (&value), 0));
252 #else
253 return castFrom32Bit ((int32) __sync_add_and_fetch (const_cast<volatile int32*> (&value), 0));
254 #endif
255}
256
257template<>
259{
260 #ifdef CARLA_PROPER_CPP11_SUPPORT
261 static_wassert (sizeof (uint32) == 4);
262 #endif
263 #ifdef _MSC_VER
264 return castFromLong (_InterlockedExchangeAdd (reinterpret_cast<volatile long*> (&value), 0));
265 #else
266 return castFrom32Bit ((uint32) __sync_add_and_fetch (const_cast<volatile uint32*> (&value), 0));
267 #endif
268}
269
270#ifdef WATER_ATOMIC_64_SUPPORTED
271template<>
273{
274 #ifdef CARLA_PROPER_CPP11_SUPPORT
275 static_wassert (sizeof (int64) == 8);
276 #endif
277 #ifdef _MSC_VER
278 return castFrom64Bit (_InterlockedExchangeAdd64 (reinterpret_cast<volatile int64*> (&value), 0));
279 #else
280 return castFrom64Bit ((int64) __sync_add_and_fetch (const_cast<volatile int64*> (&value), 0));
281 #endif
282}
283
284template<>
286{
287 #ifdef CARLA_PROPER_CPP11_SUPPORT
288 static_wassert (sizeof (uint64) == 8);
289 #endif
290 #ifdef _MSC_VER
291 return castFrom64Bit (_InterlockedExchangeAdd64 (reinterpret_cast<volatile int64*> (&value), 0));
292 #else
293 return castFrom64Bit ((uint64) __sync_add_and_fetch (const_cast<volatile uint64*> (&value), 0));
294 #endif
295}
296#endif // WATER_ATOMIC_64_SUPPORTED
297
298#ifdef _MSC_VER
299template <>
300inline int32 Atomic<int32>::exchange (const int32 newValue) noexcept
301{
302 return castFromLong (_InterlockedExchange (reinterpret_cast<volatile long*> (&value), castToLong (newValue)));
303}
304
305template <>
306inline uint32 Atomic<uint32>::exchange (const uint32 newValue) noexcept
307{
308 return castFromLong (_InterlockedExchange (reinterpret_cast<volatile long*> (&value), castToLong (newValue)));
309}
310
311template <>
312inline int32 Atomic<int32>::operator+= (const int32 amountToAdd) noexcept
313{
314 return castFromLong (_InterlockedExchangeAdd (reinterpret_cast<volatile long*> (&value), castToLong (amountToAdd)));
315}
316
317template <>
318inline uint32 Atomic<uint32>::operator+= (const uint32 amountToAdd) noexcept
319{
320 return castFromLong (_InterlockedExchangeAdd (reinterpret_cast<volatile long*> (&value), castToLong (amountToAdd)));
321}
322
323template <>
325{
326 return castFromLong (_InterlockedIncrement (reinterpret_cast<volatile long*> (&value)));
327}
328
329template <>
331{
332 return castFromLong (_InterlockedIncrement (reinterpret_cast<volatile long*> (&value)));
333}
334
335template <>
337{
338 return castFromLong (_InterlockedDecrement (reinterpret_cast<volatile long*> (&value)));
339}
340
341template <>
343{
344 return castFromLong (_InterlockedDecrement (reinterpret_cast<volatile long*> (&value)));
345}
346
347# ifndef CARLA_OS_64BIT
348template <>
349inline int64 Atomic<int64>::exchange (const int64 newValue) noexcept
350{
351 return castFrom64Bit (_InterlockedCompareExchange64 (reinterpret_cast<volatile int64*> (&value), castTo64Bit (value), castTo64Bit (newValue)));
352}
353
354template <>
355inline uint64 Atomic<uint64>::exchange (const uint64 newValue) noexcept
356{
357 return castFrom64Bit (_InterlockedCompareExchange64 (reinterpret_cast<volatile int64*> (&value), castTo64Bit (value), castTo64Bit (newValue)));
358}
359# else
360template <>
361inline int64 Atomic<int64>::exchange (const int64 newValue) noexcept
362{
363 return castFrom64Bit (_InterlockedExchange64 (reinterpret_cast<volatile int64*> (&value), castTo64Bit (newValue)));
364}
365
366template <>
367inline uint64 Atomic<uint64>::exchange (const uint64 newValue) noexcept
368{
369 return castFrom64Bit (_InterlockedExchange64 (reinterpret_cast<volatile int64*> (&value), castTo64Bit (newValue)));
370}
371
372template <>
373inline int64 Atomic<int64>::operator+= (const int64 amountToAdd) noexcept
374{
375 return castFrom64Bit (_InterlockedExchangeAdd64 (reinterpret_cast<volatile int64*> (&value), castTo64Bit (amountToAdd)));
376}
377
378template <>
379inline uint64 Atomic<uint64>::operator+= (const uint64 amountToAdd) noexcept
380{
381 return castFrom64Bit (_InterlockedExchangeAdd64 (reinterpret_cast<volatile int64*> (&value), castTo64Bit (amountToAdd)));
382}
383
384template <>
386{
387 return castFrom64Bit (_InterlockedIncrement64 (reinterpret_cast<volatile int64*> (&value)));
388}
389
390template <>
392{
393 return castFrom64Bit (_InterlockedIncrement64 (reinterpret_cast<volatile int64*> (&value)));
394}
395
396template <>
398{
399 return castFrom64Bit (_InterlockedDecrement64 (reinterpret_cast<volatile int64*> (&value)));
400}
401
402template <>
404{
405 return castFrom64Bit (_InterlockedDecrement64 (reinterpret_cast<volatile int64*> (&value)));
406}
407# endif
408#else // _MSC_VER
409template <typename Type>
410inline Type Atomic<Type>::exchange (const Type newValue) noexcept
411{
412 Type currentVal = value;
413 while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
414 return currentVal;
415}
416
417template <typename Type>
418inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
419{
420 return (Type) __sync_add_and_fetch (&value, amountToAdd);
421}
422
423template <typename Type>
425{
426 return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (&value, (Type) 1)
427 : (Type) __sync_add_and_fetch ((volatile int64*) &value, 1);
428}
429
430template <typename Type>
432{
433 return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (&value, (Type) -1)
434 : (Type) __sync_add_and_fetch ((volatile int64*) &value, -1);
435}
436#endif // _MSC_VER
437
438template <typename Type>
439inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
440{
441 return operator+= (negateValue (amountToSubtract));
442}
443
444template <typename Type>
445inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
446{
447 #ifdef _MSC_VER
448 return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
449 #else
450 return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
451 : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
452 #endif
453}
454
455template <typename Type>
456inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
457{
458 #ifdef _MSC_VER
459 return sizeof (Type) == 4 ? castFromLong (_InterlockedCompareExchange (reinterpret_cast<volatile long*> (&value), castToLong (valueToCompare), castToLong (newValue)))
460 : castFrom64Bit (_InterlockedCompareExchange64 (reinterpret_cast<volatile int64*> (&value), castTo64Bit (valueToCompare), castTo64Bit (newValue)));
461 #else
462 return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap (reinterpret_cast<volatile int32*> (&value), castTo32Bit (valueToCompare), castTo32Bit (newValue)))
463 : castFrom64Bit ((int64) __sync_val_compare_and_swap (reinterpret_cast<volatile int64*> (&value), castTo64Bit (valueToCompare), castTo64Bit (newValue)));
464 #endif
465}
466
467template <typename Type>
469{
470 #ifdef _MSC_VER
471 _ReadWriteBarrier();
472 #else
473 __sync_synchronize();
474 #endif
475}
476
477#if defined(__clang__)
478# pragma clang diagnostic pop
479#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
480# pragma GCC diagnostic pop
481#elif defined(_MSC_VER)
482# pragma warning (pop)
483#endif
484
485}
486
487#endif // WATER_ATOMIC_H_INCLUDED
#define noexcept
Definition DistrhoDefines.h:72
uint32_t uint32
Definition basics.h:90
static void memoryBarrier() noexcept
Definition Atomic.h:468
Type operator++() noexcept
Definition Atomic.h:424
static Type castFromLong(long value) noexcept
Definition Atomic.h:217
Type operator--() noexcept
Definition Atomic.h:431
Type operator+=(Type amountToAdd) noexcept
Definition Atomic.h:418
static int64 castTo64Bit(Type value) noexcept
Definition Atomic.h:219
static Type castFrom32Bit(uint32 value) noexcept
Definition Atomic.h:215
Type exchange(Type value) noexcept
Definition Atomic.h:410
void set(Type newValue) noexcept
Definition Atomic.h:134
int compareAndSetValue(int newValue, int valueToCompare) noexcept
Definition Atomic.h:456
static long castToLong(Type value) noexcept
Definition Atomic.h:220
Atomic() noexcept
Definition Atomic.h:98
Atomic & operator=(const Atomic &other) noexcept
Definition Atomic.h:128
static int32 castTo32Bit(Type value) noexcept
Definition Atomic.h:218
bool compareAndSetBool(int newValue, int valueToCompare) noexcept
Definition Atomic.h:445
ValueType negateValue(ValueType n) noexcept
Definition Atomic.h:227
Type operator-=(Type amountToSubtract) noexcept
Definition Atomic.h:439
Atomic(const Type initialValue) noexcept
Definition Atomic.h:104
static Type castFrom64Bit(uint64 value) noexcept
Definition Atomic.h:216
~Atomic() noexcept
Definition Atomic.h:116
static Dest castTo(Source value) noexcept
Definition Atomic.h:211
static Type castFrom64Bit(int64 value) noexcept
Definition Atomic.h:214
PointerType * negateValue(PointerType *n) noexcept
Definition Atomic.h:237
static Type castFrom32Bit(int32 value) noexcept
Definition Atomic.h:213
__attribute__((aligned(WATER_ALIGN_SIZE))) mutable volatile Type value
Atomic(const Atomic &other) noexcept
Definition Atomic.h:110
Type get() const noexcept
unsigned d
Definition inflate.c:940
struct huft * u[BMAX]
Definition inflate.c:1583
unsigned s
Definition inflate.c:1555
static PuglViewHint int value
Definition pugl.h:1708
#define static_wassert(expression)
#define WATER_ALIGN_SIZE
Definition AudioSampleBuffer.h:33
unsigned int uint32
Definition water.h:98
unsigned long long uint64
Definition water.h:102
int pointer_sized_int
Definition water.h:111
String & operator+=(String &s1, const NewLine &)
Definition NewLine.h:71
long long int64
Definition water.h:100
signed int int32
Definition water.h:96
int n
Definition crypt.c:458
typedef int(UZ_EXP MsgFn)()
#define const
Definition zconf.h:137