1 // Copyright 2009 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 // IWYU pragma: private, include "Common/Atomic.h"
6 
7 #pragma once
8 
9 #include "Common/Common.h"
10 #include "Common/CommonTypes.h"
11 
12 // Atomic operations are performed in a single step by the CPU. It is
13 // impossible for other threads to see the operation "half-done."
14 //
15 // Some atomic operations can be combined with different types of memory
16 // barriers called "Acquire semantics" and "Release semantics", defined below.
17 //
18 // Acquire semantics: Future memory accesses cannot be relocated to before the
19 //                    operation.
20 //
21 // Release semantics: Past memory accesses cannot be relocated to after the
22 //                    operation.
23 //
24 // These barriers affect not only the compiler, but also the CPU.
25 
26 namespace Common
27 {
AtomicAdd(volatile u32 & target,u32 value)28 inline void AtomicAdd(volatile u32& target, u32 value)
29 {
30   __sync_add_and_fetch(&target, value);
31 }
32 
AtomicAnd(volatile u32 & target,u32 value)33 inline void AtomicAnd(volatile u32& target, u32 value)
34 {
35   __sync_and_and_fetch(&target, value);
36 }
37 
AtomicDecrement(volatile u32 & target)38 inline void AtomicDecrement(volatile u32& target)
39 {
40   __sync_add_and_fetch(&target, -1);
41 }
42 
AtomicIncrement(volatile u32 & target)43 inline void AtomicIncrement(volatile u32& target)
44 {
45   __sync_add_and_fetch(&target, 1);
46 }
47 
AtomicOr(volatile u32 & target,u32 value)48 inline void AtomicOr(volatile u32& target, u32 value)
49 {
50   __sync_or_and_fetch(&target, value);
51 }
52 
53 #ifndef __ATOMIC_RELAXED
54 #error __ATOMIC_RELAXED not defined; your compiler version is too old.
55 #endif
56 
57 template <typename T>
AtomicLoad(volatile T & src)58 inline T AtomicLoad(volatile T& src)
59 {
60   return __atomic_load_n(&src, __ATOMIC_RELAXED);
61 }
62 
63 template <typename T>
AtomicLoadAcquire(volatile T & src)64 inline T AtomicLoadAcquire(volatile T& src)
65 {
66   return __atomic_load_n(&src, __ATOMIC_ACQUIRE);
67 }
68 
69 template <typename T, typename U>
AtomicStore(volatile T & dest,U value)70 inline void AtomicStore(volatile T& dest, U value)
71 {
72   __atomic_store_n(&dest, value, __ATOMIC_RELAXED);
73 }
74 
75 template <typename T, typename U>
AtomicStoreRelease(volatile T & dest,U value)76 inline void AtomicStoreRelease(volatile T& dest, U value)
77 {
78   __atomic_store_n(&dest, value, __ATOMIC_RELEASE);
79 }
80 
81 template <typename T, typename U>
AtomicExchangeAcquire(T * volatile & loc,U newval)82 inline T* AtomicExchangeAcquire(T* volatile& loc, U newval)
83 {
84   return __atomic_exchange_n(&loc, newval, __ATOMIC_ACQ_REL);
85 }
86 }  // namespace Common
87