mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 01:21:26 +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
|
#endif
|
||||||
static clock_t nxsched_process_scheduler(clock_t ticks, clock_t elapsed,
|
static clock_t nxsched_process_scheduler(clock_t ticks, clock_t elapsed,
|
||||||
bool noswitches);
|
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);
|
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;
|
static atomic_t g_timer_interval;
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_TICKLESS
|
/* Wdog timer for scheduler event. */
|
||||||
static unsigned int g_timernested;
|
|
||||||
#endif
|
static struct wdog_s g_sched_event;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
@@ -134,7 +132,7 @@ static inline_function clock_t adjust_next_interval(clock_t interval)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline_function clock_t get_time_tick(void)
|
static inline_function clock_t get_time_tick(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SYSTEM_TIME64
|
#ifdef CONFIG_SYSTEM_TIME64
|
||||||
return atomic64_read((FAR atomic64_t *)&g_timer_tick);
|
return atomic64_read((FAR atomic64_t *)&g_timer_tick);
|
||||||
@@ -164,58 +162,25 @@ int up_timer_gettick(FAR clock_t *ticks)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_TICKLESS_ALARM
|
static void nxsched_process_event(wdparm_t noswitches)
|
||||||
static inline_function
|
|
||||||
int nxsched_timer_tick_start(clock_t ticks, clock_t delay)
|
|
||||||
{
|
{
|
||||||
# ifndef CONFIG_ALARM_ARCH
|
clock_t ticks;
|
||||||
struct timespec ts;
|
clock_t next;
|
||||||
clock_ticks2time(&ts, ticks + delay);
|
clock_t elapsed;
|
||||||
return up_alarm_start(&ts);
|
|
||||||
# else
|
|
||||||
return up_alarm_tick_start(ticks + delay);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline_function
|
/* Get the current time. */
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
up_timer_gettick(&ticks);
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline_function
|
/* Calculate the elapsed time and update clock tickbase. */
|
||||||
int nxsched_timer_tick_cancel(clock_t *ticks)
|
|
||||||
{
|
elapsed = ticks - update_time_tick(ticks);
|
||||||
# ifndef CONFIG_TIMER_ARCH
|
|
||||||
struct timespec ts;
|
/* Process the timer ticks and set up the next interval (or not) */
|
||||||
up_timer_cancel(&ts);
|
|
||||||
# else
|
next = nxsched_process_scheduler(ticks, elapsed, (bool)noswitches);
|
||||||
up_timer_cancel(ticks);
|
nxsched_timer_start(ticks, next);
|
||||||
# endif
|
|
||||||
return up_timer_gettick(ticks);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: nxsched_cpu_scheduler
|
* Name: nxsched_cpu_scheduler
|
||||||
@@ -370,49 +335,6 @@ clock_t nxsched_process_scheduler(clock_t ticks, clock_t elapsed,
|
|||||||
return minslice;
|
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
|
* Name: nxsched_timer_start
|
||||||
*
|
*
|
||||||
@@ -433,27 +355,18 @@ static clock_t nxsched_timer_start(clock_t ticks, clock_t interval)
|
|||||||
if (interval != CLOCK_MAX)
|
if (interval != CLOCK_MAX)
|
||||||
{
|
{
|
||||||
interval = adjust_next_interval(interval);
|
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);
|
atomic_set(&g_timer_interval, interval);
|
||||||
return 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
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -478,20 +391,12 @@ void nxsched_timer_expiration(void)
|
|||||||
{
|
{
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
clock_t ticks;
|
clock_t ticks;
|
||||||
clock_t next;
|
|
||||||
|
|
||||||
up_timer_gettick(&ticks);
|
up_timer_gettick(&ticks);
|
||||||
|
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
|
|
||||||
/* Get the interval associated with last expiration */
|
wd_timer(ticks);
|
||||||
|
|
||||||
g_timernested++;
|
|
||||||
|
|
||||||
next = nxsched_timer_update(ticks, false);
|
|
||||||
nxsched_timer_start(ticks, next);
|
|
||||||
|
|
||||||
g_timernested--;
|
|
||||||
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
}
|
}
|
||||||
@@ -535,17 +440,7 @@ void nxsched_timer_expiration(void)
|
|||||||
|
|
||||||
void nxsched_reassess_timer(void)
|
void nxsched_reassess_timer(void)
|
||||||
{
|
{
|
||||||
clock_t ticks;
|
nxsched_process_event(1u);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|||||||
@@ -86,14 +86,21 @@ int wd_cancel(FAR struct wdog_s *wdog)
|
|||||||
|
|
||||||
wdog->func = NULL;
|
wdog->func = NULL;
|
||||||
|
|
||||||
if (first == wdog)
|
if (first == wdog && !wd_in_callback())
|
||||||
{
|
{
|
||||||
/* If the watchdog is at the head of the timer queue, then
|
/* If the watchdog is at the head of the timer queue, then
|
||||||
* we will need to re-adjust the interval timer that will
|
* we will need to re-adjust the interval timer that will
|
||||||
* generate the next interval event.
|
* 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;
|
ret = OK;
|
||||||
|
|||||||
@@ -41,6 +41,10 @@
|
|||||||
|
|
||||||
struct list_node g_wdactivelist = LIST_INITIAL_VALUE(g_wdactivelist);
|
struct list_node g_wdactivelist = LIST_INITIAL_VALUE(g_wdactivelist);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_TICKLESS
|
||||||
|
bool g_wdtimernested;
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* 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;
|
FAR struct wdog_s *wdog;
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
wdentry_t func;
|
wdentry_t func;
|
||||||
wdparm_t arg;
|
wdparm_t arg;
|
||||||
clock_t ret = CLOCK_MAX;
|
clock_t next_ticks = ticks;
|
||||||
|
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
|
|
||||||
|
wd_set_nested(true);
|
||||||
|
|
||||||
/* Process the watchdog at the head of the list as well as any
|
/* Process the watchdog at the head of the list as well as any
|
||||||
* other watchdogs that became ready to run at this time
|
* 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))
|
if (!clock_compare(wdog->expired, ticks))
|
||||||
{
|
{
|
||||||
ret = wdog->expired - ticks;
|
next_ticks = wdog->expired;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,9 +150,14 @@ static inline_function clock_t wd_expiration(clock_t ticks)
|
|||||||
CALL_FUNC(func, arg);
|
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_insert(wdog, ticks, wdentry, arg);
|
||||||
|
reassess &= !wd_in_callback();
|
||||||
|
|
||||||
if (reassess)
|
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.
|
* changed, then this will pick that new delay.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
nxsched_reassess_timer();
|
wd_timer_start(wd_next_expire());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
UNUSED(reassess);
|
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,
|
* in the interval that just expired is provided. Otherwise,
|
||||||
* this function is called on each timer interrupt and a value of one
|
* this function is called on each timer interrupt and a value of one
|
||||||
* is implicit.
|
* is implicit.
|
||||||
* noswitches - True: Can't do context switches now.
|
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* If CONFIG_SCHED_TICKLESS is defined then the number of ticks for the
|
* 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)
|
void wd_timer(clock_t ticks)
|
||||||
{
|
{
|
||||||
/* Check if there are any active watchdogs to process */
|
/* Check if there are any active watchdogs to process */
|
||||||
|
|
||||||
wd_expiration(ticks);
|
wd_expiration(ticks);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SCHED_TICKLESS */
|
|
||||||
|
|||||||
+60
-4
@@ -36,6 +36,7 @@
|
|||||||
#include <nuttx/clock.h>
|
#include <nuttx/clock.h>
|
||||||
#include <nuttx/queue.h>
|
#include <nuttx/queue.h>
|
||||||
#include <nuttx/wdog.h>
|
#include <nuttx/wdog.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
@@ -60,6 +61,65 @@ extern "C"
|
|||||||
|
|
||||||
extern struct list_node g_wdactivelist;
|
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
|
* 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);
|
void wd_timer(clock_t ticks);
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
Reference in New Issue
Block a user