Skip to content

Commit

Permalink
kernel: Fixed init_delay initialization on older GCC versions
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
jhol committed Jan 17, 2025
1 parent 7f32b9e commit 10cad65
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 6 deletions.
2 changes: 1 addition & 1 deletion include/zephyr/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,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

Expand Down
10 changes: 8 additions & 2 deletions include/zephyr/sys/time_units.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
8 changes: 5 additions & 3 deletions include/zephyr/sys_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 10cad65

Please sign in to comment.