EPICS Base  7.0.5.1
epicsAtomicCD.h
1 
2 /*************************************************************************\
3 * Copyright (c) 2011 LANS LLC, as Operator of
4 * Los Alamos National Laboratory.
5 * Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
6 * National Laboratory.
7 * SPDX-License-Identifier: EPICS
8 * EPICS BASE is distributed subject to a Software License Agreement found
9 * in file LICENSE that is included with this distribution.
10 \*************************************************************************/
11 
12 /*
13  * Author Jeffrey O. Hill
14  * johill@lanl.gov
15  */
16 
17 #ifndef epicsAtomicCD_h
18 #define epicsAtomicCD_h
19 
20 #ifndef __GNUC__
21 # error this header is only for use with the gnu compiler
22 #endif
23 
24 #define EPICS_ATOMIC_CMPLR_NAME "GCC"
25 
26 #define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B)
27 #define GCC_ATOMIC_CONCATR( A, B ) ( A ## B )
28 
29 #define GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
30  GCC_ATOMIC_CONCAT ( \
31  __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
32  __SIZEOF_INT__ )
33 
34 #define GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
35  GCC_ATOMIC_CONCAT ( \
36  __GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
37  __SIZEOF_SIZE_T__ )
38 
39 #define GCC_ATOMIC_INTRINSICS_MIN_X86 \
40  ( defined ( __i486 ) || defined ( __pentium ) || \
41  defined ( __pentiumpro ) || defined ( __MMX__ ) )
42 
43 #define GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER \
44  ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 )
45 
46 #define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \
47  ( GCC_ATOMIC_INTRINSICS_MIN_X86 && \
48  GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER )
49 
50 #ifdef __cplusplus
51 extern "C" {
52 #endif
53 
54 /*
55  * We are optimistic that __sync_synchronize is implemented
56  * in all version four gcc invariant of target. The gnu doc
57  * seems to say that when not supported by architecture a call
58  * to an external function is generated but in practice
59  * this isn`t the case for some of the atomic intrinsics, and
60  * so there is an undefined symbol. So far we have not seen
61  * that with __sync_synchronize, but we can only guess based
62  * on experimental evidence.
63  *
64  * For example we know that when generating object code for
65  * 386 most of the atomic intrinsics are not present and
66  * we see undefined symbols with mingw, but we don`t have
67  * troubles with __sync_synchronize.
68  */
69 #if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER
70 
71 #ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
72 #define EPICS_ATOMIC_READ_MEMORY_BARRIER
73 EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier (void)
74 {
75  __sync_synchronize ();
76 }
77 #endif
78 
79 #ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
80 #define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
81 EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier (void)
82 {
83  __sync_synchronize ();
84 }
85 #endif
86 
87 #else
88 
89 #ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
90 #if GCC_ATOMIC_INTRINSICS_MIN_X86
91 #define EPICS_ATOMIC_READ_MEMORY_BARRIER
92 EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier (void)
93 {
94  asm("mfence;");
95 }
96 #endif
97 #endif
98 
99 #ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
100 #if GCC_ATOMIC_INTRINSICS_MIN_X86
101 #define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
102 EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier (void)
103 {
104  asm("mfence;");
105 }
106 #endif
107 #endif
108 
109 #endif /* if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER */
110 
111 #if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
112  || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER
113 
114 #define EPICS_ATOMIC_INCR_INTT
115 EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
116 {
117  return __sync_add_and_fetch ( pTarget, 1 );
118 }
119 
120 #define EPICS_ATOMIC_DECR_INTT
121 EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
122 {
123  return __sync_sub_and_fetch ( pTarget, 1 );
124 }
125 
126 #define EPICS_ATOMIC_ADD_INTT
127 EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
128 {
129  return __sync_add_and_fetch ( pTarget, delta );
130 }
131 
132 #define EPICS_ATOMIC_CAS_INTT
133 EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
134  int oldVal, int newVal )
135 {
136  return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
137 }
138 
139 #endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T */
140 
141 #if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
142  || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER
143 
144 #define EPICS_ATOMIC_INCR_SIZET
145 EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
146 {
147  return __sync_add_and_fetch ( pTarget, 1u );
148 }
149 
150 #define EPICS_ATOMIC_DECR_SIZET
151 EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
152 {
153  return __sync_sub_and_fetch ( pTarget, 1u );
154 }
155 
156 #define EPICS_ATOMIC_ADD_SIZET
157 EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
158 {
159  return __sync_add_and_fetch ( pTarget, delta );
160 }
161 
162 #define EPICS_ATOMIC_SUB_SIZET
163 EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
164 {
165  return __sync_sub_and_fetch ( pTarget, delta );
166 }
167 
168 #define EPICS_ATOMIC_CAS_SIZET
169 EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
170  size_t oldVal, size_t newVal )
171 {
172  return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
173 }
174 
175 #define EPICS_ATOMIC_CAS_PTRT
176 EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
177  EpicsAtomicPtrT * pTarget,
178  EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
179 {
180  return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
181 }
182 
183 #endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T */
184 
185 #ifdef __cplusplus
186 } /* end of extern "C" */
187 #endif
188 
189 /*
190  * if currently unavailable as gcc intrinsics we
191  * will try for an os specific inline solution
192  */
193 #include "epicsAtomicOSD.h"
194 
195 #endif /* epicsAtomicCD_h */