rcutils  master
C API providing common utilities and data structures.
stdatomic.h
Go to the documentation of this file.
1 // Copyright 2015 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 /*
16  * An implementation of C11 stdatomic.h for Win32, part borrowed from FreeBSD
17  * (original copyright follows), with major modifications for
18  * portability to Win32 systems.
19  *
20  * Caveats and limitations:
21  * - Only the ``_Atomic parentheses'' notation is implemented, while
22  * the ``_Atomic space'' one is not.
23  * - _Atomic types must be typedef'ed, or programs using them will
24  * not type check correctly (incompatible anonymous structure
25  * types).
26  * - Support is limited to 16, 32, and 64 bit types only.
27  * - Stripped down to only the functions used in rcutils and dependents like rcl.
28  */
29 
30 /*-
31  * Copyright (c) 2011 Ed Schouten <ed@FreeBSD.org>
32  * David Chisnall <theraven@FreeBSD.org>
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  * notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  * notice, this list of conditions and the following disclaimer in the
42  * documentation and/or other materials provided with the distribution.
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54  * SUCH DAMAGE.
55  *
56  * $FreeBSD: src/include/stdatomic.h,v 1.10.2.2 2012/05/30 19:21:54 theraven Exp $
57  */
58 
59 #if !defined(_WIN32)
60 #error "this stdatomic.h does not support your compiler"
61 #endif // !defined(_WIN32)
62 
63 #ifndef RCUTILS__STDATOMIC_HELPER__WIN32__STDATOMIC_H_
64 #define RCUTILS__STDATOMIC_HELPER__WIN32__STDATOMIC_H_
65 
66 // When building with MSVC 19.28.29333.0 on Windows 10 (as of 2020-11-11),
67 // there appears to be a problem with winbase.h (which is included by
68 // Windows.h). In particular, warnings of the form:
69 //
70 // warning C5105: macro expansion producing 'defined' has undefined behavior
71 //
72 // See https://developercommunity.visualstudio.com/content/problem/695656/wdk-and-sdk-are-not-compatible-with-experimentalpr.html
73 // for more information. For now disable that warning when including windows.h
74 
75 #pragma warning(push)
76 #pragma warning(disable : 5105)
77 #include <Windows.h>
78 #pragma warning(pop)
79 
80 #include <stddef.h>
81 #include <stdint.h>
82 #include <stdio.h>
83 
84 #include <rcutils/logging_macros.h>
85 
86 // In MSVC, correct alignment of each type is already ensured.
87 #define _Atomic(T) struct { T __val; }
88 
89 /*
90  * 7.17.2 Initialization.
91  */
92 
93 #define ATOMIC_VAR_INIT(value) {.__val = (value)}
94 #define atomic_init(obj, value) do { \
95  (obj)->__val = (value); \
96 } while (0)
97 
98 /*
99  * Clang and recent GCC both provide predefined macros for the memory
100  * orderings. If we are using a compiler that doesn't define them, use the
101  * clang values - these will be ignored in the fallback path.
102  */
103 
104 #ifndef __ATOMIC_RELAXED
105 #define __ATOMIC_RELAXED 0
106 #endif
107 #ifndef __ATOMIC_CONSUME
108 #define __ATOMIC_CONSUME 1
109 #endif
110 #ifndef __ATOMIC_ACQUIRE
111 #define __ATOMIC_ACQUIRE 2
112 #endif
113 #ifndef __ATOMIC_RELEASE
114 #define __ATOMIC_RELEASE 3
115 #endif
116 #ifndef __ATOMIC_ACQ_REL
117 #define __ATOMIC_ACQ_REL 4
118 #endif
119 #ifndef __ATOMIC_SEQ_CST
120 #define __ATOMIC_SEQ_CST 5
121 #endif
122 
123 /*
124  * 7.17.3 Order and consistency.
125  *
126  * The memory_order_* constants that denote the barrier behaviour of the
127  * atomic operations.
128  */
129 
131 {
138 };
139 
141 
142 /*
143  * 7.17.4 Fences.
144  */
145 
146 #define atomic_thread_fence(order) MemoryBarrier()
147 #define atomic_signal_fence(order) _ReadWriteBarrier()
148 
149 /*
150  * 7.17.5 Lock-free property.
151  */
152 
153 #define atomic_is_lock_free(obj) (sizeof((obj)->__val) <= sizeof(void *))
154 
155 /*
156  * 7.17.6 Atomic integer types.
157  */
158 
159 typedef _Atomic (_Bool) atomic_bool;
160 typedef _Atomic (char) atomic_char;
161 typedef _Atomic (signed char) atomic_schar;
162 typedef _Atomic (unsigned char) atomic_uchar;
163 typedef _Atomic (short) atomic_short; // NOLINT
164 typedef _Atomic (unsigned short) atomic_ushort; // NOLINT
165 typedef _Atomic (int) atomic_int;
166 typedef _Atomic (unsigned int) atomic_uint;
167 typedef _Atomic (long) atomic_long; // NOLINT
168 typedef _Atomic (unsigned long) atomic_ulong; // NOLINT
169 typedef _Atomic (long long) atomic_llong; // NOLINT
170 typedef _Atomic (unsigned long long) atomic_ullong; // NOLINT
171 #if 0
172 typedef _Atomic (char16_t) atomic_char16_t;
173 typedef _Atomic (char32_t) atomic_char32_t;
174 typedef _Atomic (wchar_t) atomic_wchar_t;
175 typedef _Atomic (int_least8_t) atomic_int_least8_t;
176 typedef _Atomic (uint_least8_t) atomic_uint_least8_t;
177 #endif
178 typedef _Atomic (int_least16_t) atomic_int_least16_t;
179 typedef _Atomic (uint_least16_t) atomic_uint_least16_t;
180 typedef _Atomic (int_least32_t) atomic_int_least32_t;
181 typedef _Atomic (uint_least32_t) atomic_uint_least32_t;
182 typedef _Atomic (int_least64_t) atomic_int_least64_t;
183 typedef _Atomic (uint_least64_t) atomic_uint_least64_t;
184 #if 0
185 typedef _Atomic (int_fast8_t) atomic_int_fast8_t;
186 typedef _Atomic (uint_fast8_t) atomic_uint_fast8_t;
187 #endif
188 typedef _Atomic (int_fast16_t) atomic_int_fast16_t;
189 typedef _Atomic (uint_fast16_t) atomic_uint_fast16_t;
190 typedef _Atomic (int_fast32_t) atomic_int_fast32_t;
191 typedef _Atomic (uint_fast32_t) atomic_uint_fast32_t;
192 typedef _Atomic (int_fast64_t) atomic_int_fast64_t;
193 typedef _Atomic (uint_fast64_t) atomic_uint_fast64_t;
194 typedef _Atomic (intptr_t) atomic_intptr_t;
195 typedef _Atomic (uintptr_t) atomic_uintptr_t;
196 typedef _Atomic (size_t) atomic_size_t;
197 typedef _Atomic (ptrdiff_t) atomic_ptrdiff_t;
198 typedef _Atomic (intmax_t) atomic_intmax_t;
199 typedef _Atomic (uintmax_t) atomic_uintmax_t;
200 
201 #ifdef ROS_PACKAGE_NAME
202  #define _RCUTILS_PACKAGE_NAME ROS_PACKAGE_NAME
203 #else
204  #define _RCUTILS_PACKAGE_NAME "<Unknown Package>"
205 #endif
206 
207 /*
208  * 7.17.7 Operations on atomic types. (pruned modified for Windows' crappy C compiler)
209  */
210 
211 // TODO(emersonknapp) Regression in uncrustify breaks formatting for macros with __pragma
212 // remove indent-off when we have fix for https://github.com/uncrustify/uncrustify/issues/2314
213 // *INDENT-OFF*
214 
215 #define rcutils_win32_atomic_compare_exchange_strong(object, out, expected, desired) \
216  __pragma(warning(push)) \
217  __pragma(warning(disable: 4244)) \
218  __pragma(warning(disable: 4047)) \
219  __pragma(warning(disable: 4024)) \
220  do { \
221  switch (sizeof(out)) { \
222  case sizeof(uint64_t): \
223  out = InterlockedCompareExchange64((LONGLONG *) object, desired, *expected); \
224  break; \
225  case sizeof(uint32_t): \
226  out = _InterlockedCompareExchange((LONG *) object, desired, *expected); \
227  break; \
228  case sizeof(uint16_t): \
229  out = _InterlockedCompareExchange16((SHORT *) object, desired, *expected); \
230  break; \
231  case sizeof(uint8_t): \
232  out = _InterlockedCompareExchange8((char *) object, desired, *expected); \
233  break; \
234  default: \
235  RCUTILS_LOG_ERROR_NAMED( \
236  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_compare_exchange_strong"); \
237  exit(-1); \
238  break; \
239  } \
240  } while (0); \
241  __pragma(warning(pop))
242 
243 #define rcutils_win32_atomic_compare_exchange_weak(object, out, expected, desired) \
244  rcutils_win32_atomic_compare_exchange_strong(object, out, expected, desired)
245 
246 #define rcutils_win32_atomic_exchange(object, out, desired) \
247  __pragma(warning(push)) \
248  __pragma(warning(disable: 4244)) \
249  __pragma(warning(disable: 4047)) \
250  __pragma(warning(disable: 4024)) \
251  do { \
252  switch (sizeof(out)) { \
253  case sizeof(uint64_t): \
254  out = InterlockedExchange64((LONGLONG *) object, desired); \
255  break; \
256  case sizeof(uint32_t): \
257  out = _InterlockedExchange((LONG *) object, desired); \
258  break; \
259  case sizeof(uint16_t): \
260  out = _InterlockedExchange16((SHORT *) object, desired); \
261  break; \
262  case sizeof(uint8_t): \
263  out = _InterlockedExchange8((char *) object, desired); \
264  break; \
265  default: \
266  RCUTILS_LOG_ERROR_NAMED( \
267  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_exchange_strong"); \
268  exit(-1); \
269  break; \
270  } \
271  } while (0); \
272  __pragma(warning(pop))
273 
274 #define rcutils_win32_atomic_fetch_add(object, out, operand) \
275  __pragma(warning(push)) \
276  __pragma(warning(disable: 4244)) \
277  __pragma(warning(disable: 4047)) \
278  __pragma(warning(disable: 4024)) \
279  do { \
280  switch (sizeof(out)) { \
281  case sizeof(uint64_t): \
282  out = InterlockedExchangeAdd64((LONGLONG *) object, operand); \
283  break; \
284  case sizeof(uint32_t): \
285  out = _InterlockedExchangeAdd((LONG *) object, operand); \
286  break; \
287  case sizeof(uint16_t): \
288  out = _InterlockedExchangeAdd16((SHORT *) object, operand); \
289  break; \
290  case sizeof(uint8_t): \
291  out = _InterlockedExchangeAdd8((char *) object, operand); \
292  break; \
293  default: \
294  RCUTILS_LOG_ERROR_NAMED( \
295  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_add"); \
296  exit(-1); \
297  break; \
298  } \
299  } while (0); \
300  __pragma(warning(pop))
301 
302 #define rcutils_win32_atomic_fetch_and(object, out, operand) \
303  __pragma(warning(push)) \
304  __pragma(warning(disable: 4244)) \
305  __pragma(warning(disable: 4047)) \
306  __pragma(warning(disable: 4024)) \
307  do { \
308  switch (sizeof(out)) { \
309  case sizeof(uint64_t): \
310  out = InterlockedAnd64((LONGLONG *) object, operand); \
311  break; \
312  case sizeof(uint32_t): \
313  out = _InterlockedAnd((LONG *) object, operand); \
314  break; \
315  case sizeof(uint16_t): \
316  out = _InterlockedAnd16((SHORT *) object, operand); \
317  break; \
318  case sizeof(uint8_t): \
319  out = _InterlockedAnd8((char *) object, operand); \
320  break; \
321  default: \
322  RCUTILS_LOG_ERROR_NAMED( \
323  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_and"); \
324  exit(-1); \
325  break; \
326  } \
327  } while (0); \
328  __pragma(warning(pop))
329 
330 #define rcutils_win32_atomic_fetch_or(object, out, operand) \
331  __pragma(warning(push)) \
332  __pragma(warning(disable: 4244)) \
333  __pragma(warning(disable: 4047)) \
334  __pragma(warning(disable: 4024)) \
335  do { \
336  switch (sizeof(out)) { \
337  case sizeof(uint64_t): \
338  out = InterlockedOr64((LONGLONG *) object, operand); \
339  break; \
340  case sizeof(uint32_t): \
341  out = _InterlockedOr((LONG *) object, operand); \
342  break; \
343  case sizeof(uint16_t): \
344  out = _InterlockedOr16((SHORT *) object, operand); \
345  break; \
346  case sizeof(uint8_t): \
347  out = _InterlockedOr8((char *) object, operand); \
348  break; \
349  default: \
350  RCUTILS_LOG_ERROR_NAMED( \
351  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_or"); \
352  exit(-1); \
353  break; \
354  } \
355  } while (0); \
356  __pragma(warning(pop))
357 
358 #define rcutils_win32_atomic_fetch_sub(object, out, operand) \
359  rcutils_win32_atomic_fetch_add(object, out, -(operand))
360 
361 #define rcutils_win32_atomic_fetch_xor(object, out, operand) \
362  __pragma(warning(push)) \
363  __pragma(warning(disable: 4244)) \
364  __pragma(warning(disable: 4047)) \
365  __pragma(warning(disable: 4024)) \
366  do { \
367  switch (sizeof(out)) { \
368  case sizeof(uint64_t): \
369  out = InterlockedXor64((LONGLONG *) object, operand); \
370  break; \
371  case sizeof(uint32_t): \
372  out = _InterlockedXor((LONG *) object, operand); \
373  break; \
374  case sizeof(uint16_t): \
375  out = _InterlockedXor16((SHORT *) object, operand); \
376  break; \
377  case sizeof(uint8_t): \
378  out = _InterlockedXor8((char *) object, operand); \
379  break; \
380  default: \
381  RCUTILS_LOG_ERROR_NAMED( \
382  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_xor"); \
383  exit(-1); \
384  break; \
385  } \
386  } while (0); \
387  __pragma(warning(pop))
388 
389 #define rcutils_win32_atomic_load(object, out) \
390  __pragma(warning(push)) \
391  __pragma(warning(disable: 4244)) \
392  __pragma(warning(disable: 4047)) \
393  __pragma(warning(disable: 4024)) \
394  do { \
395  switch (sizeof(out)) { \
396  case sizeof(uint64_t): \
397  out = InterlockedExchangeAdd64((LONGLONG *) object, 0); \
398  break; \
399  case sizeof(uint32_t): \
400  out = _InterlockedExchangeAdd((LONG *) object, 0); \
401  break; \
402  case sizeof(uint16_t): \
403  out = _InterlockedExchangeAdd16((SHORT *) object, 0); \
404  break; \
405  case sizeof(uint8_t): \
406  out = _InterlockedExchangeAdd8((char *) object, 0); \
407  break; \
408  default: \
409  RCUTILS_LOG_ERROR_NAMED( \
410  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_load"); \
411  exit(-1); \
412  break; \
413  } \
414  } while (0); \
415  __pragma(warning(pop))
416 
417 // *INDENT-ON*
418 
419 #define rcutils_win32_atomic_store(object, desired) \
420  do { \
421  MemoryBarrier(); \
422  (object)->__val = (desired); \
423  MemoryBarrier(); \
424  } while (0)
425 
426 /*
427  * 7.17.8 Atomic flag type and operations. (disabled for now)
428  */
429 
430 // typedef atomic_bool atomic_flag;
431 
432 // #define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0)
433 
434 // #define atomic_flag_clear_explicit(object, order) \
435 // atomic_store_explicit(object, 0, order)
436 // #define atomic_flag_test_and_set_explicit(object, order) \
437 // atomic_compare_exchange_strong_explicit(object, 0, 1, order, order)
438 
439 // #define atomic_flag_clear(object) \
440 // atomic_flag_clear_explicit(object, memory_order_seq_cst)
441 // #define atomic_flag_test_and_set(object) \
442 // atomic_flag_test_and_set_explicit(object, memory_order_seq_cst)
443 
444 #endif // RCUTILS__STDATOMIC_HELPER__WIN32__STDATOMIC_H_
memory_order_consume
@ memory_order_consume
Definition: stdatomic.h:162
_Atomic
#define _Atomic(T)
Definition: stdatomic.h:87
__ATOMIC_ACQUIRE
#define __ATOMIC_ACQUIRE
Definition: stdatomic.h:111
memory_order_release
@ memory_order_release
Definition: stdatomic.h:164
memory_order
memory_order
Definition: stdatomic.h:160
__ATOMIC_ACQ_REL
#define __ATOMIC_ACQ_REL
Definition: stdatomic.h:117
logging_macros.h
memory_order_acq_rel
@ memory_order_acq_rel
Definition: stdatomic.h:165
__ATOMIC_RELAXED
#define __ATOMIC_RELAXED
Definition: stdatomic.h:105
memory_order_acquire
@ memory_order_acquire
Definition: stdatomic.h:163
memory_order_seq_cst
@ memory_order_seq_cst
Definition: stdatomic.h:166
memory_order_relaxed
@ memory_order_relaxed
Definition: stdatomic.h:161
__ATOMIC_RELEASE
#define __ATOMIC_RELEASE
Definition: stdatomic.h:114
__ATOMIC_CONSUME
#define __ATOMIC_CONSUME
Definition: stdatomic.h:108
__ATOMIC_SEQ_CST
#define __ATOMIC_SEQ_CST
Definition: stdatomic.h:120