From 6bc97586297a62c886ab2f658e5268ca00bad262 Mon Sep 17 00:00:00 2001 From: wangchengdong Date: Wed, 7 Jan 2026 17:32:28 +0800 Subject: [PATCH] [EXPERIMENTAL]sched/sched: Add hrtimer support to scheduler This commit add hrtimer support to scheduler tick without altering the existing scheduler behavior. Signed-off-by: Chengdong Wang --- drivers/timers/arch_alarm.c | 7 +- include/nuttx/arch.h | 6 +- sched/init/nx_start.c | 4 + sched/sched/CMakeLists.txt | 5 +- sched/sched/Make.defs | 4 +- sched/sched/sched.h | 34 +++++ sched/sched/sched_processtimer.c | 187 +++++++++++++++++++++++++--- sched/sched/sched_timerexpiration.c | 4 + 8 files changed, 224 insertions(+), 27 deletions(-) diff --git a/drivers/timers/arch_alarm.c b/drivers/timers/arch_alarm.c index 4f04e0d44b66b..aee6b22e240da 100644 --- a/drivers/timers/arch_alarm.c +++ b/drivers/timers/arch_alarm.c @@ -118,8 +118,9 @@ static void ndelay_accurate(unsigned long nanoseconds) static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower, FAR void *arg) { -#ifdef CONFIG_SCHED_TICKLESS - nxsched_timer_expiration(); +#if defined(CONFIG_HRTIMER) || defined(CONFIG_SCHED_TICKLESS) + nxsched_process_timer(); + #else clock_t now; @@ -380,7 +381,7 @@ int weak_function up_alarm_tick_cancel(FAR clock_t *ticks) * ****************************************************************************/ -#ifdef CONFIG_SCHED_TICKLESS +#if defined(CONFIG_HRTIMER) || defined(CONFIG_SCHED_TICKLESS) int weak_function up_alarm_start(FAR const struct timespec *ts) { int ret = -EAGAIN; diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index 788b4219909fb..fd4b639fc5d67 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -2031,7 +2031,8 @@ int up_alarm_tick_cancel(FAR clock_t *ticks); * ****************************************************************************/ -#if defined(CONFIG_SCHED_TICKLESS) && defined(CONFIG_SCHED_TICKLESS_ALARM) +#if defined(CONFIG_HRTIMER)|| \ + (defined(CONFIG_SCHED_TICKLESS) && defined(CONFIG_SCHED_TICKLESS_ALARM)) int up_alarm_start(FAR const struct timespec *ts); int up_alarm_tick_start(clock_t ticks); #endif @@ -2461,10 +2462,7 @@ void up_ndelay(unsigned long nanoseconds); * ****************************************************************************/ -#ifndef CONFIG_SCHED_TICKLESS void nxsched_process_timer(void); -#endif - /**************************************************************************** * Name: nxsched_timer_expiration * diff --git a/sched/init/nx_start.c b/sched/init/nx_start.c index be28b4565ca21..8b8d932176570 100644 --- a/sched/init/nx_start.c +++ b/sched/init/nx_start.c @@ -642,6 +642,10 @@ void nx_start(void) timer_initialize(); #endif +#ifdef CONFIG_HRTIMER + nxsched_hrtimer_init(); +#endif + /* Initialize the signal facility (if in link) */ nxsig_initialize(); diff --git a/sched/sched/CMakeLists.txt b/sched/sched/CMakeLists.txt index 782234f846d20..1f7d29875bb9b 100644 --- a/sched/sched/CMakeLists.txt +++ b/sched/sched/CMakeLists.txt @@ -48,7 +48,8 @@ set(SRCS sched_sysinfo.c sched_get_stateinfo.c sched_switchcontext.c - sched_sleep.c) + sched_sleep.c + sched_processtimer.c) if(DEFINED CONFIG_STACKCHECK_MARGIN) if(NOT CONFIG_STACKCHECK_MARGIN EQUAL -1) @@ -98,8 +99,6 @@ endif() if(CONFIG_SCHED_TICKLESS) list(APPEND SRCS sched_timerexpiration.c) -else() - list(APPEND SRCS sched_processtimer.c) endif() if(CONFIG_SCHED_CRITMONITOR) diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index 71a7bc2ce6be7..232408a753611 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 +CSRCS += sched_switchcontext.c sched_sleep.c sched_processtimer.c ifneq ($(CONFIG_STACKCHECK_MARGIN),) ifneq ($(CONFIG_STACKCHECK_MARGIN),-1) @@ -80,8 +80,6 @@ endif ifeq ($(CONFIG_SCHED_TICKLESS),y) CSRCS += sched_timerexpiration.c -else -CSRCS += sched_processtimer.c endif ifeq ($(CONFIG_SCHED_CRITMONITOR),y) diff --git a/sched/sched/sched.h b/sched/sched/sched.h index 3fb922585cbd0..2fbe24560b8d4 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -607,4 +607,38 @@ static inline_function int nxsched_select_cpu(cpu_set_t affinity) return cpu; } # endif + +#ifdef CONFIG_HRTIMER +/**************************************************************************** + * Name: nxsched_hrtimer_start + * + * Description: + * (Re)start the scheduler high-resolution timer with a new expiration + * based on the specified tick interval. + * + * Input Parameters: + * ticks - Number of scheduler ticks until expiration. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int nxsched_hrtimer_start(clock_t ticks); + +/**************************************************************************** + * Name: nxsched_hrtimer_init + * + * Description: + * Initialize the scheduler high-resolution timer (hrtimer) instance + * and arm the first scheduler timer event. + * + * Returned Value: + * Zero on success, or a negative errno value on failure. + * + ****************************************************************************/ + +int nxsched_hrtimer_init(void); +#endif + #endif /* __SCHED_SCHED_SCHED_H */ diff --git a/sched/sched/sched_processtimer.c b/sched/sched/sched_processtimer.c index 6dbf2d155095f..2582dbe1b6432 100644 --- a/sched/sched/sched_processtimer.c +++ b/sched/sched/sched_processtimer.c @@ -44,11 +44,108 @@ #include "sched/sched.h" #include "wdog/wdog.h" #include "clock/clock.h" +#include "hrtimer/hrtimer.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_HRTIMER + +/* Scheduler-owned high-resolution timer instance. + * + * This timer acts as the time source for scheduler-related events: + * + * - Periodic scheduler ticks in non-tickless mode + * - Dynamic expiration points in tickless mode + * + * The timer is initialized lazily to avoid unnecessary setup when + * CONFIG_HRTIMER is enabled but not used immediately. + */ + +static hrtimer_t g_nxsched_hrtimer; /**************************************************************************** * Private Functions ****************************************************************************/ +static void nxsched_process_tick(void); + +/**************************************************************************** + * Name: nxsched_hrtimer_callback + * + * Description: + * Callback invoked by the high-resolution timer framework when the + * scheduler timer expires. + * + * Behavior depends on scheduler configuration: + * + * CONFIG_SCHED_TICKLESS: + * - Query current high-resolution time + * - Convert time to scheduler ticks + * - Notify scheduler via nxsched_tick_expiration() + * + * !CONFIG_SCHED_TICKLESS: + * - Re-arm the next periodic tick + * - Process a single scheduler tick + * + * Input Parameters: + * hrtimer - Pointer to the expired high-resolution timer + * + * Returned Value: + * In non-tickless mode, returns the interval until the next expiration. + * In tickless mode, the return value is ignored. + * + ****************************************************************************/ + +static uint64_t +nxsched_hrtimer_callback(FAR hrtimer_t *hrtimer, uint64_t expired) +{ + UNUSED(hrtimer); + UNUSED(expired); + +#ifdef CONFIG_SCHED_TICKLESS + nxsched_timer_expiration(); +#else + nxsched_process_tick(); + return NSEC_PER_TICK; +#endif +} + +/**************************************************************************** + * Name: nxsched_process_hrtimer + * + * Description: + * Entry point for scheduler-related high-resolution timer processing. + * + * Responsibilities: + * - Process expired hrtimer events + * - Perform one-time initialization of the scheduler hrtimer + * - Arm the initial scheduler timer event + * + * This function is expected to be called from architecture-specific + * timer interrupt handling code. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void nxsched_process_hrtimer(void) +{ + uint64_t now = hrtimer_gettime(); + + /* Process any expired high-resolution timers */ + + hrtimer_process(now); +} +#endif /* CONFIG_HRTIMER */ + +#ifndef CONFIG_SCHED_TICKLESS + /**************************************************************************** * Name: nxsched_cpu_scheduler * @@ -145,19 +242,7 @@ static inline void nxsched_process_scheduler(void) #endif /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * System Timer Hooks - * - * These are standard interfaces that are exported by the OS - * for use by the architecture specific logic - * - ****************************************************************************/ - -/**************************************************************************** - * Name: nxsched_process_timer + * Name: nxsched_process_tick * * Description: * This function handles system timer events. @@ -174,7 +259,7 @@ static inline void nxsched_process_scheduler(void) * ****************************************************************************/ -void nxsched_process_timer(void) +static void nxsched_process_tick(void) { #ifdef CONFIG_CLOCK_TIMEKEEPING /* Process wall time */ @@ -204,3 +289,77 @@ void nxsched_process_timer(void) board_timerhook(); #endif } +#endif + +#ifdef CONFIG_HRTIMER + +/**************************************************************************** + * Name: nxsched_hrtimer_init + * + * Description: + * Initialize the scheduler high-resolution timer (hrtimer) instance + * and arm the first scheduler timer event. + * + * Returned Value: + * Zero on success, or a negative errno value on failure. + * + ****************************************************************************/ + +int nxsched_hrtimer_init(void) +{ + /* Initialize the scheduler hrtimer instance */ + + hrtimer_init(&g_nxsched_hrtimer, nxsched_hrtimer_callback); + + /* Start the first scheduler timer event with one tick interval */ + + return hrtimer_start(&g_nxsched_hrtimer, NSEC_PER_TICK, HRTIMER_MODE_REL); +} + +/**************************************************************************** + * Name: nxsched_hrtimer_start + * + * Description: + * Start or re-arm the scheduler high-resolution timer. + * + * Input Parameters: + * ticks - Absolute expiration time + * + * Returned Value: + * Zero on success, or a negative errno value on failure. + * + ****************************************************************************/ + +int nxsched_hrtimer_start(clock_t ticks) +{ + return hrtimer_start(&g_nxsched_hrtimer, ticks, HRTIMER_MODE_ABS); +} +#endif + +/**************************************************************************** + * System Timer Hooks + * + * These are standard interfaces that are exported by the OS + * for use by the architecture specific logic + * + ****************************************************************************/ + +void nxsched_process_timer(void) +{ +#if defined(CONFIG_HRTIMER) + /* High-resolution timer-based scheduling */ + + nxsched_process_hrtimer(); + +#elif defined(CONFIG_SCHED_TICKLESS) + /* Legacy tickless scheduling */ + + nxsched_timer_expiration(); + +#else + /* Legacy periodic tick-based scheduling */ + + nxsched_process_tick(); + +#endif +} diff --git a/sched/sched/sched_timerexpiration.c b/sched/sched/sched_timerexpiration.c index cd3201e8cca0c..d7b120898c82e 100644 --- a/sched/sched/sched_timerexpiration.c +++ b/sched/sched/sched_timerexpiration.c @@ -433,7 +433,11 @@ static clock_t nxsched_timer_start(clock_t ticks, clock_t interval) if (interval != CLOCK_MAX) { interval = adjust_next_interval(interval); +#ifdef CONFIG_HRTIMER + nxsched_hrtimer_start(ticks + interval); +#else nxsched_timer_tick_start(ticks, interval); +#endif } atomic_set(&g_timer_interval, interval);