This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit c69cf36b7c5a7a0f0a3d7419cb2246f91fe1dc84 Author: ouyangxiangzhen <[email protected]> AuthorDate: Thu Jan 8 11:09:30 2026 +0800 sched/wdog: Simplify the wdog expiration handling. This commit simplified the wdog expiration handling by introducing the `g_sched_event` timer. Signed-off-by: ouyangxiangzhen <[email protected]> --- sched/sched/sched_timerexpiration.c | 157 ++++++------------------------------ sched/wdog/wd_cancel.c | 11 ++- sched/wdog/wd_initialize.c | 4 + sched/wdog/wd_start.c | 60 ++++---------- sched/wdog/wdog.h | 64 ++++++++++++++- 5 files changed, 113 insertions(+), 183 deletions(-) diff --git a/sched/sched/sched_timerexpiration.c b/sched/sched/sched_timerexpiration.c index cd3201e8cca..ea25b6e7c16 100644 --- a/sched/sched/sched_timerexpiration.c +++ b/sched/sched/sched_timerexpiration.c @@ -78,8 +78,6 @@ static clock_t nxsched_cpu_scheduler(int cpu, clock_t ticks, #endif static clock_t nxsched_process_scheduler(clock_t ticks, clock_t elapsed, bool noswitches); -static clock_t nxsched_timer_process(clock_t ticks, clock_t elapsed, - bool noswitches); static clock_t nxsched_timer_start(clock_t ticks, clock_t interval); /**************************************************************************** @@ -100,9 +98,9 @@ static clock_t g_timer_tick; static atomic_t g_timer_interval; -#ifdef CONFIG_SCHED_TICKLESS -static unsigned int g_timernested; -#endif +/* Wdog timer for scheduler event. */ + +static struct wdog_s g_sched_event; /**************************************************************************** * Private Functions @@ -134,7 +132,7 @@ static inline_function clock_t adjust_next_interval(clock_t interval) return ret; } -static inline_function clock_t get_time_tick(void) +static inline_function clock_t get_time_tick(void) { #ifdef CONFIG_SYSTEM_TIME64 return atomic64_read((FAR atomic64_t *)&g_timer_tick); @@ -164,58 +162,25 @@ int up_timer_gettick(FAR clock_t *ticks) } #endif -#ifdef CONFIG_SCHED_TICKLESS_ALARM -static inline_function -int nxsched_timer_tick_start(clock_t ticks, clock_t delay) +static void nxsched_process_event(wdparm_t noswitches) { -# ifndef CONFIG_ALARM_ARCH - struct timespec ts; - clock_ticks2time(&ts, ticks + delay); - return up_alarm_start(&ts); -# else - return up_alarm_tick_start(ticks + delay); -# endif -} + clock_t ticks; + clock_t next; + clock_t elapsed; -static inline_function -int nxsched_timer_tick_cancel(clock_t *ticks) -{ - int ret; -# ifndef CONFIG_ALARM_ARCH - struct timespec ts; - ret = up_alarm_cancel(&ts); - *ticks = clock_time2ticks_floor(&ts); -# else - ret = up_alarm_tick_cancel(ticks); -# endif - return ret; -} + /* Get the current time. */ -#else -static inline_function -int nxsched_timer_tick_start(clock_t ticks, clock_t delay) -{ -# ifndef CONFIG_TIMER_ARCH - struct timespec ts; - clock_ticks2time(&ts, delay); - return up_timer_start(&ts); -# else - return up_timer_tick_start(delay); -# endif -} + up_timer_gettick(&ticks); -static inline_function -int nxsched_timer_tick_cancel(clock_t *ticks) -{ -# ifndef CONFIG_TIMER_ARCH - struct timespec ts; - up_timer_cancel(&ts); -# else - up_timer_cancel(ticks); -# endif - return up_timer_gettick(ticks); + /* Calculate the elapsed time and update clock tickbase. */ + + elapsed = ticks - update_time_tick(ticks); + + /* Process the timer ticks and set up the next interval (or not) */ + + next = nxsched_process_scheduler(ticks, elapsed, (bool)noswitches); + nxsched_timer_start(ticks, next); } -#endif /**************************************************************************** * Name: nxsched_cpu_scheduler @@ -370,49 +335,6 @@ clock_t nxsched_process_scheduler(clock_t ticks, clock_t elapsed, return minslice; } -/**************************************************************************** - * Name: nxsched_timer_process - * - * Description: - * Process events on timer expiration. - * - * Input Parameters: - * ticks - The number of ticks that have elapsed on the interval timer. - * noswitches - True: Can't do context switches now. - * - * Returned Value: - * The number of ticks to use when setting up the next timer. CLOCK_MAX if - * there is no interesting event to be timed. - * - ****************************************************************************/ - -static clock_t nxsched_timer_process(clock_t ticks, clock_t elapsed, - bool noswitches) -{ - clock_t sched_next_time; - clock_t wdog_next_time; - -#ifdef CONFIG_CLOCK_TIMEKEEPING - /* Process wall time */ - - clock_update_wall_time(); -#endif - - /* Check for operations specific to scheduling policy of the currently - * active task. - */ - - sched_next_time = nxsched_process_scheduler(ticks, elapsed, noswitches); - - /* Process watchdogs */ - - wdog_next_time = wd_timer(ticks, noswitches); - - /* Select the minimum of the two times. */ - - return MIN(sched_next_time, wdog_next_time); -} - /**************************************************************************** * Name: nxsched_timer_start * @@ -433,27 +355,18 @@ static clock_t nxsched_timer_start(clock_t ticks, clock_t interval) if (interval != CLOCK_MAX) { interval = adjust_next_interval(interval); - nxsched_timer_tick_start(ticks, interval); + wd_start_abstick(&g_sched_event, ticks + interval, + nxsched_process_event, 0u); + } + else + { + wd_cancel(&g_sched_event); } atomic_set(&g_timer_interval, interval); return interval; } -static inline_function -clock_t nxsched_timer_update(clock_t ticks, bool noswitches) -{ - clock_t elapsed; - - /* Calculate the elapsed time and update clock tickbase. */ - - elapsed = ticks - update_time_tick(ticks); - - /* Process the timer ticks and set up the next interval (or not) */ - - return nxsched_timer_process(ticks, elapsed, noswitches); -} - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -478,20 +391,12 @@ void nxsched_timer_expiration(void) { irqstate_t flags; clock_t ticks; - clock_t next; up_timer_gettick(&ticks); flags = enter_critical_section(); - /* Get the interval associated with last expiration */ - - g_timernested++; - - next = nxsched_timer_update(ticks, false); - nxsched_timer_start(ticks, next); - - g_timernested--; + wd_timer(ticks); leave_critical_section(flags); } @@ -535,17 +440,7 @@ void nxsched_timer_expiration(void) void nxsched_reassess_timer(void) { - clock_t ticks; - clock_t next; - - if (!g_timernested) - { - /* Cancel the timer and get the current time */ - - nxsched_timer_tick_cancel(&ticks); - next = nxsched_timer_update(ticks, true); - nxsched_timer_start(ticks, next); - } + nxsched_process_event(1u); } /**************************************************************************** diff --git a/sched/wdog/wd_cancel.c b/sched/wdog/wd_cancel.c index fafd9aa1a53..30fe9130b5c 100644 --- a/sched/wdog/wd_cancel.c +++ b/sched/wdog/wd_cancel.c @@ -86,14 +86,21 @@ int wd_cancel(FAR struct wdog_s *wdog) wdog->func = NULL; - if (first == wdog) + if (first == wdog && !wd_in_callback()) { /* If the watchdog is at the head of the timer queue, then * we will need to re-adjust the interval timer that will * generate the next interval event. */ - nxsched_reassess_timer(); + if (!list_is_empty(&g_wdactivelist)) + { + wd_timer_start(wd_next_expire()); + } + else + { + wd_timer_cancel(); + } } ret = OK; diff --git a/sched/wdog/wd_initialize.c b/sched/wdog/wd_initialize.c index 563ad31c9d9..c2d18193ac3 100644 --- a/sched/wdog/wd_initialize.c +++ b/sched/wdog/wd_initialize.c @@ -41,6 +41,10 @@ struct list_node g_wdactivelist = LIST_INITIAL_VALUE(g_wdactivelist); +#ifdef CONFIG_SCHED_TICKLESS +bool g_wdtimernested; +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/sched/wdog/wd_start.c b/sched/wdog/wd_start.c index 0e5ce456085..f261125f8c9 100644 --- a/sched/wdog/wd_start.c +++ b/sched/wdog/wd_start.c @@ -104,16 +104,18 @@ * ****************************************************************************/ -static inline_function clock_t wd_expiration(clock_t ticks) +static inline_function void wd_expiration(clock_t ticks) { FAR struct wdog_s *wdog; irqstate_t flags; wdentry_t func; wdparm_t arg; - clock_t ret = CLOCK_MAX; + clock_t next_ticks = ticks; flags = enter_critical_section(); + wd_set_nested(true); + /* Process the watchdog at the head of the list as well as any * other watchdogs that became ready to run at this time */ @@ -128,7 +130,7 @@ static inline_function clock_t wd_expiration(clock_t ticks) if (!clock_compare(wdog->expired, ticks)) { - ret = wdog->expired - ticks; + next_ticks = wdog->expired; break; } @@ -148,9 +150,14 @@ static inline_function clock_t wd_expiration(clock_t ticks) CALL_FUNC(func, arg); } - leave_critical_section(flags); + wd_set_nested(false); - return ret; + if (next_ticks != ticks) + { + wd_timer_start(wd_next_expire()); + } + + leave_critical_section(flags); } /**************************************************************************** @@ -286,6 +293,7 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t ticks, } reassess |= wd_insert(wdog, ticks, wdentry, arg); + reassess &= !wd_in_callback(); if (reassess) { @@ -294,7 +302,7 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t ticks, * changed, then this will pick that new delay. */ - nxsched_reassess_timer(); + wd_timer_start(wd_next_expire()); } #else UNUSED(reassess); @@ -331,7 +339,6 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t 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 @@ -343,48 +350,9 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t ticks, * ****************************************************************************/ -#ifdef CONFIG_SCHED_TICKLESS -clock_t wd_timer(clock_t ticks, bool noswitches) -{ - FAR struct wdog_s *wdog; - irqstate_t flags; - clock_t ret; - - /* Check if the watchdog at the head of the list is ready to run */ - - if (!noswitches) - { - ret = wd_expiration(ticks); - } - else - { - ret = CLOCK_MAX; - flags = enter_critical_section(); - - /* Return the delay for the next watchdog to expire */ - - if (!list_is_empty(&g_wdactivelist)) - { - /* Notice that if noswitches, expired - g_wdtickbase - * may get negative value. - */ - - wdog = list_first_entry(&g_wdactivelist, struct wdog_s, node); - ret = !clock_compare(wdog->expired, ticks) ? - wdog->expired - ticks : 0u; - } - - leave_critical_section(flags); - } - - return ret; -} - -#else void wd_timer(clock_t ticks) { /* Check if there are any active watchdogs to process */ wd_expiration(ticks); } -#endif /* CONFIG_SCHED_TICKLESS */ diff --git a/sched/wdog/wdog.h b/sched/wdog/wdog.h index 3993a6eb0e4..efcb61bc23a 100644 --- a/sched/wdog/wdog.h +++ b/sched/wdog/wdog.h @@ -36,6 +36,7 @@ #include <nuttx/clock.h> #include <nuttx/queue.h> #include <nuttx/wdog.h> +#include <nuttx/arch.h> /**************************************************************************** * Pre-processor Definitions @@ -60,6 +61,65 @@ extern "C" extern struct list_node g_wdactivelist; +#ifdef CONFIG_SCHED_TICKLESS +extern bool g_wdtimernested; +#endif + +/**************************************************************************** + * Inline functions + ****************************************************************************/ + +#ifdef CONFIG_SCHED_TICKLESS +# define wd_in_callback() (g_wdtimernested) +# define wd_set_nested(f) (g_wdtimernested = (f)) +#else +# define wd_in_callback() (false) +# define wd_set_nested(f) +#endif + +#ifdef CONFIG_SCHED_TICKLESS +static inline_function void wd_timer_start(clock_t next_tick) +{ +#ifdef CONFIG_SCHED_TICKLESS_ALARM +# ifndef CONFIG_ALARM_ARCH + struct timespec ts; + clock_ticks2time(&ts, next_tick); + up_alarm_start(&ts); +# else + up_alarm_tick_start(next_tick); +# endif +#else +# ifndef CONFIG_TIMER_ARCH + struct timespec ts1; + struct timespec ts2; + clock_ticks2time(&ts1, next_tick); + clock_systime_timespec(&ts2); + clock_timespec_subtract(&ts1, &ts2, &ts1); + up_timer_start(&ts1); +# else + up_timer_tick_start(next_tick - clock_systime_ticks()); +# endif +#endif +} +static inline_function void wd_timer_cancel(void) +{ + struct timespec ts; +#ifdef CONFIG_SCHED_TICKLESS_ALARM + up_alarm_cancel(&ts); +#else + up_timer_cancel(&ts); +#endif +} +#else +# define wd_timer_start(next_tick) +# define wd_timer_cancel() +#endif + +static inline_function clock_t wd_next_expire(void) +{ + return list_first_entry(&g_wdactivelist, struct wdog_s, node)->expired; +} + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -90,11 +150,7 @@ extern struct list_node g_wdactivelist; * ****************************************************************************/ -#ifdef CONFIG_SCHED_TICKLESS -clock_t wd_timer(clock_t ticks, bool noswitches); -#else void wd_timer(clock_t ticks); -#endif #undef EXTERN #ifdef __cplusplus
