Zth (libzth)
macros.h
Go to the documentation of this file.
1 #ifndef ZTH_MACROS_H
2 #define ZTH_MACROS_H
3 /*
4  * Zth (libzth), a cooperative userspace multitasking library.
5  * Copyright (C) 2019-2022 Jochem Rutgers
6  *
7  * This Source Code Form is subject to the terms of the Mozilla Public
8  * License, v. 2.0. If a copy of the MPL was not distributed with this
9  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
10  */
11 
12 
13 
15 // Preamble
16 //
17 
18 #ifdef _DEBUG
19 # undef NDEBUG
20 #endif
21 #if !defined(_DEBUG) && !defined(NDEBUG)
22 # define _DEBUG
23 #endif
24 
25 #ifndef ZTH_THREADS
26 # define ZTH_THREADS 1
27 #endif
28 
29 #if !ZTH_THREADS && defined(ZTH_HAVE_LIBZMQ)
30 # undef ZTH_THREADS
31 # define ZTH_THREADS 1
32 #endif
33 
34 
35 
37 // Compiler
38 //
39 
40 #ifdef __clang_analyzer__
41 // We don't use clang for compiling, but we do use clang-tidy.
42 # define CLANG_TIDY
43 #endif
44 
45 #if defined(__GNUC__) || defined(CLANG_TIDY)
46 // This is gcc
47 # ifdef __cplusplus
48 # if __cplusplus < 201103L && !defined(decltype)
49 # define decltype(x) \
50  __typeof__(x) // Well, not really true when references are
51  // involved...
52 # endif
53 # endif
54 # if ZTH_THREADS
55 # define ZTH_TLS_DECLARE(type, var) extern __thread type var;
56 # define ZTH_TLS_DEFINE(type, var, init) __thread type var = init;
57 # define ZTH_TLS_STATIC(type, var, init) static __thread type var = init;
58 # define ZTH_TLS_MEMBER(type, var) static __thread type var;
59 # define ZTH_TLS_SET(var, value) var = value
60 # define ZTH_TLS_GET(var) var
61 # endif
62 # ifndef _GNU_SOURCE
63 # define _GNU_SOURCE
64 # endif
65 # ifndef CLANG_TIDY
66 # define ZTH_ATTR_PRINTF gnu_printf
67 # endif
68 # ifndef GCC_VERSION
69 # define GCC_VERSION \
70  (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__)
71 # endif
72 # if GCC_VERSION < 50000
73 # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
74 # endif
75 # if GCC_VERSION >= 70000 && defined(__cplusplus) && __cplusplus < 201703L
76 # pragma GCC diagnostic ignored "-Wnoexcept-type"
77 # endif
78 # ifndef UNUSED_PAR
79 # define UNUSED_PAR(name) name __attribute__((unused))
80 # endif
81 #else
82 # error Unsupported compiler. Please use gcc.
83 #endif
84 
85 #ifdef CPPCHECK
86 # define __attribute__(x)
87 #endif
88 
89 #if defined(__cplusplus) && __cplusplus >= 201703L
90 # define ZTH_FALLTHROUGH [[fallthrough]];
91 #elif GCC_VERSION >= 70000L
92 # define ZTH_FALLTHROUGH __attribute__((fallthrough));
93 #else
94 # define ZTH_FALLTHROUGH
95 #endif
96 
97 #ifndef ZTH_TLS_DECLARE
98 # undef ZTH_THREADS
99 # define ZTH_THREADS 0
100 # define ZTH_TLS_DECLARE(type, var) extern type var;
101 # define ZTH_TLS_DEFINE(type, var, init) type var = init;
102 # define ZTH_TLS_STATIC(type, var, init) static type var = init;
103 # define ZTH_TLS_MEMBER(type, var) static type var;
104 # define ZTH_TLS_SET(var, value) var = value
105 # define ZTH_TLS_GET(var) var
106 #endif
107 
108 #ifndef ZTH_ATTR_PRINTF
109 # define ZTH_ATTR_PRINTF printf
110 #endif
111 
112 #define __STDC_FORMAT_MACROS
113 
114 #ifndef EXTERN_C
115 # ifdef __cplusplus
116 # define EXTERN_C extern "C"
117 # else
118 # define EXTERN_C
119 # endif
120 #endif
121 
122 #ifndef ZTH_EXPORT
123 # define ZTH_EXPORT __attribute__((visibility("default")))
124 #endif
125 
126 #ifdef __cplusplus
127 # ifdef ZTH_INLINE_EMIT
128 # define ZTH_INLINE
129 # else
130 # define ZTH_INLINE __attribute__((gnu_inline)) inline
131 # endif
132 #else
133 # define ZTH_INLINE __attribute__((gnu_inline)) extern inline
134 #endif
135 
136 /*
137 HOWTO inline:
138 
139 // Inline private C++-only function:
140 #ifdef __cplusplus
141 inline void foo() { baz::bar(); }
142 #endif
143 
144 // Inline public C++-only function:
145 #ifdef __cplusplus
146 ZTH_EXPORT inline void foo() { baz::bar(); }
147 #endif
148 
149 // Inline public C/C++ function:
150 EXTERN_C ZTH_EXPORT ZTH_INLINE void foo() { bar(); }
151 
152 // Inline public C/C++ function with C++-only implementation:
153 #ifdef __cplusplus
154 EXTERN_C ZTH_EXPORT ZTH_INLINE void foo() { baz::bar(); }
155 #else
156 ZTH_EXPORT void foo();
157 #endif
158 */
159 
160 #ifndef __cplusplus
161 # ifndef noexcept
162 # define noexcept
163 # endif
164 #elif __cplusplus < 201103L
165 # ifndef constexpr
166 # define constexpr
167 # endif
168 # ifndef constexpr14
169 # define constexpr14
170 # endif
171 # ifndef override
172 # define override
173 # endif
174 # ifndef final
175 # define final
176 # endif
177 # ifndef is_default
178 # define is_default \
179  {}
180 # endif
181 # ifndef noexcept
182 # define noexcept throw()
183 # endif
184 # ifndef nullptr
185 # define nullptr NULL
186 # endif
187 # ifndef alignas
188 # define alignas(...) __attribute__((aligned(sizeof(void*))))
189 # endif
190 # ifndef LREF_QUALIFIED
191 # define LREF_QUALIFIED
192 # endif
193 # ifndef inline17
194 # define inline17 static
195 # endif
196 #else
197 # ifndef constexpr14
198 # if __cplusplus < 201402L
199 # define constexpr14
200 # else
201 # define constexpr14 constexpr
202 # endif
203 # endif
204 # ifndef is_default
205 # define is_default = default;
206 # endif
207 # ifndef LREF_QUALIFIED
208 # define LREF_QUALIFIED &
209 # endif
210 # ifndef inline17
211 # if __cplusplus < 201703L
212 # define inline17 static
213 # else
214 # define inline17 inline
215 # endif
216 # endif
217 #endif
218 
219 #if defined(__cplusplus) && !defined(__cpp_exceptions)
220 # define try if(true)
221 # define catch(...) if(false)
222 # define zth_throw(e) std::abort()
223 #else
224 # define zth_throw(e) throw e
225 #endif
226 
227 #if defined(__SANITIZE_ADDRESS__) && !defined(ZTH_ENABLE_ASAN)
228 # define ZTH_ENABLE_ASAN
229 #endif
230 
231 
232 
234 // Hardware
235 //
236 
237 #if defined(__x86_64__)
238 # define ZTH_ARCH_X86_64 1
239 #elif defined(__i386__)
240 # define ZTH_ARCH_X86 1
241 #elif defined(__arm__)
242 # define ZTH_ARCH_ARM 1
243 # if defined(__ARM_ARCH) && __ARM_ARCH >= 6 && defined(__ARM_ARCH_PROFILE) \
244  && __ARM_ARCH_PROFILE == 'M'
245 # define ZTH_ARM_HAVE_MPU
246 # endif
247 # define __isb() __asm__ volatile("isb" ::: "memory")
248 # define __dsb() __asm__ volatile("dsb" ::: "memory")
249 # define __dmb() __asm__ volatile("dmb" ::: "memory")
250 # define barrier() __dsb()
251 #else
252 # error Unsupported hardware platform.
253 #endif
254 
255 #ifndef barrier
256 # if GCC_VERSION < 40802L
257 # define barrier() __sync_synchronize()
258 # else
259 # define barrier() __atomic_thread_fence()
260 # endif
261 #endif
262 
263 
264 
266 // OS
267 //
268 
269 #if defined(_WIN32) || defined(__CYGWIN__)
270 # define ZTH_OS_WINDOWS 1
271 # define _WANT_IO_C99_FORMATS 1
272 # define __USE_MINGW_ANSI_STDIO 1
273 # define WIN32_LEAN_AND_MEAN
274 # define NOGDI
275 # if defined(UNICODE) || defined(_UNICODE)
276 # error Do not use UNICODE. Use ANSI with UTF-8 instead.
277 # endif
278 # ifdef __CYGWIN__
279 # define ZTH_HAVE_PTHREAD
280 # endif
281 //# define ZTH_HAVE_WINSOCK
282 # ifdef ZTH_CONFIG_WRAP_IO
283 # error ZTH_CONFIG_WRAP_IO is not supported on Windows.
284 # endif
285 #elif defined(__linux__)
286 # define ZTH_OS_LINUX 1
287 # define ZTH_OS_POSIX 1
288 //# define ZTH_HAVE_VALGRIND
289 # define ZTH_HAVE_PTHREAD
290 //# define ZTH_HAVE_LIBUNWIND
291 # define ZTH_HAVE_POLL
292 # define ZTH_HAVE_MMAN
293 #elif defined(__APPLE__)
294 # include <TargetConditionals.h>
295 # ifdef TARGET_OS_MAC
296 # define ZTH_OS_MAC 1
297 # define ZTH_OS_POSIX 1
298 # else
299 # error Unsupported Apple platform.
300 # endif
301 # define ZTH_HAVE_PTHREAD
302 # define ZTH_HAVE_POLL
303 # define ZTH_HAVE_MMAN
304 # include <Availability.h>
305 # if __MAC_OS_X_VERSION_MAX_ALLOWED < 1012
306 // OSX 10.12 includes clock_gettime(). Otherwise, implement it by Zth.
307 # define ZTH_CUSTOM_CLOCK_GETTIME
308 # endif
309 #elif defined(ZTH_ARCH_ARM)
310 // Assume having newlib
311 # define ZTH_OS_BAREMETAL 1
312 # define ZTH_CUSTOM_CLOCK_GETTIME
313 # include <newlib.h>
314 # ifndef NEWLIB_VERSION
315 # define NEWLIB_VERSION \
316  (__NEWLIB__ * 10000L + __NEWLIB_MINOR__ * 100L + __NEWLIB_PATCHLEVEL__)
317 # endif
318 #else
319 # error Unsupported OS.
320 #endif
321 
322 #if defined(_DEBUG) && defined(ZTH_HAVE_VALGRIND)
323 # define ZTH_USE_VALGRIND
324 #endif
325 
326 #if !ZTH_THREADS
327 # undef ZTH_HAVE_PTHREAD
328 #endif
329 
330 
331 
333 // Context-switch approach
334 //
335 
336 // We have the following approaches. If one of them is already defined, it is
337 // used as preferred one, if compatible.
338 //
339 // - ZTH_CONTEXT_SIGALTSTACK
340 // - ZTH_CONTEXT_SJLJ
341 // - ZTH_CONTEXT_UCONTEXT
342 // - ZTH_CONTEXT_WINFIBER
343 
344 #ifdef ZTH_OS_WINDOWS
345 # ifndef ZTH_CONTEXT_WINFIBER
346 # define ZTH_CONTEXT_WINFIBER
347 # endif
348 # undef ZTH_CONTEXT_SIGALTSTACK
349 # undef ZTH_CONTEXT_SJLJ
350 # undef ZTH_CONTEXT_UCONTEXT
351 #elif defined(ZTH_OS_BAREMETAL)
352 // Assume having newlib with setjmp/longjmp fiddling.
353 # ifndef ZTH_CONTEXT_SJLJ
354 # define ZTH_CONTEXT_SJLJ
355 # endif
356 # if defined(ZTH_ARCH_ARM) && defined(__ARM_ARCH) && __ARM_ARCH >= 6 \
357  && defined(__ARM_ARCH_PROFILE) && __ARM_ARCH_PROFILE == 'M'
358 # define ZTH_ARM_USE_PSP
359 # define ZTH_STACK_SWITCH
360 # endif
361 # undef ZTH_CONTEXT_SIGALTSTACK
362 # undef ZTH_CONTEXT_UCONTEXT
363 # undef ZTH_CONTEXT_WINFIBER
364 #elif defined(ZTH_HAVE_VALGRIND)
365 // Valgrind does not handle sigaltstack very well.
366 # ifndef ZTH_CONTEXT_UCONTEXT
367 # define ZTH_CONTEXT_UCONTEXT
368 # endif
369 # undef ZTH_CONTEXT_SIGALTSTACK
370 # undef ZTH_CONTEXT_SJLJ
371 # undef ZTH_CONTEXT_WINFIBER
372 #else
373 // Default approach is ucontext.
374 # undef ZTH_CONTEXT_SJLJ
375 # undef ZTH_CONTEXT_WINFIBER
376 # if defined(ZTH_CONTEXT_UCONTEXT)
377 # undef ZTH_CONTEXT_SIGALTSTACK
378 # elif !defined(ZTH_CONTEXT_SIGALTSTACK) || defined(ZTH_ENABLE_ASAN)
379 # undef ZTH_CONTEXT_SIGALTSTACK
380 # define ZTH_CONTEXT_UCONTEXT
381 # endif
382 #endif
383 
384 #ifdef ZTH_CONTEXT_WINFIBER
385 # ifndef WINVER
386 # define WINVER 0x0501
387 # elif WINVER < 0x0400
388 # error WINVER should be at least 0x0400
389 # endif
390 # ifndef _WIN32_WINNT
391 # define _WIN32_WINNT WINVER
392 # elif _WIN32_WINNT < 0x0400
393 # error _WIN32_WINNT should be at least 0x0400
394 # endif
395 #endif
396 
397 #endif // ZTH_MACROS_H