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