This is an automated email from the ASF dual-hosted git repository. jiuzhudong pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 3eedf5f22bd283e966f50dbc2d654bb2db1bce1c Author: ouyangxiangzhen <[email protected]> AuthorDate: Wed Jan 28 16:26:54 2026 +0800 sched/wdog: Simplify timer expiration for hrtimer. This commit simplified the timer expiration for hrtimer. Signed-off-by: ouyangxiangzhen <[email protected]> --- drivers/timers/arch_alarm.c | 2 +- sched/hrtimer/hrtimer.h | 13 +- sched/sched/CMakeLists.txt | 5 +- sched/sched/Make.defs | 4 +- sched/sched/sched_processtick.c | 9 +- ...ed_tickexpiration.c => sched_processtickless.c} | 9 +- sched/sched/sched_timer.c | 154 --------------------- sched/wdog/wd_cancel.c | 2 +- sched/wdog/wd_initialize.c | 6 +- sched/wdog/wd_start.c | 22 ++- sched/wdog/wdog.h | 102 +++++++++----- 11 files changed, 118 insertions(+), 210 deletions(-) diff --git a/drivers/timers/arch_alarm.c b/drivers/timers/arch_alarm.c index dbb44a267df..8c0140bc2a3 100644 --- a/drivers/timers/arch_alarm.c +++ b/drivers/timers/arch_alarm.c @@ -126,7 +126,7 @@ static void ndelay_accurate(unsigned long nanoseconds) static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower, FAR void *arg) { -#if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_HRTIMER) +#if defined(CONFIG_SCHED_TICKLESS) nxsched_process_timer(); #else clock_t now; diff --git a/sched/hrtimer/hrtimer.h b/sched/hrtimer/hrtimer.h index eea66bef28e..478ff90a88a 100644 --- a/sched/hrtimer/hrtimer.h +++ b/sched/hrtimer/hrtimer.h @@ -145,21 +145,28 @@ void hrtimer_process(uint64_t now); static inline_function void hrtimer_reprogram(uint64_t next_expired) { + /* `hrtimer_reprogram` relies on the underlying timer being a non-periodic + * timer. If the underlying timer hardware is a periodic timer like + * systick, we cannot set the next expiration time. + */ + +#ifdef CONFIG_SCHED_TICKLESS int ret = 0; struct timespec ts; clock_nsec2time(&ts, next_expired); -#ifdef CONFIG_ALARM_ARCH +# ifdef CONFIG_ALARM_ARCH ret = up_alarm_start(&ts); -#else +# else struct timespec current; up_timer_gettime(¤t); clock_timespec_subtract(&ts, ¤t, &ts); ret = up_timer_start(&ts); -#endif +# endif DEBUGASSERT(ret == 0); +#endif } /**************************************************************************** diff --git a/sched/sched/CMakeLists.txt b/sched/sched/CMakeLists.txt index 14c731bdcca..be709a4ecb0 100644 --- a/sched/sched/CMakeLists.txt +++ b/sched/sched/CMakeLists.txt @@ -48,8 +48,7 @@ set(SRCS sched_sysinfo.c sched_get_stateinfo.c sched_switchcontext.c - sched_sleep.c - sched_timer.c) + sched_sleep.c) if(DEFINED CONFIG_STACKCHECK_MARGIN) if(NOT CONFIG_STACKCHECK_MARGIN EQUAL -1) @@ -98,7 +97,7 @@ if(NOT CONFIG_SCHED_CPULOAD_NONE) endif() if(CONFIG_SCHED_TICKLESS) - list(APPEND SRCS sched_tickexpiration.c) + list(APPEND SRCS sched_processtickless.c) else() list(APPEND SRCS sched_processtick.c) endif() diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index 3bb641e84df..1aae136ecec 100644 --- a/sched/sched/Make.defs +++ b/sched/sched/Make.defs @@ -30,7 +30,7 @@ CSRCS += sched_yield.c sched_rrgetinterval.c sched_foreach.c CSRCS += sched_lock.c sched_unlock.c sched_lockcount.c CSRCS += sched_idletask.c sched_self.c sched_get_stackinfo.c sched_get_tls.c CSRCS += sched_sysinfo.c sched_get_stateinfo.c sched_getcpu.c -CSRCS += sched_switchcontext.c sched_sleep.c sched_timer.c +CSRCS += sched_switchcontext.c sched_sleep.c ifneq ($(CONFIG_STACKCHECK_MARGIN),) ifneq ($(CONFIG_STACKCHECK_MARGIN),-1) @@ -79,7 +79,7 @@ endif endif ifeq ($(CONFIG_SCHED_TICKLESS),y) -CSRCS += sched_tickexpiration.c +CSRCS += sched_processtickless.c else CSRCS += sched_processtick.c endif diff --git a/sched/sched/sched_processtick.c b/sched/sched/sched_processtick.c index 7457f556bd5..44d3d169a54 100644 --- a/sched/sched/sched_processtick.c +++ b/sched/sched/sched_processtick.c @@ -43,6 +43,7 @@ #include "sched/sched.h" #include "wdog/wdog.h" +#include "hrtimer/hrtimer.h" #include "clock/clock.h" /**************************************************************************** @@ -146,7 +147,7 @@ static inline void nxsched_process_scheduler(void) #endif /**************************************************************************** - * Name: nxsched_process_tick + * Name: nxsched_process_timer * * Description: * This function handles system timer events. @@ -165,7 +166,7 @@ static inline void nxsched_process_scheduler(void) * ****************************************************************************/ -void nxsched_process_tick(void) +void nxsched_process_timer(void) { #ifdef CONFIG_CLOCK_TIMEKEEPING /* Process wall time */ @@ -185,7 +186,11 @@ void nxsched_process_tick(void) /* Process watchdogs */ +#ifdef CONFIG_HRTIMER + hrtimer_process(clock_systime_nsec()); +#else wd_timer(clock_systime_ticks()); +#endif #ifdef CONFIG_SYSTEMTICK_HOOK /* Call out to a user-provided function in order to perform board-specific, diff --git a/sched/sched/sched_tickexpiration.c b/sched/sched/sched_processtickless.c similarity index 98% rename from sched/sched/sched_tickexpiration.c rename to sched/sched/sched_processtickless.c index afbc05fcad3..6778607f27a 100644 --- a/sched/sched/sched_tickexpiration.c +++ b/sched/sched/sched_processtickless.c @@ -1,5 +1,5 @@ /**************************************************************************** - * sched/sched/sched_tickexpiration.c + * sched/sched/sched_processtickless.c * * SPDX-License-Identifier: Apache-2.0 * @@ -39,6 +39,7 @@ #include "sched/sched.h" #include "wdog/wdog.h" +#include "hrtimer/hrtimer.h" #include "clock/clock.h" #ifdef CONFIG_CLOCK_TIMEKEEPING @@ -362,8 +363,11 @@ static void nxsched_timer_start(clock_t ticks, clock_t interval) * ****************************************************************************/ -void nxsched_process_tick(void) +void nxsched_process_timer(void) { +#ifdef CONFIG_HRTIMER + hrtimer_process(clock_systime_nsec()); +#else irqstate_t flags; clock_t ticks; @@ -389,6 +393,7 @@ void nxsched_process_tick(void) wd_timer(ticks); leave_critical_section(flags); +#endif } /**************************************************************************** diff --git a/sched/sched/sched_timer.c b/sched/sched/sched_timer.c deleted file mode 100644 index e59b60debd0..00000000000 --- a/sched/sched/sched_timer.c +++ /dev/null @@ -1,154 +0,0 @@ -/**************************************************************************** - * sched/sched/sched_timer.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> -#include <nuttx/arch.h> -#include <nuttx/clock.h> - -#include <errno.h> - -#include "sched/sched.h" -#include "hrtimer/hrtimer.h" - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* High-resolution timer used to drive the scheduler tick. - * - * In non-tickless mode, this timer periodically generates a scheduler - * tick with interval NSEC_PER_TICK. - * - * In tickless mode, the timer is still used, but the callback does not - * request automatic re-arming. - */ - -#ifdef CONFIG_HRTIMER -static hrtimer_t g_sched_hrtimer; -static bool g_sched_hrtimer_started = false; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: nxsched_hrtimer_callback - * - * Description: - * High-resolution timer callback used to drive the scheduler. - * - * This callback is invoked when the scheduler hrtimer expires. - * It advances the scheduler time base by calling - * nxsched_process_tick(). - * - * Input Parameters: - * hrtimer - Pointer to the expired hrtimer instance - * expired - Expiration time in nanoseconds - * - * Returned Value: - * In non-tickless mode: - * Returns the next expiration interval (NSEC_PER_TICK), - * causing the hrtimer to be re-armed periodically. - * - * In tickless mode: - * Returns 0 to indicate that the timer should not be - * automatically restarted. - * - ****************************************************************************/ - -#ifdef CONFIG_HRTIMER -static uint64_t -nxsched_hrtimer_callback(FAR const struct hrtimer_s *hrtimer, - uint64_t expired) -{ - UNUSED(hrtimer); - UNUSED(expired); - - /* Advance scheduler time and process time slice expiration */ - - nxsched_process_tick(); - -#ifndef CONFIG_SCHED_TICKLESS - /* Periodic tick mode: re-arm timer with fixed tick interval */ - - return NSEC_PER_TICK; -#else - /* Tickless mode controls the next wakeup explicitly */ - - return 0; -#endif -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -#if defined(CONFIG_HRTIMER) && defined(CONFIG_SCHED_TICKLESS) -int nxsched_hrtimer_tick_start(clock_t tick) -{ - return hrtimer_start(&g_sched_hrtimer, - nxsched_hrtimer_callback, - tick * NSEC_PER_TICK, - HRTIMER_MODE_ABS); -} -#endif - -/**************************************************************************** - * Name: nxsched_process_timer - * - * Description: - * Process scheduler timing events. - * - * If high-resolution timers are enabled, this function dispatches - * expired hrtimers based on the current hrtimer time. - * - * Otherwise, it falls back to directly processing a scheduler tick. - * - ****************************************************************************/ - -void nxsched_process_timer(void) -{ -#ifdef CONFIG_HRTIMER - /* Process all expired high-resolution timers */ - - if (g_sched_hrtimer_started == false) - { - g_sched_hrtimer_started = true; - hrtimer_start(&g_sched_hrtimer, - nxsched_hrtimer_callback, - NSEC_PER_TICK, - HRTIMER_MODE_REL); - } - - hrtimer_process(clock_systime_nsec()); -#else - /* Fallback: process one scheduler tick */ - - nxsched_process_tick(); -#endif -} diff --git a/sched/wdog/wd_cancel.c b/sched/wdog/wd_cancel.c index 30fe9130b5c..1a8202e403b 100644 --- a/sched/wdog/wd_cancel.c +++ b/sched/wdog/wd_cancel.c @@ -95,7 +95,7 @@ int wd_cancel(FAR struct wdog_s *wdog) if (!list_is_empty(&g_wdactivelist)) { - wd_timer_start(wd_next_expire()); + wd_timer_start(wd_next_expire(), false); } else { diff --git a/sched/wdog/wd_initialize.c b/sched/wdog/wd_initialize.c index 779fea13a86..40cff0e6903 100644 --- a/sched/wdog/wd_initialize.c +++ b/sched/wdog/wd_initialize.c @@ -41,7 +41,11 @@ struct list_node g_wdactivelist = LIST_INITIAL_VALUE(g_wdactivelist); -#ifdef CONFIG_SCHED_TICKLESS +#ifdef CONFIG_HRTIMER +struct hrtimer_s g_wdtimer; +#endif + +#if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_HRTIMER) bool g_wdtimernested; clock_t g_wdexpired; #endif diff --git a/sched/wdog/wd_start.c b/sched/wdog/wd_start.c index 10e16545a30..afdfc1cdaee 100644 --- a/sched/wdog/wd_start.c +++ b/sched/wdog/wd_start.c @@ -104,7 +104,7 @@ * ****************************************************************************/ -static inline_function void wd_expiration(clock_t ticks) +static inline_function clock_t wd_expiration(clock_t ticks) { FAR struct wdog_s *wdog; irqstate_t flags; @@ -156,10 +156,12 @@ static inline_function void wd_expiration(clock_t ticks) if (next_ticks != ticks) { - wd_timer_start(next_ticks); + wd_timer_start(next_ticks, true); } leave_critical_section(flags); + + return next_ticks; } /**************************************************************************** @@ -283,7 +285,7 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t ticks, /* If the wdog is canceling, restarting the wdog is not allowed. */ -#ifdef CONFIG_SCHED_TICKLESS +#if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_HRTIMER) /* We need to reassess timer if the watchdog * list head has changed. */ @@ -304,7 +306,7 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t ticks, * changed, then this will pick that new delay. */ - wd_timer_start(wd_next_expire()); + wd_timer_start(wd_next_expire(), false); } #else UNUSED(reassess); @@ -352,9 +354,21 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t ticks, * ****************************************************************************/ +#ifndef CONFIG_HRTIMER void wd_timer(clock_t ticks) { /* Check if there are any active watchdogs to process */ wd_expiration(ticks); } +#else +uint64_t wd_timer(const hrtimer_t *timer, uint64_t expired) +{ + /* Check if there are any active watchdogs to process */ + + clock_t tick = div_const(expired, NSEC_PER_TICK); + clock_t delay = wd_expiration(tick) - tick; + uint64_t nsec = TICK2NSEC((uint64_t)delay); + return nsec <= HRTIMER_MAX_DELAY ? nsec : HRTIMER_MAX_DELAY; +} +#endif diff --git a/sched/wdog/wdog.h b/sched/wdog/wdog.h index 41ed4807fa4..8303e6bb35a 100644 --- a/sched/wdog/wdog.h +++ b/sched/wdog/wdog.h @@ -38,6 +38,10 @@ #include <nuttx/wdog.h> #include <nuttx/arch.h> +#ifdef CONFIG_HRTIMER +# include <nuttx/hrtimer.h> +#endif + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -61,16 +65,56 @@ extern "C" extern struct list_node g_wdactivelist; -#ifdef CONFIG_SCHED_TICKLESS +#ifdef CONFIG_HRTIMER +extern struct hrtimer_s g_wdtimer; +#endif + +#if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_HRTIMER) extern bool g_wdtimernested; extern clock_t g_wdexpired; #endif +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: wd_timer + * + * Description: + * This function is called from the timer interrupt handler to determine + * if it is time to execute a watchdog function. If so, the watchdog + * function will be executed in the context of the timer interrupt + * handler. + * + * Input Parameters: + * ticks - If CONFIG_SCHED_TICKLESS is defined then the number of ticks + * in the interval that just expired is provided. Otherwise, + * this function is called on each timer interrupt and a value of one + * is implicit. + * noswitches - True: Can't do context switches now. + * + * Returned Value: + * If CONFIG_SCHED_TICKLESS is defined then the number of ticks for the + * next delay is provided (zero if no delay). Otherwise, this function + * has no returned value. + * + * Assumptions: + * Called from interrupt handler logic with interrupts disabled. + * + ****************************************************************************/ + +#ifndef CONFIG_HRTIMER +void wd_timer(clock_t ticks); +#else +uint64_t wd_timer(const hrtimer_t *timer, uint64_t expired); +#endif + /**************************************************************************** * Inline functions ****************************************************************************/ -#ifdef CONFIG_SCHED_TICKLESS +#if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_HRTIMER) # define wd_in_callback() (g_wdtimernested) # define wd_set_nested(f) (g_wdtimernested = (f)) # define wd_update_expire(expired) (g_wdexpired = (expired)) @@ -80,7 +124,22 @@ extern clock_t g_wdexpired; # define wd_update_expire(expired) #endif -#ifdef CONFIG_SCHED_TICKLESS +#ifdef CONFIG_HRTIMER +static inline_function void wd_timer_start(clock_t tick, bool in_expiration) +{ + DEBUGASSERT((uint64_t)tick <= UINT64_MAX / NSEC_PER_TICK); + if (!in_expiration) + { + hrtimer_start(&g_wdtimer, wd_timer, + TICK2NSEC((uint64_t)tick), HRTIMER_MODE_ABS); + } +} + +static inline_function void wd_timer_cancel(void) +{ + hrtimer_cancel(&g_wdtimer); +} +#elif defined(CONFIG_SCHED_TICKLESS) static inline_function clock_t wd_adjust_next_tick(clock_t tick) { clock_t next_tick = tick; @@ -111,13 +170,10 @@ static inline_function clock_t wd_adjust_next_tick(clock_t tick) return next_tick; } -static inline_function void wd_timer_start(clock_t tick) +static inline_function void wd_timer_start(clock_t tick, bool in_expiration) { clock_t next_tick = wd_adjust_next_tick(tick); - -#ifdef CONFIG_HRTIMER - nxsched_hrtimer_tick_start(tick); -#elif defined(CONFIG_SCHED_TICKLESS_ALARM) +#ifdef CONFIG_SCHED_TICKLESS_ALARM up_alarm_tick_start(next_tick); #else up_timer_tick_start(next_tick - clock_systime_ticks()); @@ -134,7 +190,7 @@ static inline_function void wd_timer_cancel(void) #endif } #else -# define wd_timer_start(next_tick) +# define wd_timer_start(next_tick, in_expiration) # define wd_timer_cancel() #endif @@ -161,34 +217,6 @@ static inline_function clock_t wd_get_next_expire(clock_t curr) return (sclock_t)(next - curr) <= 0 ? 0u : next; } -/**************************************************************************** - * Name: wd_timer - * - * Description: - * This function is called from the timer interrupt handler to determine - * if it is time to execute a watchdog function. If so, the watchdog - * function will be executed in the context of the timer interrupt - * handler. - * - * Input Parameters: - * ticks - If CONFIG_SCHED_TICKLESS is defined then the number of ticks - * in the interval that just expired is provided. Otherwise, - * this function is called on each timer interrupt and a value of one - * is implicit. - * noswitches - True: Can't do context switches now. - * - * Returned Value: - * If CONFIG_SCHED_TICKLESS is defined then the number of ticks for the - * next delay is provided (zero if no delay). Otherwise, this function - * has no returned value. - * - * Assumptions: - * Called from interrupt handler logic with interrupts disabled. - * - ****************************************************************************/ - -void wd_timer(clock_t ticks); - #undef EXTERN #ifdef __cplusplus }
