From 1330b22d6717a77441ff637372f21e87e4f4988f Mon Sep 17 00:00:00 2001 From: chao an Date: Tue, 3 Mar 2026 17:47:40 +0800 Subject: [PATCH] sched/tickless: Fix CLOCK_MONOTONIC always 0 by updating sched ticks Fix the issue where clock_gettime(CLOCK_MONOTONIC) always returns 0 in tickless mode, caused by the scheduler tick counter (g_system_ticks) not being updated with the actual timer ticks. 1. Add clock_update_sched_ticks() function to sched/clock/clock_sched_ticks.c: a. This function directly sets the system tick counter to a specific value (vs incrementing in clock_increase_sched_ticks), with full documentation matching the existing code style. b. Uses seqlock to ensure thread-safe access to g_system_ticks. 2. Call clock_update_sched_ticks() in nxsched_process_timer() (sched_processtickless.c): a. Syncs the scheduler tick counter with the actual timer ticks retrieved via up_timer_gettick(). With this fix, g_system_ticks is properly updated in tickless mode, and clock_gettime(CLOCK_MONOTONIC) returns the correct non-zero monotonic time. Signed-off-by: chao an --- sched/clock/clock.h | 73 +++++++++++++++++++++++++++++ sched/clock/clock_sched_ticks.c | 28 +++++++++++ sched/sched/sched_processtickless.c | 10 +++- 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/sched/clock/clock.h b/sched/clock/clock.h index a59ce4a8627df..71b80297b094f 100644 --- a/sched/clock/clock.h +++ b/sched/clock/clock.h @@ -70,15 +70,88 @@ extern spinlock_t g_basetime_lock; * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: clock_basetime + * + * Description: + * Get the initial time value from the best source available. + * + ****************************************************************************/ + int clock_basetime(FAR struct timespec *tp); +/**************************************************************************** + * Name: clock_initialize + * + * Description: + * Perform one-time initialization of the timing facilities. + * + ****************************************************************************/ + void clock_initialize(void); +/**************************************************************************** + * Name: clock_update_sched_ticks + * + * Description: + * Update the scheduler tick counter to a specific value. This function + * directly sets the system tick counter to the given value (rather than + * incrementing it), typically used for synchronizing or resetting the + * scheduler tick count to a known state. + * + * Input Parameters: + * ticks - The new value to set for the scheduler tick counter + * + * Returned Value: + * None + * + ****************************************************************************/ + +void clock_update_sched_ticks(clock_t ticks); + +/**************************************************************************** + * Name: clock_increase_sched_ticks + * + * Description: + * Increment the scheduler tick counter. This function should be called + * each time the real-time clock interrupt occurs, indicating the passage + * of one or more scheduling ticks. + * + * Input Parameters: + * ticks - The number of ticks to increment (typically 1) + * + * Returned Value: + * None + * + ****************************************************************************/ + void clock_increase_sched_ticks(clock_t ticks); +/**************************************************************************** + * Name: clock_get_sched_ticks + * + * Description: + * Return the current value of the scheduler tick counter. This counter + * only increases while the scheduler is running, and is independent of + * the real-time clock. + * + * Returned Value: + * The current number of scheduler ticks. + * + ****************************************************************************/ + clock_t clock_get_sched_ticks(void); #ifdef CONFIG_SCHED_CPULOAD_SYSCLK + +/**************************************************************************** + * Name: cpuload_init + * + * Description: + * Initialize the CPU load measurement logic. + * + ****************************************************************************/ + void cpuload_init(void); #endif diff --git a/sched/clock/clock_sched_ticks.c b/sched/clock/clock_sched_ticks.c index 353e4f3e0b1d4..282a51450f7c4 100644 --- a/sched/clock/clock_sched_ticks.c +++ b/sched/clock/clock_sched_ticks.c @@ -46,6 +46,34 @@ static seqcount_t g_system_tick_lock = SEQLOCK_INITIALIZER; * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: clock_update_sched_ticks + * + * Description: + * Update the scheduler tick counter to a specific value. This function + * directly sets the system tick counter to the given value (rather than + * incrementing it), typically used for synchronizing or resetting the + * scheduler tick count to a known state. + * + * Input Parameters: + * ticks - The new value to set for the scheduler tick counter + * + * Returned Value: + * None + * + ****************************************************************************/ + +void clock_update_sched_ticks(clock_t ticks) +{ + irqstate_t flags; + + /* Increment the per-tick scheduler counter */ + + flags = write_seqlock_irqsave(&g_system_tick_lock); + g_system_ticks = ticks; + write_sequnlock_irqrestore(&g_system_tick_lock, flags); +} + /**************************************************************************** * Name: clock_increase_sched_ticks * diff --git a/sched/sched/sched_processtickless.c b/sched/sched/sched_processtickless.c index 352d9f105bab2..8eea08ad9bdce 100644 --- a/sched/sched/sched_processtickless.c +++ b/sched/sched/sched_processtickless.c @@ -375,13 +375,17 @@ void nxsched_process_timer(void) { #ifdef CONFIG_HRTIMER uint64_t nsec = clock_systime_nsec(); + clock_t ticks = NSEC2TICK(nsec); + + clock_update_sched_ticks(ticks); + hrtimer_process(nsec); # if CONFIG_RR_INTERVAL > 0 /* Workaround for SCHED_RR, see the note. */ irqstate_t flags = enter_critical_section(); - nxsched_process_event(div_const(nsec, (uint32_t)NSEC_PER_TICK), true); + nxsched_process_event(ticks, true); leave_critical_section(flags); # endif @@ -397,6 +401,10 @@ void nxsched_process_timer(void) up_timer_gettick(&ticks); + /* Update sched ticks */ + + clock_update_sched_ticks(ticks); + #if CONFIG_RR_INTERVAL > 0 /* Workaround for SCHED_RR, see the note. */