mirror of
https://github.com/apache/nuttx.git
synced 2026-05-22 05:42:05 +08:00
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:
committed by
Xiang Xiao
parent
7b47b9de17
commit
c69cf36b7c
@@ -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);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user