v2 / thirdparty / libatomic_ops / atomic_ops / sysdeps / gcc / generic.h
247 lines · 213 sloc · 8.08 KB · f53b5d737fd636890520101e736ad29e20d3c322
Raw
1/*
2 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
3 * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
4 * Copyright (c) 2003-2011 Hewlett-Packard Development Company, L.P.
5 * Copyright (c) 2013-2017 Ivan Maidanski
6 *
7 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
9 *
10 * Permission is hereby granted to use or copy this program
11 * for any purpose, provided the above notices are retained on all copies.
12 * Permission to modify the code and to distribute modified code is granted,
13 * provided the above notices are retained, and a notice that the code was
14 * modified is included with the above copyright notice.
15 *
16 */
17
18/* The following implementation assumes GCC 4.7 or later. */
19/* For the details, see GNU Manual, chapter 6.52 (Built-in functions */
20/* for memory model aware atomic operations). */
21
22#define AO_GCC_ATOMIC_TEST_AND_SET
23#include "../test_and_set_t_is_char.h"
24
25#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) \
26 || defined(AO_GCC_FORCE_HAVE_CAS)
27# define AO_GCC_HAVE_char_SYNC_CAS
28#endif
29
30#if (__SIZEOF_SHORT__ == 2 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)) \
31 || defined(AO_GCC_FORCE_HAVE_CAS)
32# define AO_GCC_HAVE_short_SYNC_CAS
33#endif
34
35#if (__SIZEOF_INT__ == 4 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) \
36 || (__SIZEOF_INT__ == 8 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) \
37 || defined(AO_GCC_FORCE_HAVE_CAS)
38# define AO_GCC_HAVE_int_SYNC_CAS
39#endif
40
41#if (__SIZEOF_SIZE_T__ == 4 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) \
42 || (__SIZEOF_SIZE_T__ == 8 \
43 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) \
44 || defined(AO_GCC_FORCE_HAVE_CAS)
45# define AO_GCC_HAVE_SYNC_CAS
46#endif
47
48#undef AO_compiler_barrier
49#define AO_compiler_barrier() __atomic_signal_fence(__ATOMIC_SEQ_CST)
50
51#ifdef AO_UNIPROCESSOR
52 /* If only a single processor (core) is used, AO_UNIPROCESSOR could */
53 /* be defined by the client to avoid unnecessary memory barrier. */
54 AO_INLINE void
55 AO_nop_full(void)
56 {
57 AO_compiler_barrier();
58 }
59# define AO_HAVE_nop_full
60
61#elif defined(AO_THREAD_SANITIZER) && !defined(AO_USE_ATOMIC_THREAD_FENCE)
62 /* Workaround a compiler warning (reported by gcc-11, at least) */
63 /* that atomic_thread_fence is unsupported with thread sanitizer. */
64
65#else
66 AO_INLINE void
67 AO_nop_read(void)
68 {
69 __atomic_thread_fence(__ATOMIC_ACQUIRE);
70 }
71# define AO_HAVE_nop_read
72
73# ifndef AO_HAVE_nop_write
74 AO_INLINE void
75 AO_nop_write(void)
76 {
77 __atomic_thread_fence(__ATOMIC_RELEASE);
78 }
79# define AO_HAVE_nop_write
80# endif
81
82 AO_INLINE void
83 AO_nop_full(void)
84 {
85 /* __sync_synchronize() could be used instead. */
86 __atomic_thread_fence(__ATOMIC_SEQ_CST);
87 }
88# define AO_HAVE_nop_full
89#endif /* !AO_UNIPROCESSOR && !AO_THREAD_SANITIZER */
90
91#include "generic-small.h"
92
93#ifndef AO_PREFER_GENERALIZED
94# include "generic-arithm.h"
95
96# define AO_CLEAR(addr) __atomic_clear(addr, __ATOMIC_RELEASE)
97# define AO_HAVE_CLEAR
98
99 AO_INLINE AO_TS_VAL_t
100 AO_test_and_set(volatile AO_TS_t *addr)
101 {
102 return (AO_TS_VAL_t)(__atomic_test_and_set(addr, __ATOMIC_RELAXED)
103 ? AO_TS_SET : AO_TS_CLEAR);
104 }
105# define AO_HAVE_test_and_set
106
107 AO_INLINE AO_TS_VAL_t
108 AO_test_and_set_acquire(volatile AO_TS_t *addr)
109 {
110 return (AO_TS_VAL_t)(__atomic_test_and_set(addr, __ATOMIC_ACQUIRE)
111 ? AO_TS_SET : AO_TS_CLEAR);
112 }
113# define AO_HAVE_test_and_set_acquire
114
115 AO_INLINE AO_TS_VAL_t
116 AO_test_and_set_release(volatile AO_TS_t *addr)
117 {
118 return (AO_TS_VAL_t)(__atomic_test_and_set(addr, __ATOMIC_RELEASE)
119 ? AO_TS_SET : AO_TS_CLEAR);
120 }
121# define AO_HAVE_test_and_set_release
122
123 AO_INLINE AO_TS_VAL_t
124 AO_test_and_set_full(volatile AO_TS_t *addr)
125 {
126 return (AO_TS_VAL_t)(__atomic_test_and_set(addr, __ATOMIC_SEQ_CST)
127 ? AO_TS_SET : AO_TS_CLEAR);
128 }
129# define AO_HAVE_test_and_set_full
130#endif /* !AO_PREFER_GENERALIZED */
131
132#ifdef AO_HAVE_DOUBLE_PTR_STORAGE
133
134# if ((__SIZEOF_SIZE_T__ == 4 \
135 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) \
136 || (__SIZEOF_SIZE_T__ == 8 /* half of AO_double_t */ \
137 && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16))) \
138 && !defined(AO_SKIPATOMIC_double_compare_and_swap_ANY)
139# define AO_GCC_HAVE_double_SYNC_CAS
140# endif
141
142# if !defined(AO_GCC_HAVE_double_SYNC_CAS) || !defined(AO_PREFER_GENERALIZED)
143
144# if !defined(AO_HAVE_double_load) && !defined(AO_SKIPATOMIC_double_load)
145 AO_INLINE AO_double_t
146 AO_double_load(const volatile AO_double_t *addr)
147 {
148 AO_double_t result;
149
150 result.AO_whole = __atomic_load_n(&addr->AO_whole, __ATOMIC_RELAXED);
151 return result;
152 }
153# define AO_HAVE_double_load
154# endif
155
156# if !defined(AO_HAVE_double_load_acquire) \
157 && !defined(AO_SKIPATOMIC_double_load_acquire)
158 AO_INLINE AO_double_t
159 AO_double_load_acquire(const volatile AO_double_t *addr)
160 {
161 AO_double_t result;
162
163 result.AO_whole = __atomic_load_n(&addr->AO_whole, __ATOMIC_ACQUIRE);
164 return result;
165 }
166# define AO_HAVE_double_load_acquire
167# endif
168
169# if !defined(AO_HAVE_double_store) && !defined(AO_SKIPATOMIC_double_store)
170 AO_INLINE void
171 AO_double_store(volatile AO_double_t *addr, AO_double_t value)
172 {
173 __atomic_store_n(&addr->AO_whole, value.AO_whole, __ATOMIC_RELAXED);
174 }
175# define AO_HAVE_double_store
176# endif
177
178# if !defined(AO_HAVE_double_store_release) \
179 && !defined(AO_SKIPATOMIC_double_store_release)
180 AO_INLINE void
181 AO_double_store_release(volatile AO_double_t *addr, AO_double_t value)
182 {
183 __atomic_store_n(&addr->AO_whole, value.AO_whole, __ATOMIC_RELEASE);
184 }
185# define AO_HAVE_double_store_release
186# endif
187
188#endif /* !AO_GCC_HAVE_double_SYNC_CAS || !AO_PREFER_GENERALIZED */
189
190#endif /* AO_HAVE_DOUBLE_PTR_STORAGE */
191
192#ifdef AO_GCC_HAVE_double_SYNC_CAS
193# ifndef AO_HAVE_double_compare_and_swap
194 AO_INLINE int
195 AO_double_compare_and_swap(volatile AO_double_t *addr,
196 AO_double_t old_val, AO_double_t new_val)
197 {
198 return (int)__atomic_compare_exchange_n(&addr->AO_whole,
199 &old_val.AO_whole /* p_expected */,
200 new_val.AO_whole /* desired */,
201 0 /* is_weak: false */,
202 __ATOMIC_RELAXED /* success */,
203 __ATOMIC_RELAXED /* failure */);
204 }
205# define AO_HAVE_double_compare_and_swap
206# endif
207
208# ifndef AO_HAVE_double_compare_and_swap_acquire
209 AO_INLINE int
210 AO_double_compare_and_swap_acquire(volatile AO_double_t *addr,
211 AO_double_t old_val,
212 AO_double_t new_val)
213 {
214 return (int)__atomic_compare_exchange_n(&addr->AO_whole,
215 &old_val.AO_whole, new_val.AO_whole, 0,
216 __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
217 }
218# define AO_HAVE_double_compare_and_swap_acquire
219# endif
220
221# ifndef AO_HAVE_double_compare_and_swap_release
222 AO_INLINE int
223 AO_double_compare_and_swap_release(volatile AO_double_t *addr,
224 AO_double_t old_val,
225 AO_double_t new_val)
226 {
227 return (int)__atomic_compare_exchange_n(&addr->AO_whole,
228 &old_val.AO_whole, new_val.AO_whole, 0,
229 __ATOMIC_RELEASE,
230 __ATOMIC_RELAXED /* failure */);
231 }
232# define AO_HAVE_double_compare_and_swap_release
233# endif
234
235# ifndef AO_HAVE_double_compare_and_swap_full
236 AO_INLINE int
237 AO_double_compare_and_swap_full(volatile AO_double_t *addr,
238 AO_double_t old_val, AO_double_t new_val)
239 {
240 return (int)__atomic_compare_exchange_n(&addr->AO_whole,
241 &old_val.AO_whole, new_val.AO_whole, 0,
242 __ATOMIC_ACQ_REL,
243 __ATOMIC_ACQUIRE /* failure */);
244 }
245# define AO_HAVE_double_compare_and_swap_full
246# endif
247#endif /* AO_GCC_HAVE_double_SYNC_CAS */
248