diff --git a/core/lib/include/compiler_hints.h b/core/lib/include/compiler_hints.h new file mode 100644 index 0000000000..c66f8891bd --- /dev/null +++ b/core/lib/include/compiler_hints.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * 2017 HAW-Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup core_internal + * @{ + * + * @file + * @brief Common macros and compiler attributes/pragmas configuration + * + * @author René Kijewski + * @author Michel Rottleuthner + */ + +#ifndef COMPILER_HINTS_H +#define COMPILER_HINTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @def NORETURN + * @brief The *NORETURN* keyword tells the compiler to assume that the function + * cannot return. + */ +#ifdef __GNUC__ +#define NORETURN __attribute__((noreturn)) +#else +#define NORETURN +#endif + +/** + * @def PURE + * @brief The function has no effects except the return value and its return + * value depends only on the parameters and/or global variables. Such a + * function can be subject to common subexpression elimination and loop + * optimization just as an arithmetic operator would be. + */ +#ifdef __GNUC__ +#define PURE __attribute__((pure)) +#else +#define PURE +#endif + +/** + * @def UNREACHABLE() + * @brief Tell the compiler that this line of code cannot be reached. + * @details Most useful in junction with #NORETURN. + * Use this if the compiler cannot tell that e.g. + * an assembler instruction causes a longjmp, or a write causes a reboot. + */ +#if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 5) +#define UNREACHABLE() __builtin_unreachable() +#else +#define UNREACHABLE() do { /* nothing */ } while (1) +#endif + +/** + * @brief Disable -Wpedantic for the argument, but restore diagnostic + * settings afterwards + * @param ... The expression that -Wpendantic should not apply to + * + * @warning This is intended for internal use only + * + * This is particularly useful when declaring non-strictly conforming + * preprocessor macros, as the diagnostics need to be disabled where the + * macro is evaluated, not where the macro is declared. + */ +#define WITHOUT_PEDANTIC(...) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \ + __VA_ARGS__ \ + _Pragma("GCC diagnostic pop") + +/** + * @brief Declare a constant named @p identifier as anonymous `enum` that has + * the value @p const_expr + * + * @warning This is intended for internal use only + * + * This turns any expression that is constant and known at compile time into + * a formal compile time constant. This allows e.g. using non-formally but + * still constant expressions in `static_assert()`. + */ +#define DECLARE_CONSTANT(identifier, const_expr) \ + WITHOUT_PEDANTIC(enum { identifier = const_expr };) + +#if DOXYGEN +/** + * @brief Check if given variable / expression is detected as compile time + * constant + * @note This might return 0 on compile time constant expressions if the + * compiler is not able to prove the constness at the given level + * of optimization. + * @details This will return 0 if the used compiler does not support this + * @warning This is intended for internal use only + * + * This allows providing two different implementations in C, with one being + * more efficient if constant folding is used. + */ +#define IS_CT_CONSTANT(expr) +#elif defined(__GNUC__) +/* both clang and gcc (which both define __GNUC__) support this */ +#define IS_CT_CONSTANT(expr) __builtin_constant_p(expr) +#else +#define IS_CT_CONSTANT(expr) 0 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* COMPILER_HINTS_H */ +/** @} */ diff --git a/core/lib/include/container.h b/core/lib/include/container.h new file mode 100644 index 0000000000..98ffe557ce --- /dev/null +++ b/core/lib/include/container.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * 2017 HAW-Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup core_internal + * @{ + * + * @file + * @brief Common macros and compiler attributes/pragmas configuration + * + * @author René Kijewski + * @author Michel Rottleuthner + */ + +#ifndef CONTAINER_H +#define CONTAINER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* uncrustify gets mightily confused by these macros... */ +/* begin{code-style-ignore} */ + +/** + * @def container_of(PTR, TYPE, MEMBER) + * @brief Returns the container of a pointer to a member. + * @details For a struct `TYPE` with a member `MEMBER`, + * given a pointer `PTR` to `TYPE::MEMBER` this function returns a pointer + * to the instance of `TYPE`. + * @details E.g. for `struct my_struct_t { ...; something_t n; ... } my_struct;`, + * `&my_struct == container_of(&my_struct.n, struct my_struct_t, n)`. + * @param[in] PTR pointer to a member + * @param[in] TYPE a type name (a struct or union), container of PTR + * @param[in] MEMBER name of the member of TYPE which PTR points to + * @return Pointer to the container of PTR. + */ +#if __STDC_VERSION__ >= 201112L +# define container_of(PTR, TYPE, MEMBER) \ + (_Generic((PTR), \ + const __typeof__ (((TYPE *) 0)->MEMBER) *: \ + ((TYPE *) ((uintptr_t) (PTR) - offsetof(TYPE, MEMBER))), \ + __typeof__ (((TYPE *) 0)->MEMBER) *: \ + ((TYPE *) ((uintptr_t) (PTR) - offsetof(TYPE, MEMBER))) \ + )) +#elif defined __GNUC__ +# define container_of(PTR, TYPE, MEMBER) \ + (__extension__ ({ \ + __extension__ const __typeof__ (((TYPE *) 0)->MEMBER) *__m____ = (PTR); \ + ((TYPE *) ((uintptr_t) __m____ - offsetof(TYPE, MEMBER))); \ + })) +#else +# define container_of(PTR, TYPE, MEMBER) \ + ((TYPE *) ((char *) (PTR) - offsetof(TYPE, MEMBER))) +#endif + +/** + * @def index_of(ARRAY, ELEMENT) + * @brief Returns the index of a pointer to an array element. + + * @param[in] ARRAY an array + * @param[in] ELEMENT pointer to an array element + * @return Index of the element in the array + */ +#define index_of(ARRAY, ELEMENT) (((uintptr_t)(ELEMENT) - (uintptr_t)(ARRAY)) / sizeof((ARRAY)[0])) + +/** + * @def ARRAY_SIZE(a) + * @brief Calculate the number of elements in a static array. + * @param[in] a Array to examine + * @returns The number of elements in the array a. + */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CONTAINER_H */ +/** @} */ diff --git a/core/lib/include/kernel_defines.h b/core/lib/include/kernel_defines.h index df07b50339..9698477fb1 100644 --- a/core/lib/include/kernel_defines.h +++ b/core/lib/include/kernel_defines.h @@ -21,265 +21,15 @@ #ifndef KERNEL_DEFINES_H #define KERNEL_DEFINES_H -#include -#include +#include "modules.h" +#include "riot_version.h" +#include "compiler_hints.h" +#include "container.h" #ifdef __cplusplus extern "C" { #endif -/* uncrustify gets mightily confused by these macros... */ -/* begin{code-style-ignore} */ - -/** - * @def container_of(PTR, TYPE, MEMBER) - * @brief Returns the container of a pointer to a member. - * @details For a struct `TYPE` with a member `MEMBER`, - * given a pointer `PTR` to `TYPE::MEMBER` this function returns a pointer - * to the instance of `TYPE`. - * @details E.g. for `struct my_struct_t { ...; something_t n; ... } my_struct;`, - * `&my_struct == container_of(&my_struct.n, struct my_struct_t, n)`. - * @param[in] PTR pointer to a member - * @param[in] TYPE a type name (a struct or union), container of PTR - * @param[in] MEMBER name of the member of TYPE which PTR points to - * @return Pointer to the container of PTR. - */ -#if __STDC_VERSION__ >= 201112L -# define container_of(PTR, TYPE, MEMBER) \ - (_Generic((PTR), \ - const __typeof__ (((TYPE *) 0)->MEMBER) *: \ - ((TYPE *) ((uintptr_t) (PTR) - offsetof(TYPE, MEMBER))), \ - __typeof__ (((TYPE *) 0)->MEMBER) *: \ - ((TYPE *) ((uintptr_t) (PTR) - offsetof(TYPE, MEMBER))) \ - )) -#elif defined __GNUC__ -# define container_of(PTR, TYPE, MEMBER) \ - (__extension__ ({ \ - __extension__ const __typeof__ (((TYPE *) 0)->MEMBER) *__m____ = (PTR); \ - ((TYPE *) ((uintptr_t) __m____ - offsetof(TYPE, MEMBER))); \ - })) -#else -# define container_of(PTR, TYPE, MEMBER) \ - ((TYPE *) ((char *) (PTR) - offsetof(TYPE, MEMBER))) -#endif - -/** - * @def index_of(ARRAY, ELEMENT) - * @brief Returns the index of a pointer to an array element. - - * @param[in] ARRAY an array - * @param[in] ELEMENT pointer to an array element - * @return Index of the element in the array - */ -#define index_of(ARRAY, ELEMENT) (((uintptr_t)(ELEMENT) - (uintptr_t)(ARRAY)) / sizeof((ARRAY)[0])) - -/** - * @def NORETURN - * @brief The *NORETURN* keyword tells the compiler to assume that the function - * cannot return. - */ -#ifdef __GNUC__ -#define NORETURN __attribute__((noreturn)) -#else -#define NORETURN -#endif - -/** - * @def PURE - * @brief The function has no effects except the return value and its return - * value depends only on the parameters and/or global variables. Such a - * function can be subject to common subexpression elimination and loop - * optimization just as an arithmetic operator would be. - */ -#ifdef __GNUC__ -#define PURE __attribute__((pure)) -#else -#define PURE -#endif - -/** - * @def UNREACHABLE() - * @brief Tell the compiler that this line of code cannot be reached. - * @details Most useful in junction with #NORETURN. - * Use this if the compiler cannot tell that e.g. - * an assembler instruction causes a longjmp, or a write causes a reboot. - */ -#if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 5) -#define UNREACHABLE() __builtin_unreachable() -#else -#define UNREACHABLE() do { /* nothing */ } while (1) -#endif - -/** - * @def ARRAY_SIZE(a) - * @brief Calculate the number of elements in a static array. - * @param[in] a Array to examine - * @returns The number of elements in the array a. - */ -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) -#endif - -/** - * @def IS_ACTIVE(macro) - * @brief Allows to verify a macro definition outside the preprocessor. - * - * @details This macro is based on Linux's clever 'IS_BUILTIN' - * (https://github.com/torvalds/linux/blob/master/include/linux/kconfig.h). - * It takes a @p macro value that may be defined to 1 or not even - * defined (e.g. FEATURE_FOO) and then expands it to an expression - * that can be used in C code, either 1 or 0. - * - * The advantage of using this is that the compiler sees all the - * code, so checks can be performed, sections that would not be - * executed are removed during optimization. For example: - * ``` - * if (IS_ACTIVE(FEATURE_FOO)) { - * do_something(); - * } - * ``` - * @param[in] macro Macro to evaluate - * @returns 1 if the macro is defined to 1 - * @returns 0 if the macro is not defined, of if it is defined to something - * else than 1. - * - * @note This should only be used when macros are defined as 1, it will - * not work if the macro value is, for example, (1) or 1U. - * - * @note Although this may seem to work similarly to the preprocessor's - * 'defined', it is not entirely equal. If the given macro has - * been defined with no value, this will expand to 0. Also note - * that this is intended to be used with 'boolean' macros that act - * as switches, and usually will be defined as 1 or not defined. - */ -#define IS_ACTIVE(macro) __is_active(macro) - -/** - * @def IS_USED(module) - * @brief Checks whether a module is being used or not. Can be used in C - * conditionals. - * - * @param[in] module Module to check - * @returns 1 if the module is being used - * @returns 0 if the module is not being used - */ -#define IS_USED(module) IS_ACTIVE(module) - -/** - * @def RIOT_VERSION_NUM(major, minor, patch, extra) - * @brief Generates a 64 bit variable of a release version. - * Comparisons to this only apply to released branches - * - * To define @p extra add a file `EXTRAVERSION` to the RIOT root - * with the content - * - * RIOT_EXTRAVERSION = - * - * with `` being the number of your local version. - * This can be useful if you are maintaining a downstream - * release to base further work on. - * - * @warning This is only intended to be used with external boards or - * modules. - * In-tree code must not make use of this macro. - * - * @param[in] major Mayor version of the release - * @param[in] minor Minor version of the release - * @param[in] patch Patch level of the release - * @param[in] extra Extra version, user defined - * - * @returns A machine readable version variable - */ -#define RIOT_VERSION_NUM(major, minor, patch, extra) \ - (((0ULL + major) << 48) + ((0ULL + minor) << 32) + \ - ((0ULL + patch) << 16) + (extra)) - -/** - * @brief Disable -Wpedantic for the argument, but restore diagnostic - * settings afterwards - * @param ... The expression that -Wpendantic should not apply to - * - * @warning This is intended for internal use only - * - * This is particularly useful when declaring non-strictly conforming - * preprocessor macros, as the diagnostics need to be disabled where the - * macro is evaluated, not where the macro is declared. - */ -#define WITHOUT_PEDANTIC(...) \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \ - __VA_ARGS__ \ - _Pragma("GCC diagnostic pop") - -/** - * @brief Declare a constant named @p identifier as anonymous `enum` that has - * the value @p const_expr - * - * @warning This is intended for internal use only - * - * This turns any expression that is constant and known at compile time into - * a formal compile time constant. This allows e.g. using non-formally but - * still constant expressions in `static_assert()`. - */ -#define DECLARE_CONSTANT(identifier, const_expr) \ - WITHOUT_PEDANTIC(enum { identifier = const_expr };) - -#if DOXYGEN -/** - * @brief Check if given variable / expression is detected as compile time - * constant - * @note This might return 0 on compile time constant expressions if the - * compiler is not able to prove the constness at the given level - * of optimization. - * @details This will return 0 if the used compiler does not support this - * @warning This is intended for internal use only - * - * This allows providing two different implementations in C, with one being - * more efficient if constant folding is used. - */ -#define IS_CT_CONSTANT(expr) -#elif defined(__GNUC__) -/* both clang and gcc (which both define __GNUC__) support this */ -#define IS_CT_CONSTANT(expr) __builtin_constant_p(expr) -#else -#define IS_CT_CONSTANT(expr) 0 -#endif - -/** - * @cond INTERNAL - */ -/* Here a prefix "__PREFIX_WHEN_" is added to the macro. So if it was a 1 we - * have "__PREFIX_WHEN_1", and if it was not defined we have "__PREFIX_WHEN_". - */ -#define __is_active(val) ___is_active(__PREFIX_WHEN_##val) - -/* With this placeholder we turn the original value into two arguments when the - * original value was defined as 1 (note the comma). - */ -#define __PREFIX_WHEN_1 0, - -/* Here we add two extra arguments, that way the next macro can accept varargs. - * - * If the original macro was defined as 1, this will have three arguments - * (__take_second_arg(0, 1, 0, 0)), otherwise it will have two - * (__take_second_arg(__PREFIX_WHEN_ 1, 0, 0)). The third zero is there just to - * be compliant with C99, which states that when a function-like macro ends - * with ellipsis (...) it should be called with at least one argument for the - * variable list. - */ -#define ___is_active(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0, 0) - -/* Finally, we just always take the second argument, which will be either 1 - * (when three arguments are passed, i.e. macro was defined as 1) or 0 (when - * only two arguments are passed). - */ -#define __take_second_arg(__ignored, val, ...) val -/** - * @endcond - */ - -/* end{code-style-ignore} */ - #ifdef __cplusplus } #endif diff --git a/core/lib/include/modules.h b/core/lib/include/modules.h new file mode 100644 index 0000000000..8310cf36d6 --- /dev/null +++ b/core/lib/include/modules.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * 2017 HAW-Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup core_internal + * @{ + * + * @file + * @brief Common macros and compiler attributes/pragmas configuration + * + * @author René Kijewski + * @author Michel Rottleuthner + */ + +#ifndef MODULES_H +#define MODULES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @def IS_ACTIVE(macro) + * @brief Allows to verify a macro definition outside the preprocessor. + * + * @details This macro is based on Linux's clever 'IS_BUILTIN' + * (https://github.com/torvalds/linux/blob/master/include/linux/kconfig.h). + * It takes a @p macro value that may be defined to 1 or not even + * defined (e.g. FEATURE_FOO) and then expands it to an expression + * that can be used in C code, either 1 or 0. + * + * The advantage of using this is that the compiler sees all the + * code, so checks can be performed, sections that would not be + * executed are removed during optimization. For example: + * ``` + * if (IS_ACTIVE(FEATURE_FOO)) { + * do_something(); + * } + * ``` + * @param[in] macro Macro to evaluate + * @returns 1 if the macro is defined to 1 + * @returns 0 if the macro is not defined, of if it is defined to something + * else than 1. + * + * @note This should only be used when macros are defined as 1, it will + * not work if the macro value is, for example, (1) or 1U. + * + * @note Although this may seem to work similarly to the preprocessor's + * 'defined', it is not entirely equal. If the given macro has + * been defined with no value, this will expand to 0. Also note + * that this is intended to be used with 'boolean' macros that act + * as switches, and usually will be defined as 1 or not defined. + */ +#define IS_ACTIVE(macro) __is_active(macro) + +/** + * @def IS_USED(module) + * @brief Checks whether a module is being used or not. Can be used in C + * conditionals. + * + * @param[in] module Module to check + * @returns 1 if the module is being used + * @returns 0 if the module is not being used + */ +#define IS_USED(module) IS_ACTIVE(module) + +/** + * @cond INTERNAL + */ +/* Here a prefix "__PREFIX_WHEN_" is added to the macro. So if it was a 1 we + * have "__PREFIX_WHEN_1", and if it was not defined we have "__PREFIX_WHEN_". + */ +#define __is_active(val) ___is_active(__PREFIX_WHEN_##val) + +/* With this placeholder we turn the original value into two arguments when the + * original value was defined as 1 (note the comma). + */ +#define __PREFIX_WHEN_1 0, + +/* Here we add two extra arguments, that way the next macro can accept varargs. + * + * If the original macro was defined as 1, this will have three arguments + * (__take_second_arg(0, 1, 0, 0)), otherwise it will have two + * (__take_second_arg(__PREFIX_WHEN_ 1, 0, 0)). The third zero is there just to + * be compliant with C99, which states that when a function-like macro ends + * with ellipsis (...) it should be called with at least one argument for the + * variable list. + */ +#define ___is_active(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0, 0) + +/* Finally, we just always take the second argument, which will be either 1 + * (when three arguments are passed, i.e. macro was defined as 1) or 0 (when + * only two arguments are passed). + */ +#define __take_second_arg(__ignored, val, ...) val +/** + * @endcond + */ + +#ifdef __cplusplus +} +#endif + +#endif /* MODULES_H */ +/** @} */ diff --git a/core/lib/include/riot_version.h b/core/lib/include/riot_version.h new file mode 100644 index 0000000000..688b1c9d27 --- /dev/null +++ b/core/lib/include/riot_version.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * 2017 HAW-Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup core_internal + * @{ + * + * @file + * @brief Common macros and compiler attributes/pragmas configuration + * + * @author René Kijewski + * @author Michel Rottleuthner + */ + +#ifndef RIOT_VERSION_H +#define RIOT_VERSION_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @def RIOT_VERSION_NUM(major, minor, patch, extra) + * @brief Generates a 64 bit variable of a release version. + * Comparisons to this only apply to released branches + * + * To define @p extra add a file `EXTRAVERSION` to the RIOT root + * with the content + * + * RIOT_EXTRAVERSION = + * + * with `` being the number of your local version. + * This can be useful if you are maintaining a downstream + * release to base further work on. + * + * @warning This is only intended to be used with external boards or + * modules. + * In-tree code must not make use of this macro. + * + * @param[in] major Mayor version of the release + * @param[in] minor Minor version of the release + * @param[in] patch Patch level of the release + * @param[in] extra Extra version, user defined + * + * @returns A machine readable version variable + */ +#define RIOT_VERSION_NUM(major, minor, patch, extra) \ + (((0ULL + major) << 48) + ((0ULL + minor) << 32) + \ + ((0ULL + patch) << 16) + (extra)) + +#ifdef __cplusplus +} +#endif + +#endif /* RIOT_VERSION_H */ +/** @} */