Commit | Line | Data |
---|---|---|
990570ed | 1 | /* |
21cf9b6b | 2 | * Copyright (C) 2011 EfficiOS Inc. |
ab5be9fa | 3 | * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
990570ed | 4 | * |
ab5be9fa | 5 | * SPDX-License-Identifier: GPL-2.0-only |
990570ed | 6 | * |
990570ed DG |
7 | */ |
8 | ||
9 | #ifndef _MACROS_H | |
10 | #define _MACROS_H | |
11 | ||
64803277 SM |
12 | #include <common/compat/string.hpp> |
13 | ||
28f23191 JG |
14 | #include <memory> |
15 | #include <pthread.h> | |
93375aa6 | 16 | #include <stddef.h> |
64803277 | 17 | #include <stdlib.h> |
f6835b82 | 18 | #include <string.h> |
64803277 | 19 | #include <type_traits> |
990570ed DG |
20 | |
21 | /* | |
22 | * Takes a pointer x and transform it so we can use it to access members | |
23 | * without a function call. Here an example: | |
24 | * | |
25 | * #define GET_SIZE(x) LTTNG_REF(x)->size | |
26 | * | |
27 | * struct { int size; } s; | |
28 | * | |
29 | * printf("size : %d\n", GET_SIZE(&s)); | |
30 | * | |
31 | * For this example we can't use something like this for compatibility purpose | |
32 | * since this will fail: | |
33 | * | |
34 | * #define GET_SIZE(x) x->size; | |
35 | * | |
36 | * This is mostly use for the compatibility layer of lttng-tools. See | |
37 | * poll/epoll for a good example. Since x can be on the stack or allocated | |
38 | * memory using malloc(), we must use generic accessors for compat in order to | |
39 | * *not* use a function to access members and not the variable name. | |
40 | */ | |
5c7248cd | 41 | #define LTTNG_REF(x) ((typeof(*(x)) *) (x)) |
990570ed | 42 | |
64803277 SM |
43 | #ifdef NDEBUG |
44 | /* | |
28f23191 JG |
45 | * Force usage of the assertion condition to prevent unused variable warnings |
46 | * when `assert()` are disabled by the `NDEBUG` definition. | |
47 | */ | |
48 | #define LTTNG_ASSERT(_cond) ((void) sizeof((void) (_cond), 0)) | |
64803277 | 49 | #else |
28f23191 JG |
50 | #include <assert.h> |
51 | #define LTTNG_ASSERT(_cond) assert(_cond) | |
64803277 SM |
52 | #endif |
53 | ||
990570ed DG |
54 | /* |
55 | * Memory allocation zeroed | |
56 | */ | |
64803277 | 57 | |
28f23191 | 58 | static inline void *zmalloc_internal(size_t size) |
64803277 SM |
59 | { |
60 | return calloc(1, size); | |
61 | } | |
62 | ||
31375c42 JG |
63 | template <typename MallocableType> |
64 | struct can_malloc { | |
f12e33ba JG |
65 | /* |
66 | * gcc versions before 5.0 lack some type traits defined in C++11. | |
67 | * Since in this instance we use the trait to prevent misuses | |
68 | * of malloc (and statically assert) and not to generate different | |
69 | * code based on this property, simply set value to true and allow | |
70 | * the code to compile. Anyone using a contemporary compiler will | |
71 | * catch the error. | |
72 | */ | |
73 | #if __GNUG__ && __GNUC__ < 5 | |
74 | static constexpr bool value = true; | |
75 | #else | |
31375c42 | 76 | static constexpr bool value = std::is_trivially_constructible<MallocableType>::value; |
f12e33ba | 77 | #endif |
64803277 SM |
78 | }; |
79 | ||
80 | /* | |
31375c42 | 81 | * Malloc and zero-initialize an object of type T, asserting that MallocableType can be |
64803277 SM |
82 | * safely malloc-ed (is trivially constructible). |
83 | */ | |
31375c42 JG |
84 | template <typename MallocableType> |
85 | MallocableType *zmalloc() | |
64803277 | 86 | { |
31375c42 JG |
87 | static_assert(can_malloc<MallocableType>::value, "type can be malloc'ed"); |
88 | return (MallocableType *) zmalloc_internal(sizeof(MallocableType)); /* NOLINT sizeof | |
89 | potentially used on a | |
90 | pointer. */ | |
64803277 SM |
91 | } |
92 | ||
93 | /* | |
31375c42 | 94 | * Malloc and zero-initialize a buffer of size `size`, asserting that type AllocatedType |
64803277 SM |
95 | * can be safely malloc-ed (is trivially constructible). |
96 | */ | |
31375c42 JG |
97 | template <typename AllocatedType> |
98 | AllocatedType *zmalloc(size_t size) | |
64803277 | 99 | { |
31375c42 JG |
100 | static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed"); |
101 | LTTNG_ASSERT(size >= sizeof(AllocatedType)); | |
102 | return (AllocatedType *) zmalloc_internal(size); | |
64803277 SM |
103 | } |
104 | ||
105 | /* | |
31375c42 JG |
106 | * Malloc and zero-initialize an array of `nmemb` elements of type AllocatedType, |
107 | * asserting that AllocatedType can be safely malloc-ed (is trivially constructible). | |
64803277 | 108 | */ |
31375c42 JG |
109 | template <typename AllocatedType> |
110 | AllocatedType *calloc(size_t nmemb) | |
64803277 | 111 | { |
31375c42 JG |
112 | static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed"); |
113 | return (AllocatedType *) zmalloc_internal(nmemb * sizeof(AllocatedType)); /* NOLINT sizeof | |
114 | potentially | |
115 | used on a | |
116 | pointer. */ | |
64803277 SM |
117 | } |
118 | ||
119 | /* | |
31375c42 | 120 | * Malloc an object of type AllocatedType, asserting that AllocatedType can be safely malloc-ed (is |
64803277 SM |
121 | * trivially constructible). |
122 | */ | |
31375c42 JG |
123 | template <typename AllocatedType> |
124 | AllocatedType *malloc() | |
4616a46c | 125 | { |
31375c42 JG |
126 | static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed"); |
127 | return (AllocatedType *) malloc(sizeof(AllocatedType)); | |
4616a46c | 128 | } |
990570ed | 129 | |
64803277 | 130 | /* |
31375c42 | 131 | * Malloc a buffer of size `size`, asserting that AllocatedType can be safely |
64803277 SM |
132 | * malloc-ed (is trivially constructible). |
133 | */ | |
28f23191 | 134 | template <typename AllocatedType> |
31375c42 | 135 | AllocatedType *malloc(size_t size) |
64803277 | 136 | { |
28f23191 | 137 | static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed"); |
31375c42 | 138 | return (AllocatedType *) malloc(size); |
64803277 SM |
139 | } |
140 | ||
141 | /* | |
142 | * Prevent using `free` on types that are non-POD. | |
143 | * | |
144 | * Declare a delete prototype of free if the parameter type is not safe to free | |
145 | * (non-POD). | |
146 | * | |
147 | * If the parameter is a pointer to void, we can't check if what is pointed | |
148 | * to is safe to free or not, as we don't know what is pointed to. Ideally, | |
149 | * all calls to free would be with a typed pointer, but there are too many | |
150 | * instances of passing a pointer to void to enforce that right now. So allow | |
151 | * pointers to void, these will not be checked. | |
152 | */ | |
153 | ||
28f23191 JG |
154 | template <typename FreedType> |
155 | struct can_free { | |
f12e33ba JG |
156 | /* |
157 | * gcc versions before 5.0 lack some type traits defined in C++11. | |
158 | * Since in this instance we use the trait to prevent misuses | |
159 | * of free (and statically assert) and not to generate different | |
160 | * code based on this property, simply set value to true and allow | |
161 | * the code to compile. Anyone using a contemporary compiler will | |
162 | * catch the error. | |
163 | */ | |
164 | #if __GNUG__ && __GNUC__ < 5 | |
165 | static constexpr bool value = true; | |
166 | #else | |
31375c42 JG |
167 | static constexpr bool value = std::is_trivially_destructible<FreedType>::value || |
168 | std::is_void<FreedType>::value; | |
f12e33ba | 169 | #endif |
64803277 SM |
170 | }; |
171 | ||
31375c42 JG |
172 | template <typename FreedType, typename = typename std::enable_if<!can_free<FreedType>::value>::type> |
173 | void free(FreedType *p) = delete; | |
64803277 | 174 | |
31375c42 JG |
175 | template <typename InitializedType> |
176 | struct can_memset { | |
177 | static constexpr bool value = std::is_pod<InitializedType>::value || | |
178 | std::is_void<InitializedType>::value; | |
a8e336c2 SM |
179 | }; |
180 | ||
31375c42 JG |
181 | template <typename InitializedType, |
182 | typename = typename std::enable_if<!can_memset<InitializedType>::value>::type> | |
183 | void *memset(InitializedType *s, int c, size_t n) = delete; | |
a8e336c2 | 184 | |
28f23191 JG |
185 | template <typename T> |
186 | struct can_memcpy { | |
f12e33ba JG |
187 | /* |
188 | * gcc versions before 5.0 lack some type traits defined in C++11. | |
189 | * Since in this instance we use the trait to prevent misuses | |
190 | * of memcpy (and statically assert) and not to generate different | |
191 | * code based on this property, simply set value to true and allow | |
192 | * the code to compile. Anyone using a contemporary compiler will | |
193 | * catch the error. | |
194 | */ | |
195 | #if __GNUG__ && __GNUC__ < 5 | |
196 | static constexpr bool value = true; | |
197 | #else | |
a8e336c2 | 198 | static constexpr bool value = std::is_trivially_copyable<T>::value; |
f12e33ba | 199 | #endif |
a8e336c2 SM |
200 | }; |
201 | ||
31375c42 JG |
202 | template <typename DestinationType, |
203 | typename SourceType, | |
204 | typename = typename std::enable_if<!can_memcpy<DestinationType>::value>::type, | |
205 | typename = typename std::enable_if<!can_memcpy<SourceType>::value>::type> | |
206 | void *memcpy(DestinationType *d, const SourceType *s, size_t n) = delete; | |
a8e336c2 | 207 | |
31375c42 JG |
208 | template <typename MovedType> |
209 | struct can_memmove { | |
f12e33ba JG |
210 | /* |
211 | * gcc versions before 5.0 lack some type traits defined in C++11. | |
212 | * Since in this instance we use the trait to prevent misuses | |
213 | * of memmove (and statically assert) and not to generate different | |
214 | * code based on this property, simply set value to true and allow | |
215 | * the code to compile. Anyone using a contemporary compiler will | |
216 | * catch the error. | |
217 | */ | |
218 | #if __GNUG__ && __GNUC__ < 5 | |
219 | static constexpr bool value = true; | |
220 | #else | |
31375c42 | 221 | static constexpr bool value = std::is_trivially_copyable<MovedType>::value; |
f12e33ba | 222 | #endif |
a8e336c2 SM |
223 | }; |
224 | ||
31375c42 JG |
225 | template <typename DestinationType, |
226 | typename SourceType, | |
227 | typename = typename std::enable_if<!can_memmove<DestinationType>::value>::type, | |
228 | typename = typename std::enable_if<!can_memmove<SourceType>::value>::type> | |
229 | void *memmove(DestinationType *d, const SourceType *s, size_t n) = delete; | |
a8e336c2 | 230 | |
990570ed | 231 | #ifndef ARRAY_SIZE |
28f23191 | 232 | #define ARRAY_SIZE(array) (sizeof(array) / (sizeof((array)[0]))) |
990570ed DG |
233 | #endif |
234 | ||
54c90d10 DG |
235 | #ifndef LTTNG_PACKED |
236 | #define LTTNG_PACKED __attribute__((__packed__)) | |
237 | #endif | |
238 | ||
1405051a | 239 | #ifndef LTTNG_NO_SANITIZE_ADDRESS |
28f23191 | 240 | #if defined(__clang__) || defined(__GNUC__) |
1405051a FD |
241 | #define LTTNG_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) |
242 | #else | |
243 | #define LTTNG_NO_SANITIZE_ADDRESS | |
244 | #endif | |
245 | #endif | |
246 | ||
28f23191 | 247 | #define member_sizeof(type, field) sizeof(((type *) 0)->field) |
f8f3885c | 248 | |
28f23191 JG |
249 | #define ASSERT_LOCKED(lock) LTTNG_ASSERT(pthread_mutex_trylock(&(lock))) |
250 | #define ASSERT_RCU_READ_LOCKED() LTTNG_ASSERT(rcu_read_ongoing()) | |
56047f5a | 251 | #define ASSERT_RCU_READ_UNLOCKED() LTTNG_ASSERT(!rcu_read_ongoing()) |
5e5c14ce | 252 | |
d22ad5f8 SM |
253 | /* Attribute suitable to tag functions as having printf()-like arguments. */ |
254 | #define ATTR_FORMAT_PRINTF(_string_index, _first_to_check) \ | |
255 | __attribute__((format(printf, _string_index, _first_to_check))) | |
256 | ||
411b3154 | 257 | /* Attribute suitable to tag functions as having strftime()-like arguments. */ |
28f23191 | 258 | #define ATTR_FORMAT_STRFTIME(_string_index) __attribute__((format(strftime, _string_index, 0))) |
411b3154 | 259 | |
d22ad5f8 SM |
260 | /* Macros used to ignore specific compiler diagnostics. */ |
261 | ||
262 | #define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") | |
28f23191 | 263 | #define DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") |
d22ad5f8 SM |
264 | |
265 | #if defined(__clang__) | |
28f23191 JG |
266 | /* Clang */ |
267 | #define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT | |
268 | #define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \ | |
411b3154 | 269 | _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") |
28f23191 JG |
270 | #define DIAGNOSTIC_IGNORE_LOGICAL_OP |
271 | #define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES | |
272 | #define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF | |
273 | _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"") | |
d22ad5f8 | 274 | #else |
28f23191 JG |
275 | /* GCC */ |
276 | #define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT \ | |
d22ad5f8 | 277 | _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"") |
28f23191 | 278 | #define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \ |
411b3154 | 279 | _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") |
28f23191 | 280 | #define DIAGNOSTIC_IGNORE_LOGICAL_OP _Pragma("GCC diagnostic ignored \"-Wlogical-op\"") |
efc2642c | 281 | #if __GNUG__ && __GNUC__ >= 7 |
28f23191 | 282 | #define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES \ |
05aa7e19 | 283 | _Pragma("GCC diagnostic ignored \"-Wduplicated-branches\"") |
efc2642c | 284 | #else |
28f23191 | 285 | #define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES |
efc2642c | 286 | #endif /* __GNUG__ && __GNUC__ >= 7 */ |
28f23191 | 287 | #define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"") |
d22ad5f8 SM |
288 | #endif |
289 | ||
d50d200a SM |
290 | /* Used to make specific C++ functions to C code. */ |
291 | #ifdef __cplusplus | |
292 | #define C_LINKAGE extern "C" | |
293 | #else | |
294 | #define C_LINKAGE | |
295 | #endif | |
296 | ||
28f23191 JG |
297 | /* |
298 | * lttng_strncpy returns 0 on success, or nonzero on failure. | |
299 | * It checks that the @src string fits into @dst_len before performing | |
300 | * the copy. On failure, no copy has been performed. | |
301 | * | |
302 | * Assumes that 'src' is null-terminated. | |
303 | * | |
304 | * dst_len includes the string's trailing NULL. | |
305 | */ | |
306 | static inline int lttng_strncpy(char *dst, const char *src, size_t dst_len) | |
f6835b82 | 307 | { |
b25a5991 | 308 | if (strlen(src) >= dst_len) { |
f6835b82 MD |
309 | /* Fail since copying would result in truncation. */ |
310 | return -1; | |
311 | } | |
c3ef76cd | 312 | strcpy(dst, src); |
f6835b82 MD |
313 | return 0; |
314 | } | |
315 | ||
0114db0e JG |
316 | namespace lttng { |
317 | namespace utils { | |
31375c42 JG |
318 | template <class ParentType, class MemberType> |
319 | ParentType *container_of(const MemberType *member, const MemberType ParentType::*ptr_to_member) | |
0114db0e | 320 | { |
31375c42 | 321 | const ParentType *dummy_parent = nullptr; |
0114db0e JG |
322 | auto *offset_of_member = reinterpret_cast<const char *>(&(dummy_parent->*ptr_to_member)); |
323 | auto address_of_parent = reinterpret_cast<const char *>(member) - offset_of_member; | |
324 | ||
31375c42 | 325 | return reinterpret_cast<ParentType *>(address_of_parent); |
0114db0e JG |
326 | } |
327 | } /* namespace utils */ | |
328 | } /* namespace lttng */ | |
329 | ||
990570ed | 330 | #endif /* _MACROS_H */ |