sched/wdog: Simplify timer expiration for hrtimer.

This commit simplified the timer expiration for hrtimer.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
ouyangxiangzhen
2026-01-28 16:26:54 +08:00
committed by Donny(董九柱)
parent 5bab9fcc7f
commit 3eedf5f22b
11 changed files with 118 additions and 210 deletions
+1 -1
View File
@@ -126,7 +126,7 @@ static void ndelay_accurate(unsigned long nanoseconds)
static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower, static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower,
FAR void *arg) FAR void *arg)
{ {
#if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_HRTIMER) #if defined(CONFIG_SCHED_TICKLESS)
nxsched_process_timer(); nxsched_process_timer();
#else #else
clock_t now; clock_t now;
+10 -3
View File
@@ -145,21 +145,28 @@ void hrtimer_process(uint64_t now);
static inline_function void hrtimer_reprogram(uint64_t next_expired) 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; int ret = 0;
struct timespec ts; struct timespec ts;
clock_nsec2time(&ts, next_expired); clock_nsec2time(&ts, next_expired);
#ifdef CONFIG_ALARM_ARCH # ifdef CONFIG_ALARM_ARCH
ret = up_alarm_start(&ts); ret = up_alarm_start(&ts);
#else # else
struct timespec current; struct timespec current;
up_timer_gettime(&current); up_timer_gettime(&current);
clock_timespec_subtract(&ts, &current, &ts); clock_timespec_subtract(&ts, &current, &ts);
ret = up_timer_start(&ts); ret = up_timer_start(&ts);
#endif # endif
DEBUGASSERT(ret == 0); DEBUGASSERT(ret == 0);
#endif
} }
/**************************************************************************** /****************************************************************************
+2 -3
View File
@@ -48,8 +48,7 @@ set(SRCS
sched_sysinfo.c sched_sysinfo.c
sched_get_stateinfo.c sched_get_stateinfo.c
sched_switchcontext.c sched_switchcontext.c
sched_sleep.c sched_sleep.c)
sched_timer.c)
if(DEFINED CONFIG_STACKCHECK_MARGIN) if(DEFINED CONFIG_STACKCHECK_MARGIN)
if(NOT CONFIG_STACKCHECK_MARGIN EQUAL -1) if(NOT CONFIG_STACKCHECK_MARGIN EQUAL -1)
@@ -98,7 +97,7 @@ if(NOT CONFIG_SCHED_CPULOAD_NONE)
endif() endif()
if(CONFIG_SCHED_TICKLESS) if(CONFIG_SCHED_TICKLESS)
list(APPEND SRCS sched_tickexpiration.c) list(APPEND SRCS sched_processtickless.c)
else() else()
list(APPEND SRCS sched_processtick.c) list(APPEND SRCS sched_processtick.c)
endif() endif()
+2 -2
View File
@@ -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_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_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_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),)
ifneq ($(CONFIG_STACKCHECK_MARGIN),-1) ifneq ($(CONFIG_STACKCHECK_MARGIN),-1)
@@ -79,7 +79,7 @@ endif
endif endif
ifeq ($(CONFIG_SCHED_TICKLESS),y) ifeq ($(CONFIG_SCHED_TICKLESS),y)
CSRCS += sched_tickexpiration.c CSRCS += sched_processtickless.c
else else
CSRCS += sched_processtick.c CSRCS += sched_processtick.c
endif endif
+7 -2
View File
@@ -43,6 +43,7 @@
#include "sched/sched.h" #include "sched/sched.h"
#include "wdog/wdog.h" #include "wdog/wdog.h"
#include "hrtimer/hrtimer.h"
#include "clock/clock.h" #include "clock/clock.h"
/**************************************************************************** /****************************************************************************
@@ -146,7 +147,7 @@ static inline void nxsched_process_scheduler(void)
#endif #endif
/**************************************************************************** /****************************************************************************
* Name: nxsched_process_tick * Name: nxsched_process_timer
* *
* Description: * Description:
* This function handles system timer events. * 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 #ifdef CONFIG_CLOCK_TIMEKEEPING
/* Process wall time */ /* Process wall time */
@@ -185,7 +186,11 @@ void nxsched_process_tick(void)
/* Process watchdogs */ /* Process watchdogs */
#ifdef CONFIG_HRTIMER
hrtimer_process(clock_systime_nsec());
#else
wd_timer(clock_systime_ticks()); wd_timer(clock_systime_ticks());
#endif
#ifdef CONFIG_SYSTEMTICK_HOOK #ifdef CONFIG_SYSTEMTICK_HOOK
/* Call out to a user-provided function in order to perform board-specific, /* Call out to a user-provided function in order to perform board-specific,
@@ -1,5 +1,5 @@
/**************************************************************************** /****************************************************************************
* sched/sched/sched_tickexpiration.c * sched/sched/sched_processtickless.c
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
@@ -39,6 +39,7 @@
#include "sched/sched.h" #include "sched/sched.h"
#include "wdog/wdog.h" #include "wdog/wdog.h"
#include "hrtimer/hrtimer.h"
#include "clock/clock.h" #include "clock/clock.h"
#ifdef CONFIG_CLOCK_TIMEKEEPING #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; irqstate_t flags;
clock_t ticks; clock_t ticks;
@@ -389,6 +393,7 @@ void nxsched_process_tick(void)
wd_timer(ticks); wd_timer(ticks);
leave_critical_section(flags); leave_critical_section(flags);
#endif
} }
/**************************************************************************** /****************************************************************************
-154
View File
@@ -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
}
+1 -1
View File
@@ -95,7 +95,7 @@ int wd_cancel(FAR struct wdog_s *wdog)
if (!list_is_empty(&g_wdactivelist)) if (!list_is_empty(&g_wdactivelist))
{ {
wd_timer_start(wd_next_expire()); wd_timer_start(wd_next_expire(), false);
} }
else else
{ {
+5 -1
View File
@@ -41,7 +41,11 @@
struct list_node g_wdactivelist = LIST_INITIAL_VALUE(g_wdactivelist); 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; bool g_wdtimernested;
clock_t g_wdexpired; clock_t g_wdexpired;
#endif #endif
+18 -4
View File
@@ -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; FAR struct wdog_s *wdog;
irqstate_t flags; irqstate_t flags;
@@ -156,10 +156,12 @@ static inline_function void wd_expiration(clock_t ticks)
if (next_ticks != ticks) if (next_ticks != ticks)
{ {
wd_timer_start(next_ticks); wd_timer_start(next_ticks, true);
} }
leave_critical_section(flags); 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. */ /* 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 /* We need to reassess timer if the watchdog
* list head has changed. * 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. * changed, then this will pick that new delay.
*/ */
wd_timer_start(wd_next_expire()); wd_timer_start(wd_next_expire(), false);
} }
#else #else
UNUSED(reassess); 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) void wd_timer(clock_t ticks)
{ {
/* Check if there are any active watchdogs to process */ /* Check if there are any active watchdogs to process */
wd_expiration(ticks); 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
+65 -37
View File
@@ -38,6 +38,10 @@
#include <nuttx/wdog.h> #include <nuttx/wdog.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#ifdef CONFIG_HRTIMER
# include <nuttx/hrtimer.h>
#endif
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
@@ -61,16 +65,56 @@ extern "C"
extern struct list_node g_wdactivelist; 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 bool g_wdtimernested;
extern clock_t g_wdexpired; extern clock_t g_wdexpired;
#endif #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 * Inline functions
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_SCHED_TICKLESS #if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_HRTIMER)
# define wd_in_callback() (g_wdtimernested) # define wd_in_callback() (g_wdtimernested)
# define wd_set_nested(f) (g_wdtimernested = (f)) # define wd_set_nested(f) (g_wdtimernested = (f))
# define wd_update_expire(expired) (g_wdexpired = (expired)) # define wd_update_expire(expired) (g_wdexpired = (expired))
@@ -80,7 +124,22 @@ extern clock_t g_wdexpired;
# define wd_update_expire(expired) # define wd_update_expire(expired)
#endif #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) static inline_function clock_t wd_adjust_next_tick(clock_t tick)
{ {
clock_t next_tick = 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; 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); clock_t next_tick = wd_adjust_next_tick(tick);
#ifdef CONFIG_SCHED_TICKLESS_ALARM
#ifdef CONFIG_HRTIMER
nxsched_hrtimer_tick_start(tick);
#elif defined(CONFIG_SCHED_TICKLESS_ALARM)
up_alarm_tick_start(next_tick); up_alarm_tick_start(next_tick);
#else #else
up_timer_tick_start(next_tick - clock_systime_ticks()); up_timer_tick_start(next_tick - clock_systime_ticks());
@@ -134,7 +190,7 @@ static inline_function void wd_timer_cancel(void)
#endif #endif
} }
#else #else
# define wd_timer_start(next_tick) # define wd_timer_start(next_tick, in_expiration)
# define wd_timer_cancel() # define wd_timer_cancel()
#endif #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; 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 #undef EXTERN
#ifdef __cplusplus #ifdef __cplusplus
} }