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 #include <Windows.h>
67 
68 #include <stddef.h>
69 #include <stdint.h>
70 #include <stdio.h>
71 
72 #include <rcutils/logging_macros.h>
73 
74 // In MSVC, correct alignment of each type is already ensured.
75 #define _Atomic(T) struct { T __val; }
76 
77 /*
78  * 7.17.2 Initialization.
79  */
80 
81 #define ATOMIC_VAR_INIT(value) {.__val = (value)}
82 #define atomic_init(obj, value) do { \
83  (obj)->__val = (value); \
84 } while (0)
85 
86 /*
87  * Clang and recent GCC both provide predefined macros for the memory
88  * orderings. If we are using a compiler that doesn't define them, use the
89  * clang values - these will be ignored in the fallback path.
90  */
91 
92 #ifndef __ATOMIC_RELAXED
93 #define __ATOMIC_RELAXED 0
94 #endif
95 #ifndef __ATOMIC_CONSUME
96 #define __ATOMIC_CONSUME 1
97 #endif
98 #ifndef __ATOMIC_ACQUIRE
99 #define __ATOMIC_ACQUIRE 2
100 #endif
101 #ifndef __ATOMIC_RELEASE
102 #define __ATOMIC_RELEASE 3
103 #endif
104 #ifndef __ATOMIC_ACQ_REL
105 #define __ATOMIC_ACQ_REL 4
106 #endif
107 #ifndef __ATOMIC_SEQ_CST
108 #define __ATOMIC_SEQ_CST 5
109 #endif
110 
111 /*
112  * 7.17.3 Order and consistency.
113  *
114  * The memory_order_* constants that denote the barrier behaviour of the
115  * atomic operations.
116  */
117 
119 {
126 };
127 
129 
130 /*
131  * 7.17.4 Fences.
132  */
133 
134 #define atomic_thread_fence(order) MemoryBarrier()
135 #define atomic_signal_fence(order) _ReadWriteBarrier()
136 
137 /*
138  * 7.17.5 Lock-free property.
139  */
140 
141 #define atomic_is_lock_free(obj) (sizeof((obj)->__val) <= sizeof(void *))
142 
143 /*
144  * 7.17.6 Atomic integer types.
145  */
146 
147 typedef _Atomic (_Bool) atomic_bool;
148 typedef _Atomic (char) atomic_char;
149 typedef _Atomic (signed char) atomic_schar;
150 typedef _Atomic (unsigned char) atomic_uchar;
151 typedef _Atomic (short) atomic_short; // NOLINT
152 typedef _Atomic (unsigned short) atomic_ushort; // NOLINT
153 typedef _Atomic (int) atomic_int;
154 typedef _Atomic (unsigned int) atomic_uint;
155 typedef _Atomic (long) atomic_long; // NOLINT
156 typedef _Atomic (unsigned long) atomic_ulong; // NOLINT
157 typedef _Atomic (long long) atomic_llong; // NOLINT
158 typedef _Atomic (unsigned long long) atomic_ullong; // NOLINT
159 #if 0
160 typedef _Atomic (char16_t) atomic_char16_t;
161 typedef _Atomic (char32_t) atomic_char32_t;
162 typedef _Atomic (wchar_t) atomic_wchar_t;
163 typedef _Atomic (int_least8_t) atomic_int_least8_t;
164 typedef _Atomic (uint_least8_t) atomic_uint_least8_t;
165 #endif
166 typedef _Atomic (int_least16_t) atomic_int_least16_t;
167 typedef _Atomic (uint_least16_t) atomic_uint_least16_t;
168 typedef _Atomic (int_least32_t) atomic_int_least32_t;
169 typedef _Atomic (uint_least32_t) atomic_uint_least32_t;
170 typedef _Atomic (int_least64_t) atomic_int_least64_t;
171 typedef _Atomic (uint_least64_t) atomic_uint_least64_t;
172 #if 0
173 typedef _Atomic (int_fast8_t) atomic_int_fast8_t;
174 typedef _Atomic (uint_fast8_t) atomic_uint_fast8_t;
175 #endif
176 typedef _Atomic (int_fast16_t) atomic_int_fast16_t;
177 typedef _Atomic (uint_fast16_t) atomic_uint_fast16_t;
178 typedef _Atomic (int_fast32_t) atomic_int_fast32_t;
179 typedef _Atomic (uint_fast32_t) atomic_uint_fast32_t;
180 typedef _Atomic (int_fast64_t) atomic_int_fast64_t;
181 typedef _Atomic (uint_fast64_t) atomic_uint_fast64_t;
182 typedef _Atomic (intptr_t) atomic_intptr_t;
183 typedef _Atomic (uintptr_t) atomic_uintptr_t;
184 typedef _Atomic (size_t) atomic_size_t;
185 typedef _Atomic (ptrdiff_t) atomic_ptrdiff_t;
186 typedef _Atomic (intmax_t) atomic_intmax_t;
187 typedef _Atomic (uintmax_t) atomic_uintmax_t;
188 
189 #ifdef ROS_PACKAGE_NAME
190  #define _RCUTILS_PACKAGE_NAME ROS_PACKAGE_NAME
191 #else
192  #define _RCUTILS_PACKAGE_NAME "<Unknown Package>"
193 #endif
194 
195 /*
196  * 7.17.7 Operations on atomic types. (pruned modified for Windows' crappy C compiler)
197  */
198 
199 // TODO(emersonknapp) Regression in uncrustify breaks formatting for macros with __pragma
200 // remove indent-off when we have fix for https://github.com/uncrustify/uncrustify/issues/2314
201 // *INDENT-OFF*
202 
203 #define rcutils_win32_atomic_compare_exchange_strong(object, out, expected, desired) \
204  __pragma(warning(push)) \
205  __pragma(warning(disable: 4244)) \
206  __pragma(warning(disable: 4047)) \
207  __pragma(warning(disable: 4024)) \
208  do { \
209  switch (sizeof(out)) { \
210  case sizeof(uint64_t): \
211  out = InterlockedCompareExchange64((LONGLONG *) object, desired, *expected); \
212  break; \
213  case sizeof(uint32_t): \
214  out = _InterlockedCompareExchange((LONG *) object, desired, *expected); \
215  break; \
216  case sizeof(uint16_t): \
217  out = _InterlockedCompareExchange16((SHORT *) object, desired, *expected); \
218  break; \
219  case sizeof(uint8_t): \
220  out = _InterlockedCompareExchange8((char *) object, desired, *expected); \
221  break; \
222  default: \
223  RCUTILS_LOG_ERROR_NAMED( \
224  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_compare_exchange_strong"); \
225  exit(-1); \
226  break; \
227  } \
228  } while (0); \
229  __pragma(warning(pop))
230 
231 #define rcutils_win32_atomic_compare_exchange_weak(object, out, expected, desired) \
232  rcutils_win32_atomic_compare_exchange_strong(object, out, expected, desired)
233 
234 #define rcutils_win32_atomic_exchange(object, out, desired) \
235  __pragma(warning(push)) \
236  __pragma(warning(disable: 4244)) \
237  __pragma(warning(disable: 4047)) \
238  __pragma(warning(disable: 4024)) \
239  do { \
240  switch (sizeof(out)) { \
241  case sizeof(uint64_t): \
242  out = InterlockedExchange64((LONGLONG *) object, desired); \
243  break; \
244  case sizeof(uint32_t): \
245  out = _InterlockedExchange((LONG *) object, desired); \
246  break; \
247  case sizeof(uint16_t): \
248  out = _InterlockedExchange16((SHORT *) object, desired); \
249  break; \
250  case sizeof(uint8_t): \
251  out = _InterlockedExchange8((char *) object, desired); \
252  break; \
253  default: \
254  RCUTILS_LOG_ERROR_NAMED( \
255  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_exchange_strong"); \
256  exit(-1); \
257  break; \
258  } \
259  } while (0); \
260  __pragma(warning(pop))
261 
262 #define rcutils_win32_atomic_fetch_add(object, out, operand) \
263  __pragma(warning(push)) \
264  __pragma(warning(disable: 4244)) \
265  __pragma(warning(disable: 4047)) \
266  __pragma(warning(disable: 4024)) \
267  do { \
268  switch (sizeof(out)) { \
269  case sizeof(uint64_t): \
270  out = InterlockedExchangeAdd64((LONGLONG *) object, operand); \
271  break; \
272  case sizeof(uint32_t): \
273  out = _InterlockedExchangeAdd((LONG *) object, operand); \
274  break; \
275  case sizeof(uint16_t): \
276  out = _InterlockedExchangeAdd16((SHORT *) object, operand); \
277  break; \
278  case sizeof(uint8_t): \
279  out = _InterlockedExchangeAdd8((char *) object, operand); \
280  break; \
281  default: \
282  RCUTILS_LOG_ERROR_NAMED( \
283  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_add"); \
284  exit(-1); \
285  break; \
286  } \
287  } while (0); \
288  __pragma(warning(pop))
289 
290 #define rcutils_win32_atomic_fetch_and(object, out, operand) \
291  __pragma(warning(push)) \
292  __pragma(warning(disable: 4244)) \
293  __pragma(warning(disable: 4047)) \
294  __pragma(warning(disable: 4024)) \
295  do { \
296  switch (sizeof(out)) { \
297  case sizeof(uint64_t): \
298  out = InterlockedAnd64((LONGLONG *) object, operand); \
299  break; \
300  case sizeof(uint32_t): \
301  out = _InterlockedAnd((LONG *) object, operand); \
302  break; \
303  case sizeof(uint16_t): \
304  out = _InterlockedAnd16((SHORT *) object, operand); \
305  break; \
306  case sizeof(uint8_t): \
307  out = _InterlockedAnd8((char *) object, operand); \
308  break; \
309  default: \
310  RCUTILS_LOG_ERROR_NAMED( \
311  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_and"); \
312  exit(-1); \
313  break; \
314  } \
315  } while (0); \
316  __pragma(warning(pop))
317 
318 #define rcutils_win32_atomic_fetch_or(object, out, operand) \
319  __pragma(warning(push)) \
320  __pragma(warning(disable: 4244)) \
321  __pragma(warning(disable: 4047)) \
322  __pragma(warning(disable: 4024)) \
323  do { \
324  switch (sizeof(out)) { \
325  case sizeof(uint64_t): \
326  out = InterlockedOr64((LONGLONG *) object, operand); \
327  break; \
328  case sizeof(uint32_t): \
329  out = _InterlockedOr((LONG *) object, operand); \
330  break; \
331  case sizeof(uint16_t): \
332  out = _InterlockedOr16((SHORT *) object, operand); \
333  break; \
334  case sizeof(uint8_t): \
335  out = _InterlockedOr8((char *) object, operand); \
336  break; \
337  default: \
338  RCUTILS_LOG_ERROR_NAMED( \
339  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_or"); \
340  exit(-1); \
341  break; \
342  } \
343  } while (0); \
344  __pragma(warning(pop))
345 
346 #define rcutils_win32_atomic_fetch_sub(object, out, operand) \
347  rcutils_win32_atomic_fetch_add(object, out, -(operand))
348 
349 #define rcutils_win32_atomic_fetch_xor(object, out, operand) \
350  __pragma(warning(push)) \
351  __pragma(warning(disable: 4244)) \
352  __pragma(warning(disable: 4047)) \
353  __pragma(warning(disable: 4024)) \
354  do { \
355  switch (sizeof(out)) { \
356  case sizeof(uint64_t): \
357  out = InterlockedXor64((LONGLONG *) object, operand); \
358  break; \
359  case sizeof(uint32_t): \
360  out = _InterlockedXor((LONG *) object, operand); \
361  break; \
362  case sizeof(uint16_t): \
363  out = _InterlockedXor16((SHORT *) object, operand); \
364  break; \
365  case sizeof(uint8_t): \
366  out = _InterlockedXor8((char *) object, operand); \
367  break; \
368  default: \
369  RCUTILS_LOG_ERROR_NAMED( \
370  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_xor"); \
371  exit(-1); \
372  break; \
373  } \
374  } while (0); \
375  __pragma(warning(pop))
376 
377 #define rcutils_win32_atomic_load(object, out) \
378  __pragma(warning(push)) \
379  __pragma(warning(disable: 4244)) \
380  __pragma(warning(disable: 4047)) \
381  __pragma(warning(disable: 4024)) \
382  do { \
383  switch (sizeof(out)) { \
384  case sizeof(uint64_t): \
385  out = InterlockedExchangeAdd64((LONGLONG *) object, 0); \
386  break; \
387  case sizeof(uint32_t): \
388  out = _InterlockedExchangeAdd((LONG *) object, 0); \
389  break; \
390  case sizeof(uint16_t): \
391  out = _InterlockedExchangeAdd16((SHORT *) object, 0); \
392  break; \
393  case sizeof(uint8_t): \
394  out = _InterlockedExchangeAdd8((char *) object, 0); \
395  break; \
396  default: \
397  RCUTILS_LOG_ERROR_NAMED( \
398  _RCUTILS_PACKAGE_NAME, "Unsupported integer type in atomic_load"); \
399  exit(-1); \
400  break; \
401  } \
402  } while (0); \
403  __pragma(warning(pop))
404 
405 // *INDENT-ON*
406 
407 #define rcutils_win32_atomic_store(object, desired) \
408  do { \
409  MemoryBarrier(); \
410  (object)->__val = (desired); \
411  MemoryBarrier(); \
412  } while (0)
413 
414 /*
415  * 7.17.8 Atomic flag type and operations. (disabled for now)
416  */
417 
418 // typedef atomic_bool atomic_flag;
419 
420 // #define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0)
421 
422 // #define atomic_flag_clear_explicit(object, order) \
423 // atomic_store_explicit(object, 0, order)
424 // #define atomic_flag_test_and_set_explicit(object, order) \
425 // atomic_compare_exchange_strong_explicit(object, 0, 1, order, order)
426 
427 // #define atomic_flag_clear(object) \
428 // atomic_flag_clear_explicit(object, memory_order_seq_cst)
429 // #define atomic_flag_test_and_set(object) \
430 // atomic_flag_test_and_set_explicit(object, memory_order_seq_cst)
431 
432 #endif // RCUTILS__STDATOMIC_HELPER__WIN32__STDATOMIC_H_
memory_order_consume
@ memory_order_consume
Definition: stdatomic.h:162
_Atomic
#define _Atomic(T)
Definition: stdatomic.h:75
__ATOMIC_ACQUIRE
#define __ATOMIC_ACQUIRE
Definition: stdatomic.h:99
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:105
logging_macros.h
memory_order_acq_rel
@ memory_order_acq_rel
Definition: stdatomic.h:165
__ATOMIC_RELAXED
#define __ATOMIC_RELAXED
Definition: stdatomic.h:93
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:102
__ATOMIC_CONSUME
#define __ATOMIC_CONSUME
Definition: stdatomic.h:96
__ATOMIC_SEQ_CST
#define __ATOMIC_SEQ_CST
Definition: stdatomic.h:108