1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2013 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // This file is an internal atomic implementation for compiler-based
32 // ThreadSanitizer (http://clang.llvm.org/docs/ThreadSanitizer.html).
33 // Use atomicops.h instead.
34 
35 #ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
36 #define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
37 
38 #define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
39 
40 #include <sanitizer/tsan_interface_atomic.h>
41 
42 namespace google {
43 namespace protobuf {
44 namespace internal {
45 
NoBarrier_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)46 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
47                                          Atomic32 old_value,
48                                          Atomic32 new_value) {
49   Atomic32 cmp = old_value;
50   __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
51       __tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
52   return cmp;
53 }
54 
NoBarrier_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)55 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
56                                          Atomic32 new_value) {
57   return __tsan_atomic32_exchange(ptr, new_value,
58       __tsan_memory_order_relaxed);
59 }
60 
Acquire_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)61 inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
62                                        Atomic32 new_value) {
63   return __tsan_atomic32_exchange(ptr, new_value,
64       __tsan_memory_order_acquire);
65 }
66 
Release_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)67 inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
68                                        Atomic32 new_value) {
69   return __tsan_atomic32_exchange(ptr, new_value,
70       __tsan_memory_order_release);
71 }
72 
NoBarrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)73 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
74                                           Atomic32 increment) {
75   return increment + __tsan_atomic32_fetch_add(ptr, increment,
76       __tsan_memory_order_relaxed);
77 }
78 
Barrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)79 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
80                                         Atomic32 increment) {
81   return increment + __tsan_atomic32_fetch_add(ptr, increment,
82       __tsan_memory_order_acq_rel);
83 }
84 
Acquire_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)85 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
86                                        Atomic32 old_value,
87                                        Atomic32 new_value) {
88   Atomic32 cmp = old_value;
89   __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
90       __tsan_memory_order_acquire, __tsan_memory_order_acquire);
91   return cmp;
92 }
93 
Release_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)94 inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
95                                        Atomic32 old_value,
96                                        Atomic32 new_value) {
97   Atomic32 cmp = old_value;
98   __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
99       __tsan_memory_order_release, __tsan_memory_order_relaxed);
100   return cmp;
101 }
102 
NoBarrier_Store(volatile Atomic32 * ptr,Atomic32 value)103 inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
104   __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
105 }
106 
Acquire_Store(volatile Atomic32 * ptr,Atomic32 value)107 inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
108   __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
109   __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
110 }
111 
Release_Store(volatile Atomic32 * ptr,Atomic32 value)112 inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
113   __tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
114 }
115 
NoBarrier_Load(volatile const Atomic32 * ptr)116 inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
117   return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
118 }
119 
Acquire_Load(volatile const Atomic32 * ptr)120 inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
121   return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
122 }
123 
Release_Load(volatile const Atomic32 * ptr)124 inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
125   __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
126   return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
127 }
128 
NoBarrier_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)129 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
130                                          Atomic64 old_value,
131                                          Atomic64 new_value) {
132   Atomic64 cmp = old_value;
133   __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
134       __tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
135   return cmp;
136 }
137 
NoBarrier_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)138 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
139                                          Atomic64 new_value) {
140   return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed);
141 }
142 
Acquire_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)143 inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
144                                        Atomic64 new_value) {
145   return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire);
146 }
147 
Release_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)148 inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
149                                        Atomic64 new_value) {
150   return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release);
151 }
152 
NoBarrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)153 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
154                                           Atomic64 increment) {
155   return increment + __tsan_atomic64_fetch_add(ptr, increment,
156       __tsan_memory_order_relaxed);
157 }
158 
Barrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)159 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
160                                         Atomic64 increment) {
161   return increment + __tsan_atomic64_fetch_add(ptr, increment,
162       __tsan_memory_order_acq_rel);
163 }
164 
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)165 inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
166   __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
167 }
168 
Acquire_Store(volatile Atomic64 * ptr,Atomic64 value)169 inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
170   __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
171   __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
172 }
173 
Release_Store(volatile Atomic64 * ptr,Atomic64 value)174 inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
175   __tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
176 }
177 
NoBarrier_Load(volatile const Atomic64 * ptr)178 inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
179   return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
180 }
181 
Acquire_Load(volatile const Atomic64 * ptr)182 inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
183   return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
184 }
185 
Release_Load(volatile const Atomic64 * ptr)186 inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
187   __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
188   return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
189 }
190 
Acquire_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)191 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
192                                        Atomic64 old_value,
193                                        Atomic64 new_value) {
194   Atomic64 cmp = old_value;
195   __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
196       __tsan_memory_order_acquire, __tsan_memory_order_acquire);
197   return cmp;
198 }
199 
Release_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)200 inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
201                                        Atomic64 old_value,
202                                        Atomic64 new_value) {
203   Atomic64 cmp = old_value;
204   __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
205       __tsan_memory_order_release, __tsan_memory_order_relaxed);
206   return cmp;
207 }
208 
MemoryBarrier()209 inline void MemoryBarrier() {
210   __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
211 }
212 
213 }  // namespace internal
214 }  // namespace protobuf
215 }  // namespace google
216 
217 #undef ATOMICOPS_COMPILER_BARRIER
218 
219 #endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
220