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 <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
ouyangxiangzhen
2026-01-08 11:09:30 +08:00
committed by Xiang Xiao
parent 7b47b9de17
commit c69cf36b7c
5 changed files with 113 additions and 183 deletions
+26 -131
View File
@@ -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);
}
/****************************************************************************
+9 -2
View File
@@ -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;
+4
View File
@@ -41,6 +41,10 @@
struct list_node g_wdactivelist = LIST_INITIAL_VALUE(g_wdactivelist);
#ifdef CONFIG_SCHED_TICKLESS
bool g_wdtimernested;
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
+14 -46
View File
@@ -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 */
+60 -4
View File
@@ -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