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,
FAR void *arg)
{
#if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_HRTIMER)
#if defined(CONFIG_SCHED_TICKLESS)
nxsched_process_timer();
#else
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)
{
/* `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(&current);
clock_timespec_subtract(&ts, &current, &ts);
ret = up_timer_start(&ts);
#endif
# endif
DEBUGASSERT(ret == 0);
#endif
}
/****************************************************************************
+2 -3
View File
@@ -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()
+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_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
+7 -2
View File
@@ -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,
@@ -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
}
/****************************************************************************
-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))
{
wd_timer_start(wd_next_expire());
wd_timer_start(wd_next_expire(), false);
}
else
{
+5 -1
View File
@@ -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
+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;
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
+65 -37
View File
@@ -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
}