kernel: Fixed init_delay initialization on older GCC versions

Within the K_THREAD_DEFINE macro, a nested set of macros is expanded to
populate the values of a global _static_thread_data structure.

The K_THREAD_DEFINE macro expands to statements including the
Z_THREAD_COMMON_DEFINE macro, which expands to statements including the
Z_THREAD_INITIALIZER macro, which expands to an initialization expression
of a _static_thread_data struct. The init_delay member of that struct is
then initialized with the Z_THREAD_INIT_DELAY_INITIALIZER macro, which
expands to an expression including the SYS_TIMEOUT_MS macro which
converts a number of milliseconds to a number of ticks.

For example, take the following macro:

    K_THREAD_DEFINE(
        thread_X,
        STACKSIZE,
        thread_X_entry_point, NULL, NULL, NULL,
        PRIORITY,
        0,
        0);

In abbreviated form, it expands as follows:

    typedef struct {
        int ticks;
    } k_timeout_t;

    struct _static_thread_data {
        /* ... */
        k_timeout_t init_delay;
    };

    struct _static_thread_data _k_thread_data_thread_X = {
        /* ... */
        .init_delay = (k_timeout_t){ .ticks = 0 }
    };

However, in GCC versions before 5.1, the code fails to compile with the
error "initializer element is not constant", when compiled with the
following options:

    gcc -std=gnu99 -c test.c

In the above code, the error can be corrected by replacing...

    .init_delay = (k_timeout_t){ .ticks = 0 }

...with...

    .init_delay = { .ticks = 0 }

...i.e. removing initialization with a compound literal.

In order to achieve this, this patch reworks the system of macros.

The Z_TIMEOUT_TICKS(t) macro is refactored into Z_TIMEOUT_TICKS_INIT(t)
which defines the initializer part: { .ticks = t }, and Z_TIMEOUT_TICKS(t)
which is defined as ((k_timeout_t) Z_TIMEOUT_TICKS_INIT(t)) .

For symmetry, Z_TIMEOUT_NO_WAIT_INIT is split out of Z_TIMEOUT_NO_WAIT.

Similarly, SYS_TIMEOUT_MS_INIT(ms) is split out of SYS_TIMEOUT_MS(ms) so
that the Z_THREAD_INIT_DELAY_INITIALIZER(ms) macro can use
SYS_TIMEOUT_MS_INIT(ms) which expands Z_TIMEOUT_TICKS_INIT(t) to initialize
init_delay without using a compound literal.

Signed-off-by: Joel Holdsworth <jholdsworth@nvidia.com>
This commit is contained in:
Joel Holdsworth 2025-01-16 09:34:43 -08:00 committed by Benjamin Cabé
commit 52a1db1cf3
3 changed files with 14 additions and 6 deletions

View file

@ -756,7 +756,7 @@ struct _static_thread_data {
#define Z_THREAD_INIT_DELAY_INITIALIZER(ms) .init_delay_ms = (ms)
#define Z_THREAD_INIT_DELAY(thread) SYS_TIMEOUT_MS((thread)->init_delay_ms)
#else
#define Z_THREAD_INIT_DELAY_INITIALIZER(ms) .init_delay = SYS_TIMEOUT_MS(ms)
#define Z_THREAD_INIT_DELAY_INITIALIZER(ms) .init_delay = SYS_TIMEOUT_MS_INIT(ms)
#define Z_THREAD_INIT_DELAY(thread) (thread)->init_delay
#endif

View file

@ -38,10 +38,16 @@ extern "C" {
*/
#define SYS_FOREVER_US (-1)
/** @brief System-wide macro to initialize #k_timeout_t with a number of ticks
* converted from milliseconds.
*/
#define SYS_TIMEOUT_MS_INIT(ms) \
Z_TIMEOUT_TICKS_INIT((ms) == SYS_FOREVER_MS ? \
K_TICKS_FOREVER : Z_TIMEOUT_MS_TICKS(ms))
/** @brief System-wide macro to convert milliseconds to kernel timeouts
*/
#define SYS_TIMEOUT_MS(ms) Z_TIMEOUT_TICKS((ms) == SYS_FOREVER_MS ? \
K_TICKS_FOREVER : Z_TIMEOUT_MS_TICKS(ms))
#define SYS_TIMEOUT_MS(ms) ((k_timeout_t) SYS_TIMEOUT_MS_INIT(ms))
/* Exhaustively enumerated, highly optimized time unit conversion API */

View file

@ -115,12 +115,14 @@ typedef struct {
/** @} */
/** @cond INTERNAL_HIDDEN */
#define Z_TIMEOUT_NO_WAIT ((k_timeout_t) {0})
#define Z_TIMEOUT_NO_WAIT_INIT {0}
#define Z_TIMEOUT_NO_WAIT ((k_timeout_t) Z_TIMEOUT_NO_WAIT_INIT)
#if defined(__cplusplus) && ((__cplusplus - 0) < 202002L)
#define Z_TIMEOUT_TICKS(t) ((k_timeout_t) { (t) })
#define Z_TIMEOUT_TICKS_INIT(t) { (t) }
#else
#define Z_TIMEOUT_TICKS(t) ((k_timeout_t) { .ticks = (t) })
#define Z_TIMEOUT_TICKS_INIT(t) { .ticks = (t) }
#endif
#define Z_TIMEOUT_TICKS(t) ((k_timeout_t) Z_TIMEOUT_TICKS_INIT(t))
#define Z_FOREVER Z_TIMEOUT_TICKS(K_TICKS_FOREVER)
#ifdef CONFIG_TIMEOUT_64BIT