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 /*
190  * 7.17.7 Operations on atomic types. (pruned modified for Windows' crappy C compiler)
191  */
192 
193 #define rcutils_win32_atomic_compare_exchange_strong(object, out, expected, desired) \
194  __pragma(warning(push)) \
195  __pragma(warning(disable: 4244)) \
196  do { \
197  switch (sizeof(out)) { \
198  case sizeof(uint64_t): \
199  out = _InterlockedCompareExchange64((LONGLONG *) object, desired, *expected); \
200  break; \
201  case sizeof(uint32_t): \
202  out = _InterlockedCompareExchange((LONG *) object, desired, *expected); \
203  break; \
204  case sizeof(uint16_t): \
205  out = _InterlockedCompareExchange16((SHORT *) object, desired, *expected); \
206  break; \
207  case sizeof(uint8_t): \
208  out = _InterlockedCompareExchange8((char *) object, desired, *expected); \
209  break; \
210  default: \
211  RCUTILS_LOG_ERROR_NAMED( \
212  ROS_PACKAGE_NAME, "Unsupported integer type in atomic_compare_exchange_strong"); \
213  exit(-1); \
214  break; \
215  } \
216  } while (0); \
217  __pragma(warning(pop))
218 
219 #define rcutils_win32_atomic_compare_exchange_weak(object, out, expected, desired) \
220  rcutils_win32_atomic_compare_exchange_strong(object, out, expected, desired)
221 
222 #define rcutils_win32_atomic_exchange(object, out, desired) \
223  __pragma(warning(push)) \
224  __pragma(warning(disable: 4244)) \
225  do { \
226  switch (sizeof(out)) { \
227  case sizeof(uint64_t): \
228  out = _InterlockedExchange64((LONGLONG *) object, desired); \
229  break; \
230  case sizeof(uint32_t): \
231  out = _InterlockedExchange((LONG *) object, desired); \
232  break; \
233  case sizeof(uint16_t): \
234  out = _InterlockedExchange16((SHORT *) object, desired); \
235  break; \
236  case sizeof(uint8_t): \
237  out = _InterlockedExchange8((char *) object, desired); \
238  break; \
239  default: \
240  RCUTILS_LOG_ERROR_NAMED( \
241  ROS_PACKAGE_NAME, "Unsupported integer type in atomic_exchange_strong"); \
242  exit(-1); \
243  break; \
244  } \
245  } while (0); \
246  __pragma(warning(pop))
247 
248 #define rcutils_win32_atomic_fetch_add(object, out, operand) \
249  __pragma(warning(push)) \
250  __pragma(warning(disable: 4244)) \
251  do { \
252  switch (sizeof(out)) { \
253  case sizeof(uint64_t): \
254  out = _InterlockedExchangeAdd64((LONGLONG *) object, operand); \
255  break; \
256  case sizeof(uint32_t): \
257  out = _InterlockedExchangeAdd((LONG *) object, operand); \
258  break; \
259  case sizeof(uint16_t): \
260  out = _InterlockedExchangeAdd16((SHORT *) object, operand); \
261  break; \
262  case sizeof(uint8_t): \
263  out = _InterlockedExchangeAdd8((char *) object, operand); \
264  break; \
265  default: \
266  RCUTILS_LOG_ERROR_NAMED( \
267  ROS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_add"); \
268  exit(-1); \
269  break; \
270  } \
271  } while (0); \
272  __pragma(warning(pop))
273 
274 #define rcutils_win32_atomic_fetch_and(object, out, operand) \
275  __pragma(warning(push)) \
276  __pragma(warning(disable: 4244)) \
277  do { \
278  switch (sizeof(out)) { \
279  case sizeof(uint64_t): \
280  out = _InterlockedAnd64((LONGLONG *) object, operand); \
281  break; \
282  case sizeof(uint32_t): \
283  out = _InterlockedAnd((LONG *) object, operand); \
284  break; \
285  case sizeof(uint16_t): \
286  out = _InterlockedAnd16((SHORT *) object, operand); \
287  break; \
288  case sizeof(uint8_t): \
289  out = _InterlockedAnd8((char *) object, operand); \
290  break; \
291  default: \
292  RCUTILS_LOG_ERROR_NAMED( \
293  ROS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_and"); \
294  exit(-1); \
295  break; \
296  } \
297  } while (0); \
298  __pragma(warning(pop))
299 
300 #define rcutils_win32_atomic_fetch_or(object, out, operand) \
301  __pragma(warning(push)) \
302  __pragma(warning(disable: 4244)) \
303  do { \
304  switch (sizeof(out)) { \
305  case sizeof(uint64_t): \
306  out = _InterlockedOr64((LONGLONG *) object, operand); \
307  break; \
308  case sizeof(uint32_t): \
309  out = _InterlockedOr((LONG *) object, operand); \
310  break; \
311  case sizeof(uint16_t): \
312  out = _InterlockedOr16((SHORT *) object, operand); \
313  break; \
314  case sizeof(uint8_t): \
315  out = _InterlockedOr8((char *) object, operand); \
316  break; \
317  default: \
318  RCUTILS_LOG_ERROR_NAMED( \
319  ROS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_or"); \
320  exit(-1); \
321  break; \
322  } \
323  } while (0); \
324  __pragma(warning(pop))
325 
326 #define rcutils_win32_atomic_fetch_sub(object, out, operand) \
327  rcutils_win32_atomic_fetch_add(object, out, -(operand))
328 
329 #define rcutils_win32_atomic_fetch_xor(object, out, operand) \
330  __pragma(warning(push)) \
331  __pragma(warning(disable: 4244)) \
332  do { \
333  switch (sizeof(out)) { \
334  case sizeof(uint64_t): \
335  out = _InterlockedXor64((LONGLONG *) object, operand); \
336  break; \
337  case sizeof(uint32_t): \
338  out = _InterlockedXor((LONG *) object, operand); \
339  break; \
340  case sizeof(uint16_t): \
341  out = _InterlockedXor16((SHORT *) object, operand); \
342  break; \
343  case sizeof(uint8_t): \
344  out = _InterlockedXor8((char *) object, operand); \
345  break; \
346  default: \
347  RCUTILS_LOG_ERROR_NAMED( \
348  ROS_PACKAGE_NAME, "Unsupported integer type in atomic_fetch_xor"); \
349  exit(-1); \
350  break; \
351  } \
352  } while (0); \
353  __pragma(warning(pop))
354 
355 #define rcutils_win32_atomic_load(object, out) \
356  __pragma(warning(push)) \
357  __pragma(warning(disable: 4244)) \
358  do { \
359  switch (sizeof(out)) { \
360  case sizeof(uint64_t): \
361  out = _InterlockedExchangeAdd64((LONGLONG *) object, 0); \
362  break; \
363  case sizeof(uint32_t): \
364  out = _InterlockedExchangeAdd((LONG *) object, 0); \
365  break; \
366  case sizeof(uint16_t): \
367  out = _InterlockedExchangeAdd16((SHORT *) object, 0); \
368  break; \
369  case sizeof(uint8_t): \
370  out = _InterlockedExchangeAdd8((char *) object, 0); \
371  break; \
372  default: \
373  RCUTILS_LOG_ERROR_NAMED( \
374  ROS_PACKAGE_NAME, "Unsupported integer type in atomic_load"); \
375  exit(-1); \
376  break; \
377  } \
378  } while (0); \
379  __pragma(warning(pop))
380 
381 #define rcutils_win32_atomic_store(object, desired) \
382  do { \
383  MemoryBarrier(); \
384  (object)->__val = (desired); \
385  MemoryBarrier(); \
386  } while (0)
387 
388 /*
389  * 7.17.8 Atomic flag type and operations. (disabled for now)
390  */
391 
392 // typedef atomic_bool atomic_flag;
393 
394 // #define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0)
395 
396 // #define atomic_flag_clear_explicit(object, order) \
397 // atomic_store_explicit(object, 0, order)
398 // #define atomic_flag_test_and_set_explicit(object, order) \
399 // atomic_compare_exchange_strong_explicit(object, 0, 1, order, order)
400 
401 // #define atomic_flag_clear(object) \
402 // atomic_flag_clear_explicit(object, memory_order_seq_cst)
403 // #define atomic_flag_test_and_set(object) \
404 // atomic_flag_test_and_set_explicit(object, memory_order_seq_cst)
405 
406 #endif // RCUTILS__STDATOMIC_HELPER__WIN32__STDATOMIC_H_
#define __ATOMIC_SEQ_CST
Definition: stdatomic.h:108
Definition: stdatomic.h:163
Definition: stdatomic.h:164
Definition: stdatomic.h:165
Definition: stdatomic.h:166
memory_order
Definition: stdatomic.h:160
Definition: stdatomic.h:161
#define __ATOMIC_RELEASE
Definition: stdatomic.h:102
#define _Atomic(T)
Definition: stdatomic.h:75
#define __ATOMIC_ACQ_REL
Definition: stdatomic.h:105
Definition: stdatomic.h:162
#define __ATOMIC_ACQUIRE
Definition: stdatomic.h:99
#define __ATOMIC_CONSUME
Definition: stdatomic.h:96
#define __ATOMIC_RELAXED
Definition: stdatomic.h:93