• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //    * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //    * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //    * Neither the name of Google Inc. nor the name Chromium Embedded
14 // Framework nor the names of its contributors may be used to endorse
15 // or promote products derived from this software without specific prior
16 // written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 // Do not include this header file directly. Use base/cef_atomicops.h
31 // instead.
32 
33 #ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_ATOMICOPS_X86_GCC_H_
34 #define CEF_INCLUDE_BASE_INTERNAL_CEF_ATOMICOPS_X86_GCC_H_
35 
36 // This struct is not part of the public API of this module; clients may not
37 // use it.
38 // Features of this x86.  Values may not be correct before main() is run,
39 // but are set conservatively.
40 struct AtomicOps_x86CPUFeatureStruct {
41   bool has_amd_lock_mb_bug;  // Processor has AMD memory-barrier bug; do lfence
42                              // after acquire compare-and-swap.
43 };
44 extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures;
45 
46 #define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
47 
48 namespace base {
49 namespace subtle {
50 
51 // 32-bit low-level operations on any platform.
52 
NoBarrier_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)53 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
54                                          Atomic32 old_value,
55                                          Atomic32 new_value) {
56   Atomic32 prev;
57   __asm__ __volatile__("lock; cmpxchgl %1,%2"
58                        : "=a"(prev)
59                        : "q"(new_value), "m"(*ptr), "0"(old_value)
60                        : "memory");
61   return prev;
62 }
63 
NoBarrier_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)64 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
65                                          Atomic32 new_value) {
66   __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
67                        : "=r"(new_value)
68                        : "m"(*ptr), "0"(new_value)
69                        : "memory");
70   return new_value;  // Now it's the previous value.
71 }
72 
NoBarrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)73 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
74                                           Atomic32 increment) {
75   Atomic32 temp = increment;
76   __asm__ __volatile__("lock; xaddl %0,%1"
77                        : "+r"(temp), "+m"(*ptr)
78                        :
79                        : "memory");
80   // temp now holds the old value of *ptr
81   return temp + increment;
82 }
83 
Barrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)84 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
85                                         Atomic32 increment) {
86   Atomic32 temp = increment;
87   __asm__ __volatile__("lock; xaddl %0,%1"
88                        : "+r"(temp), "+m"(*ptr)
89                        :
90                        : "memory");
91   // temp now holds the old value of *ptr
92   if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
93     __asm__ __volatile__("lfence" : : : "memory");
94   }
95   return temp + increment;
96 }
97 
Acquire_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)98 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
99                                        Atomic32 old_value,
100                                        Atomic32 new_value) {
101   Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
102   if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
103     __asm__ __volatile__("lfence" : : : "memory");
104   }
105   return x;
106 }
107 
Release_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)108 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
109                                        Atomic32 old_value,
110                                        Atomic32 new_value) {
111   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
112 }
113 
NoBarrier_Store(volatile Atomic32 * ptr,Atomic32 value)114 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
115   *ptr = value;
116 }
117 
MemoryBarrier()118 inline void MemoryBarrier() {
119   __asm__ __volatile__("mfence" : : : "memory");
120 }
121 
Acquire_Store(volatile Atomic32 * ptr,Atomic32 value)122 inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
123   *ptr = value;
124   MemoryBarrier();
125 }
126 
Release_Store(volatile Atomic32 * ptr,Atomic32 value)127 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
128   ATOMICOPS_COMPILER_BARRIER();
129   *ptr = value;  // An x86 store acts as a release barrier.
130   // See comments in Atomic64 version of Release_Store(), below.
131 }
132 
NoBarrier_Load(volatile const Atomic32 * ptr)133 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
134   return *ptr;
135 }
136 
Acquire_Load(volatile const Atomic32 * ptr)137 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
138   Atomic32 value = *ptr;  // An x86 load acts as a acquire barrier.
139   // See comments in Atomic64 version of Release_Store(), below.
140   ATOMICOPS_COMPILER_BARRIER();
141   return value;
142 }
143 
Release_Load(volatile const Atomic32 * ptr)144 inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
145   MemoryBarrier();
146   return *ptr;
147 }
148 
149 #if defined(__x86_64__)
150 
151 // 64-bit low-level operations on 64-bit platform.
152 
NoBarrier_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)153 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
154                                          Atomic64 old_value,
155                                          Atomic64 new_value) {
156   Atomic64 prev;
157   __asm__ __volatile__("lock; cmpxchgq %1,%2"
158                        : "=a"(prev)
159                        : "q"(new_value), "m"(*ptr), "0"(old_value)
160                        : "memory");
161   return prev;
162 }
163 
NoBarrier_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)164 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
165                                          Atomic64 new_value) {
166   __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
167                        : "=r"(new_value)
168                        : "m"(*ptr), "0"(new_value)
169                        : "memory");
170   return new_value;  // Now it's the previous value.
171 }
172 
NoBarrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)173 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
174                                           Atomic64 increment) {
175   Atomic64 temp = increment;
176   __asm__ __volatile__("lock; xaddq %0,%1"
177                        : "+r"(temp), "+m"(*ptr)
178                        :
179                        : "memory");
180   // temp now contains the previous value of *ptr
181   return temp + increment;
182 }
183 
Barrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)184 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
185                                         Atomic64 increment) {
186   Atomic64 temp = increment;
187   __asm__ __volatile__("lock; xaddq %0,%1"
188                        : "+r"(temp), "+m"(*ptr)
189                        :
190                        : "memory");
191   // temp now contains the previous value of *ptr
192   if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
193     __asm__ __volatile__("lfence" : : : "memory");
194   }
195   return temp + increment;
196 }
197 
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)198 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
199   *ptr = value;
200 }
201 
Acquire_Store(volatile Atomic64 * ptr,Atomic64 value)202 inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
203   *ptr = value;
204   MemoryBarrier();
205 }
206 
Release_Store(volatile Atomic64 * ptr,Atomic64 value)207 inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
208   ATOMICOPS_COMPILER_BARRIER();
209 
210   *ptr = value;  // An x86 store acts as a release barrier
211                  // for current AMD/Intel chips as of Jan 2008.
212                  // See also Acquire_Load(), below.
213 
214   // When new chips come out, check:
215   //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
216   //  System Programming Guide, Chatper 7: Multiple-processor management,
217   //  Section 7.2, Memory Ordering.
218   // Last seen at:
219   //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
220   //
221   // x86 stores/loads fail to act as barriers for a few instructions (clflush
222   // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
223   // not generated by the compiler, and are rare.  Users of these instructions
224   // need to know about cache behaviour in any case since all of these involve
225   // either flushing cache lines or non-temporal cache hints.
226 }
227 
NoBarrier_Load(volatile const Atomic64 * ptr)228 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
229   return *ptr;
230 }
231 
Acquire_Load(volatile const Atomic64 * ptr)232 inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
233   Atomic64 value = *ptr;  // An x86 load acts as a acquire barrier,
234                           // for current AMD/Intel chips as of Jan 2008.
235                           // See also Release_Store(), above.
236   ATOMICOPS_COMPILER_BARRIER();
237   return value;
238 }
239 
Release_Load(volatile const Atomic64 * ptr)240 inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
241   MemoryBarrier();
242   return *ptr;
243 }
244 
Acquire_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)245 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
246                                        Atomic64 old_value,
247                                        Atomic64 new_value) {
248   Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
249   if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
250     __asm__ __volatile__("lfence" : : : "memory");
251   }
252   return x;
253 }
254 
Release_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)255 inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
256                                        Atomic64 old_value,
257                                        Atomic64 new_value) {
258   return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
259 }
260 
261 #endif  // defined(__x86_64__)
262 
263 }  // namespace base::subtle
264 }  // namespace base
265 
266 #undef ATOMICOPS_COMPILER_BARRIER
267 
268 #endif  // CEF_INCLUDE_BASE_INTERNAL_CEF_ATOMICOPS_X86_GCC_H_
269