BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsls_atomicoperations_arm_all_gcc.h
Go to the documentation of this file.
1/// @file bsls_atomicoperations_arm_all_gcc.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_atomicoperations_arm_all_gcc.h -*-C++-*-
8#ifndef INCLUDED_BSLS_ATOMICOPERATIONS_ARM_ALL_GCC
9#define INCLUDED_BSLS_ATOMICOPERATIONS_ARM_ALL_GCC
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_atomicoperations_arm_all_gcc bsls_atomicoperations_arm_all_gcc
15/// @brief Provide implementations of atomic operations for ARM/GCC.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_atomicoperations_arm_all_gcc
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_atomicoperations_arm_all_gcc-purpose"> Purpose</a>
25/// * <a href="#bsls_atomicoperations_arm_all_gcc-classes"> Classes </a>
26/// * <a href="#bsls_atomicoperations_arm_all_gcc-description"> Description </a>
27///
28/// # Purpose {#bsls_atomicoperations_arm_all_gcc-purpose}
29/// Provide implementations of atomic operations for ARM/GCC.
30///
31/// # Classes {#bsls_atomicoperations_arm_all_gcc-classes}
32///
33/// - bsls::AtomicOperations_ARM_ALL_GCC: implementation of atomics for ARM/GCC.
34///
35/// # Description {#bsls_atomicoperations_arm_all_gcc-description}
36/// This component provides classes necessary to implement atomics
37/// on the Linux ARM platform with GCC. The classes are for private use only.
38/// See @ref bsls_atomicoperations and @ref bsls_atomic for the public interface to
39/// atomics.
40///
41/// IMPLEMENTATION NOTES: Wherever possible we use atomic intrinsics that both
42/// GCC 4.6+ and Clang 3.2+ support. Otherwise the inline assembly code is
43/// used that can be compiled both by GCC and Clang. This puts some
44/// restrictions on the assembly code because Clang doesn't support register
45/// pairs that represent a 64bit value. So instead of `ldrexd %1, %H1, [%3]`
46/// the exact registers have to be specified, as in `ldrexd r2, r3, [%3]`. Note
47/// also that operations like `ldrexd` and `stdrexd` are supported only starting
48/// from `armv6zk`, so not every armv6 platform will work.
49///
50/// For more details on ARM atomic primitives see the Linux kernel source code
51/// (arch/arm/include/asm/atomic.h) and the "C/C++11 mappings to processors"
52/// (http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html), and the
53/// "ARM1156T2F-S Technical Reference Manual"
54/// (http://infocenter.arm.com/help/index.jsp?
55/// topic=/com.arm.doc.ddi0290g/Babebdcb.html), which contains documentation on
56/// the p15 coprocessor opcodes used in this component).
57/// @}
58/** @} */
59/** @} */
60
61/** @addtogroup bsl
62 * @{
63 */
64/** @addtogroup bsls
65 * @{
66 */
67/** @addtogroup bsls_atomicoperations_arm_all_gcc
68 * @{
69 */
70
71#include <bsls_atomicoperations_default.h>
72#include <bsls_platform.h>
73#include <bsls_types.h>
74
75#if defined(BSLS_PLATFORM_CPU_ARM) \
76 && (defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG))
77
78
79
80namespace bsls {
81
82struct AtomicOperations_ARM_ALL_GCC;
83typedef AtomicOperations_ARM_ALL_GCC AtomicOperations_Imp;
84
85 // ======================================================
86 // struct Atomic_TypeTraits<AtomicOperations_ARM_ALL_GCC>
87 // ======================================================
88
89template <>
90struct Atomic_TypeTraits<AtomicOperations_ARM_ALL_GCC>
91{
92 struct Int
93 {
94 volatile int d_value __attribute__((__aligned__(sizeof(int))));
95 };
96
97 struct Int64
98 {
99 volatile Types::Int64 d_value
100 __attribute__((__aligned__(sizeof(Types::Int64))));
101 };
102
103 struct Uint
104 {
105 volatile unsigned int d_value
106 __attribute__((__aligned__(sizeof(unsigned int))));
107 };
108
109 struct Uint64
110 {
111 volatile Types::Uint64 d_value
112 __attribute__((__aligned__(sizeof(Types::Uint64))));
113 };
114
115 struct Pointer
116 {
117 void * volatile d_value __attribute__((__aligned__(sizeof(void *))));
118 };
119};
120
121 // ===================================
122 // struct AtomicOperations_ARM_ALL_GCC
123 // ===================================
124
125struct AtomicOperations_ARM_ALL_GCC
126 : AtomicOperations_Default32<AtomicOperations_ARM_ALL_GCC>
127{
128private:
129 // PRIVATE TYPES
130 struct Int64_Words {
131 int w1;
132 int w2;
133 };
134
135public:
136 typedef Atomic_TypeTraits<AtomicOperations_ARM_ALL_GCC> AtomicTypes;
137
138 // *** atomic functions for int ***
139
140 static int getInt(const AtomicTypes::Int *atomicInt);
141
142 static int getIntAcquire(const AtomicTypes::Int *atomicInt);
143
144 static void setInt(AtomicTypes::Int *atomicInt, int value);
145
146 static void setIntRelease(AtomicTypes::Int *atomicInt, int value);
147
148 static int swapInt(AtomicTypes::Int *atomicInt, int swapValue);
149
150 static int testAndSwapInt(AtomicTypes::Int *atomicInt,
151 int compareValue,
152 int swapValue);
153
154 static int addIntNv(AtomicTypes::Int *atomicInt, int value);
155
156 // *** atomic functions for Int64 ***
157
158 static Types::Int64 getInt64(const AtomicTypes::Int64 *atomicInt);
159
160 static void setInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 value);
161
162 static Types::Int64 swapInt64(AtomicTypes::Int64 *atomicInt,
163 Types::Int64 swapValue);
164
165 static Types::Int64 testAndSwapInt64(AtomicTypes::Int64 *atomicInt,
166 Types::Int64 compareValue,
167 Types::Int64 swapValue);
168
169 static Types::Int64 addInt64Nv(AtomicTypes::Int64 *atomicInt,
170 Types::Int64 value);
171};
172
173// ===========================================================================
174// INLINE FUNCTION DEFINITIONS
175// ===========================================================================
176
177 // -----------------------------------
178 // struct AtomicOperations_ARM_ALL_GCC
179 // -----------------------------------
180
181#if BSLS_PLATFORM_CMP_VERSION < 40700
182# if defined(BSLS_PLATFORM_CPU_ARM_V7)
183
184# define BSLS_ATOMICOPERATIONS_BARRIER() \
185 asm volatile ("dmb" ::: "memory") \
186
187# define BSLS_ATOMICOPERATIONS_INSTR_BARRIER() \
188 asm volatile ("isb") \
189
190# else
191
192# define BSLS_ATOMICOPERATIONS_BARRIER() \
193 do { \
194 int temp_reg = 0; \
195 asm volatile ( \
196 "mcr p15, 0, %[temp_reg], c7, c10, 5 \n\t" \
197 : \
198 : [temp_reg] "r" (temp_reg) \
199 : "memory"); \
200 } while (0) \
201
202# define BSLS_ATOMICOPERATIONS_INSTR_BARRIER() \
203 do { \
204 int temp_reg = 0; \
205 asm volatile ( \
206 "mcr p15, 0, %[temp_reg], c7, c5, 4 \n\t" \
207 : \
208 : [temp_reg] "r" (temp_reg)); \
209 } while (0) \
210
211# endif
212#else
213# define BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
214#endif
215
216inline
217int AtomicOperations_ARM_ALL_GCC::
218 getInt(const AtomicTypes::Int *atomicInt)
219{
220#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
221 return __atomic_load_n(&atomicInt->d_value, __ATOMIC_SEQ_CST);
222#else
223 int result = atomicInt->d_value;
224 BSLS_ATOMICOPERATIONS_BARRIER();
225
226 return result;
227
228#endif
229}
230
231inline
232int AtomicOperations_ARM_ALL_GCC::
233 getIntAcquire(const AtomicTypes::Int *atomicInt)
234{
235#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
236 return __atomic_load_n(&atomicInt->d_value, __ATOMIC_ACQUIRE);
237#else
238 return getInt(atomicInt);
239#endif
240}
241
242inline
243void AtomicOperations_ARM_ALL_GCC::
244 setInt(AtomicTypes::Int *atomicInt, int value)
245{
246#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
247 __atomic_store_n(&atomicInt->d_value, value, __ATOMIC_SEQ_CST);
248#else
249 BSLS_ATOMICOPERATIONS_BARRIER();
250 atomicInt->d_value = value;
251 BSLS_ATOMICOPERATIONS_BARRIER();
252#endif
253}
254
255inline
256void AtomicOperations_ARM_ALL_GCC::
257 setIntRelease(AtomicTypes::Int *atomicInt, int value)
258{
259#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
260 __atomic_store_n(&atomicInt->d_value, value, __ATOMIC_RELEASE);
261#else
262 BSLS_ATOMICOPERATIONS_BARRIER();
263 setInt(atomicInt, value);
264#endif
265}
266
267inline
268int AtomicOperations_ARM_ALL_GCC::
269 swapInt(AtomicTypes::Int *atomicInt, int swapValue)
270{
271#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
272 return __atomic_exchange_n(&atomicInt->d_value,
273 swapValue,
274 __ATOMIC_SEQ_CST);
275#else
276 int oldValue;
277 int tmp;
278
279 BSLS_ATOMICOPERATIONS_BARRIER();
280
281 asm volatile (
282 "1: ldrex %[old], [%3] \n\t"
283 " strex %[tmp], %[val], [%3] \n\t"
284 " teq %[tmp], #0 \n\t"
285 " bne 1b \n\t"
286
287 : [old] "=&r" (oldValue),
288 [tmp] "=&r" (tmp),
289 "+Qo" (*atomicInt)
290 : "r" (atomicInt),
291 [val] "r" (swapValue)
292 : "cc", "memory");
293
294 BSLS_ATOMICOPERATIONS_INSTR_BARRIER();
295
296 return oldValue;
297#endif
298}
299
300inline
301int AtomicOperations_ARM_ALL_GCC::
302 testAndSwapInt(AtomicTypes::Int *atomicInt,
303 int compareValue,
304 int swapValue)
305{
306#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
307 __atomic_compare_exchange_n(&atomicInt->d_value, &compareValue, swapValue,
308 false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
309 return compareValue;
310#else
311 return __sync_val_compare_and_swap(&atomicInt->d_value,
312 compareValue,
313 swapValue);
314#endif
315}
316
317inline
318int AtomicOperations_ARM_ALL_GCC::
319 addIntNv(AtomicTypes::Int *atomicInt, int value)
320{
321#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
322 return __atomic_add_fetch(&atomicInt->d_value, value, __ATOMIC_SEQ_CST);
323#else
324 return __sync_add_and_fetch(&atomicInt->d_value, value);
325#endif
326}
327
328inline
329Types::Int64 AtomicOperations_ARM_ALL_GCC::
330 getInt64(const AtomicTypes::Int64 *atomicInt)
331{
332#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
333 return __atomic_load_n(&atomicInt->d_value, __ATOMIC_SEQ_CST);
334#else
335 Types::Int64 result;
336
337 asm volatile (
338 " ldrexd r2, r3, [%2] \n\t"
339 " mov %[res1], r2 \n\t"
340 " mov %[res2], r3 \n\t"
341
342 : [res1] "=&r" (((Int64_Words &) result).w1),
343 [res2] "=&r" (((Int64_Words &) result).w2)
344 : "r" (atomicInt),
345 "Qo" (*atomicInt)
346 : "r2", "r3");
347
348 BSLS_ATOMICOPERATIONS_BARRIER();
349
350 return result;
351#endif
352}
353
354inline
355void AtomicOperations_ARM_ALL_GCC::
356 setInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 value)
357{
358#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
359 return __atomic_store_n(&atomicInt->d_value, value, __ATOMIC_SEQ_CST);
360#else
361 swapInt64(atomicInt, value);
362#endif
363}
364
365inline
366Types::Int64 AtomicOperations_ARM_ALL_GCC::
367 swapInt64(AtomicTypes::Int64 *atomicInt,
368 Types::Int64 swapValue)
369{
370#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
371 return __atomic_exchange_n(&atomicInt->d_value,
372 swapValue,
373 __ATOMIC_SEQ_CST);
374#else
375 Types::Int64 oldValue;
376 int rc;
377
378 BSLS_ATOMICOPERATIONS_BARRIER();
379
380 asm volatile (
381 "1: ldrexd r2, r3, [%4] \n\t"
382 " mov %[old1], r2 \n\t"
383 " mov %[old2], r3 \n\t"
384 " mov r2, %[val1] \n\t"
385 " mov r3, %[val2] \n\t"
386 " strexd %[rc], r2, r3, [%4] \n\t"
387 " teq %[rc], #0 \n\t"
388 " bne 1b \n\t"
389
390 : [rc] "=&r" (rc),
391 [old1] "=&r" (((Int64_Words &) oldValue).w1),
392 [old2] "=&r" (((Int64_Words &) oldValue).w2),
393 "+Qo" (*atomicInt)
394 : "r" (atomicInt),
395 [val1] "r" (((Int64_Words &) swapValue).w1),
396 [val2] "r" (((Int64_Words &) swapValue).w2)
397 : "r2", "r3", "cc", "memory");
398
399 BSLS_ATOMICOPERATIONS_INSTR_BARRIER();
400
401 return oldValue;
402#endif
403}
404
405inline
406Types::Int64 AtomicOperations_ARM_ALL_GCC::
407 testAndSwapInt64(AtomicTypes::Int64 *atomicInt,
408 Types::Int64 compareValue,
409 Types::Int64 swapValue)
410{
411#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
412 __atomic_compare_exchange_n(&atomicInt->d_value,
413 &compareValue,
414 swapValue,
415 false,
416 __ATOMIC_SEQ_CST,
417 __ATOMIC_SEQ_CST);
418 return compareValue;
419#else
420 Types::Int64 oldValue;
421 int rc;
422
423 BSLS_ATOMICOPERATIONS_BARRIER();
424
425 asm volatile (
426 "1: ldrexd r2, r3, [%4] \n\t"
427 " mov %[old1], r2 \n\t"
428 " mov %[old2], r3 \n\t"
429 " mov r2, %[val1] \n\t"
430 " mov r3, %[val2] \n\t"
431 " mov %[rc], #0 \n\t"
432 " teq %[old1], %[cmp1] \n\t"
433 " itt eq \n\t"
434 " teqeq %[old2], %[cmp2] \n\t"
435 " strexdeq %[rc], r2, r3, [%4] \n\t"
436 " teq %[rc], #0 \n\t"
437 " bne 1b \n\t"
438
439 : [rc] "=&r" (rc),
440 [old1] "=&r" (((Int64_Words &) oldValue).w1),
441 [old2] "=&r" (((Int64_Words &) oldValue).w2),
442 "+Qo" (*atomicInt)
443 : "r" (atomicInt),
444 [cmp1] "r" (((Int64_Words &) compareValue).w1),
445 [cmp2] "r" (((Int64_Words &) compareValue).w2),
446 [val1] "r" (((Int64_Words &) swapValue).w1),
447 [val2] "r" (((Int64_Words &) swapValue).w2)
448 : "r2", "r3", "cc", "memory");
449
450 BSLS_ATOMICOPERATIONS_INSTR_BARRIER();
451
452 return oldValue;
453#endif
454}
455
456inline
457Types::Int64 AtomicOperations_ARM_ALL_GCC::
458 addInt64Nv(AtomicTypes::Int64 *atomicInt,
459 Types::Int64 value)
460{
461#ifdef BSLS_ATOMICOPERATIONS_USE_CPP11_INTRINSICS
462 return __atomic_add_fetch(&atomicInt->d_value, value, __ATOMIC_SEQ_CST);
463#else
464 Types::Int64 old;
465 Types::Int64 newVal;
466 Types::Int64 prev = atomicInt->d_value;
467
468 do {
469 old = prev;
470 newVal = old + value;
471 } while (old != (prev = testAndSwapInt64(atomicInt, old, newVal)));
472
473 return newVal;
474#endif
475}
476
477} // close package namespace
478
479
480
481#endif // defined(BSLS_PLATFORM_CPU_ARM) && (CMP_GNU || CMP_CLANG)
482
483#endif
484
485// ----------------------------------------------------------------------------
486// Copyright 2013 Bloomberg Finance L.P.
487//
488// Licensed under the Apache License, Version 2.0 (the "License");
489// you may not use this file except in compliance with the License.
490// You may obtain a copy of the License at
491//
492// http://www.apache.org/licenses/LICENSE-2.0
493//
494// Unless required by applicable law or agreed to in writing, software
495// distributed under the License is distributed on an "AS IS" BASIS,
496// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
497// See the License for the specific language governing permissions and
498// limitations under the License.
499// ----------------------------- END-OF-FILE ----------------------------------
500
501/** @} */
502/** @} */
503/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlt_iso8601util.h:691
long long Int64
Definition bsls_types.h:132