X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fcommon%2Fmacros.hpp;h=ff0d5bb9365fb11cf6e1f9506aeebd80b2e20d80;hb=56047f5a23df5c2c583a102b8015bbec5a7da9f1;hp=d2b78200e7ebab9e7e6faffd16749f2a88082bae;hpb=c9e313bc594f40a86eed237dce222c0fc99c957f;p=lttng-tools.git diff --git a/src/common/macros.hpp b/src/common/macros.hpp index d2b78200e..ff0d5bb93 100644 --- a/src/common/macros.hpp +++ b/src/common/macros.hpp @@ -9,10 +9,15 @@ #ifndef _MACROS_H #define _MACROS_H -#include +#include + #include +#include #include -#include + +#include +#include +#include /* * Takes a pointer x and transform it so we can use it to access members @@ -34,27 +39,201 @@ * memory using malloc(), we must use generic accessors for compat in order to * *not* use a function to access members and not the variable name. */ -#define LTTNG_REF(x) ((typeof(*x) *)(x)) +#define LTTNG_REF(x) ((typeof(*(x)) *) (x)) + +#ifdef NDEBUG +/* +* Force usage of the assertion condition to prevent unused variable warnings +* when `assert()` are disabled by the `NDEBUG` definition. +*/ +# define LTTNG_ASSERT(_cond) ((void) sizeof((void) (_cond), 0)) +#else +# include +# define LTTNG_ASSERT(_cond) assert(_cond) +#endif /* * Memory allocation zeroed */ + static inline -void *zmalloc(size_t len) +void *zmalloc_internal(size_t size) { - return calloc(1, len); + return calloc(1, size); } -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(array) (sizeof(array) / (sizeof((array)[0]))) +template +struct can_malloc { + /* + * gcc versions before 5.0 lack some type traits defined in C++11. + * Since in this instance we use the trait to prevent misuses + * of malloc (and statically assert) and not to generate different + * code based on this property, simply set value to true and allow + * the code to compile. Anyone using a contemporary compiler will + * catch the error. + */ +#if __GNUG__ && __GNUC__ < 5 + static constexpr bool value = true; +#else + static constexpr bool value = std::is_trivially_constructible::value; #endif +}; -#ifndef container_of -#define container_of(ptr, type, member) \ - ({ \ - const typeof(((type *)NULL)->member) * __ptr = (ptr); \ - (type *)((char *)__ptr - offsetof(type, member)); \ - }) +/* + * Malloc and zero-initialize an object of type T, asserting that MallocableType can be + * safely malloc-ed (is trivially constructible). + */ +template +MallocableType *zmalloc() +{ + static_assert(can_malloc::value, "type can be malloc'ed"); + return (MallocableType *) zmalloc_internal(sizeof(MallocableType)); /* NOLINT sizeof + potentially used on a + pointer. */ +} + +/* + * Malloc and zero-initialize a buffer of size `size`, asserting that type AllocatedType + * can be safely malloc-ed (is trivially constructible). + */ +template +AllocatedType *zmalloc(size_t size) +{ + static_assert(can_malloc::value, "type can be malloc'ed"); + LTTNG_ASSERT(size >= sizeof(AllocatedType)); + return (AllocatedType *) zmalloc_internal(size); +} + +/* + * Malloc and zero-initialize an array of `nmemb` elements of type AllocatedType, + * asserting that AllocatedType can be safely malloc-ed (is trivially constructible). + */ +template +AllocatedType *calloc(size_t nmemb) +{ + static_assert(can_malloc::value, "type can be malloc'ed"); + return (AllocatedType *) zmalloc_internal(nmemb * sizeof(AllocatedType)); /* NOLINT sizeof + potentially + used on a + pointer. */ +} + +/* + * Malloc an object of type AllocatedType, asserting that AllocatedType can be safely malloc-ed (is + * trivially constructible). + */ +template +AllocatedType *malloc() +{ + static_assert(can_malloc::value, "type can be malloc'ed"); + return (AllocatedType *) malloc(sizeof(AllocatedType)); +} + +/* + * Malloc a buffer of size `size`, asserting that AllocatedType can be safely + * malloc-ed (is trivially constructible). + */ +template +AllocatedType *malloc(size_t size) +{ + static_assert (can_malloc::value, "type can be malloc'ed"); + return (AllocatedType *) malloc(size); +} + +/* + * Prevent using `free` on types that are non-POD. + * + * Declare a delete prototype of free if the parameter type is not safe to free + * (non-POD). + * + * If the parameter is a pointer to void, we can't check if what is pointed + * to is safe to free or not, as we don't know what is pointed to. Ideally, + * all calls to free would be with a typed pointer, but there are too many + * instances of passing a pointer to void to enforce that right now. So allow + * pointers to void, these will not be checked. + */ + +template +struct can_free +{ + /* + * gcc versions before 5.0 lack some type traits defined in C++11. + * Since in this instance we use the trait to prevent misuses + * of free (and statically assert) and not to generate different + * code based on this property, simply set value to true and allow + * the code to compile. Anyone using a contemporary compiler will + * catch the error. + */ +#if __GNUG__ && __GNUC__ < 5 + static constexpr bool value = true; +#else + static constexpr bool value = std::is_trivially_destructible::value || + std::is_void::value; +#endif +}; + +template ::value>::type> +void free(FreedType *p) = delete; + +template +struct can_memset { + static constexpr bool value = std::is_pod::value || + std::is_void::value; +}; + +template ::value>::type> +void *memset(InitializedType *s, int c, size_t n) = delete; + +template +struct can_memcpy +{ + /* + * gcc versions before 5.0 lack some type traits defined in C++11. + * Since in this instance we use the trait to prevent misuses + * of memcpy (and statically assert) and not to generate different + * code based on this property, simply set value to true and allow + * the code to compile. Anyone using a contemporary compiler will + * catch the error. + */ +#if __GNUG__ && __GNUC__ < 5 + static constexpr bool value = true; +#else + static constexpr bool value = std::is_trivially_copyable::value; +#endif +}; + +template ::value>::type, + typename = typename std::enable_if::value>::type> +void *memcpy(DestinationType *d, const SourceType *s, size_t n) = delete; + +template +struct can_memmove { + /* + * gcc versions before 5.0 lack some type traits defined in C++11. + * Since in this instance we use the trait to prevent misuses + * of memmove (and statically assert) and not to generate different + * code based on this property, simply set value to true and allow + * the code to compile. Anyone using a contemporary compiler will + * catch the error. + */ +#if __GNUG__ && __GNUC__ < 5 + static constexpr bool value = true; +#else + static constexpr bool value = std::is_trivially_copyable::value; +#endif +}; + +template ::value>::type, + typename = typename std::enable_if::value>::type> +void *memmove(DestinationType *d, const SourceType *s, size_t n) = delete; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) (sizeof(array) / (sizeof((array)[0]))) #endif #ifndef LTTNG_PACKED @@ -71,8 +250,9 @@ void *zmalloc(size_t len) #define member_sizeof(type, field) sizeof(((type *) 0)->field) -#define ASSERT_LOCKED(lock) LTTNG_ASSERT(pthread_mutex_trylock(&lock)) -#define ASSERT_RCU_READ_LOCKED(lock) LTTNG_ASSERT(rcu_read_ongoing()) +#define ASSERT_LOCKED(lock) LTTNG_ASSERT(pthread_mutex_trylock(&(lock))) +#define ASSERT_RCU_READ_LOCKED() LTTNG_ASSERT(rcu_read_ongoing()) +#define ASSERT_RCU_READ_UNLOCKED() LTTNG_ASSERT(!rcu_read_ongoing()) /* Attribute suitable to tag functions as having printf()-like arguments. */ #define ATTR_FORMAT_PRINTF(_string_index, _first_to_check) \ @@ -93,6 +273,9 @@ void *zmalloc(size_t len) # define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \ _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") # define DIAGNOSTIC_IGNORE_LOGICAL_OP +# define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES +# define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF + _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"") #else /* GCC */ # define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT \ @@ -101,6 +284,14 @@ void *zmalloc(size_t len) _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") # define DIAGNOSTIC_IGNORE_LOGICAL_OP \ _Pragma("GCC diagnostic ignored \"-Wlogical-op\"") +#if __GNUG__ && __GNUC__ >= 7 +# define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES \ + _Pragma("GCC diagnostic ignored \"-Wduplicated-branches\"") +#else +# define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES +#endif /* __GNUG__ && __GNUC__ >= 7 */ +# define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF \ + _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"") #endif /* Used to make specific C++ functions to C code. */ @@ -130,15 +321,18 @@ int lttng_strncpy(char *dst, const char *src, size_t dst_len) return 0; } -#ifdef NDEBUG -/* -* Force usage of the assertion condition to prevent unused variable warnings -* when `assert()` are disabled by the `NDEBUG` definition. -*/ -# define LTTNG_ASSERT(_cond) ((void) sizeof((void) (_cond), 0)) -#else -# include -# define LTTNG_ASSERT(_cond) assert(_cond) -#endif +namespace lttng { +namespace utils { +template +ParentType *container_of(const MemberType *member, const MemberType ParentType::*ptr_to_member) +{ + const ParentType *dummy_parent = nullptr; + auto *offset_of_member = reinterpret_cast(&(dummy_parent->*ptr_to_member)); + auto address_of_parent = reinterpret_cast(member) - offset_of_member; + + return reinterpret_cast(address_of_parent); +} +} /* namespace utils */ +} /* namespace lttng */ #endif /* _MACROS_H */