mirror of
https://github.com/apache/nuttx.git
synced 2026-05-20 04:16:35 +08:00
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:
committed by
Donny(董九柱)
parent
5bab9fcc7f
commit
3eedf5f22b
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user