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