diff --git a/kernel/timeout.c b/kernel/timeout.c index b8c37bb7e94..0dd93d5d026 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -18,6 +18,17 @@ static sys_dlist_t timeout_list = SYS_DLIST_STATIC_INIT(&timeout_list); static struct k_spinlock timeout_lock; +/* On multiprocessor setups, it's possible to have multiple + * sys_clock_announce() calls arrive in parallel (the latest to exit + * the driver will generally be announcing zero ticks). But we want + * the list of timeouts to be executed serially, so as not to confuse + * application code. This lock wraps the announce loop, external to + * the nested timeout_lock. + */ +#ifdef CONFIG_SMP +static struct k_spinlock ann_lock; +#endif + #define MAX_WAIT (IS_ENABLED(CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE) \ ? K_TICKS_FOREVER : INT_MAX) @@ -242,6 +253,10 @@ void sys_clock_announce(int32_t ticks) z_time_slice(ticks); #endif +#ifdef CONFIG_SMP + k_spinlock_key_t ann_key = k_spin_lock(&ann_lock); +#endif + k_spinlock_key_t key = k_spin_lock(&timeout_lock); announce_remaining = ticks; @@ -270,6 +285,10 @@ void sys_clock_announce(int32_t ticks) sys_clock_set_timeout(next_timeout(), false); k_spin_unlock(&timeout_lock, key); + +#ifdef CONFIG_SMP + k_spin_unlock(&ann_lock, ann_key); +#endif } int64_t sys_clock_tick_get(void)