From 9116ed92478b27fea6b9dc7aa7e35cdcad543244 Mon Sep 17 00:00:00 2001 From: ligd Date: Wed, 25 Aug 2021 13:52:20 +0800 Subject: [PATCH] sched/wdog: fix switch_context caused error in wd_start() Thead A: Thread B: wd_start(wdogX) wd_cancel nxsched_cancel_timer --> wd_start(wdogX) wd_cancel add wdogX to g_wdactivelist <-- add wdogX to g_wdactivelist then, you will find wdogX add twice. Change-Id: Icbf3b2badff20908e115c9134e2400cdcb32b1e0 Signed-off-by: ligd --- sched/sched/sched_timerexpiration.c | 2 +- sched/wdog/wd_start.c | 19 +++++++++++-------- sched/wdog/wdog.h | 3 ++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sched/sched/sched_timerexpiration.c b/sched/sched/sched_timerexpiration.c index 9b43c54e31..ce3348f6ca 100644 --- a/sched/sched/sched_timerexpiration.c +++ b/sched/sched/sched_timerexpiration.c @@ -344,7 +344,7 @@ static unsigned int nxsched_timer_process(unsigned int ticks, /* Process watchdogs */ - tmp = wd_timer(ticks); + tmp = wd_timer(ticks, noswitches); if (tmp > 0) { cmptime = tmp; diff --git a/sched/wdog/wd_start.c b/sched/wdog/wd_start.c index d285fc72ec..d7e2a27881 100644 --- a/sched/wdog/wd_start.c +++ b/sched/wdog/wd_start.c @@ -351,6 +351,7 @@ int wd_start(FAR struct wdog_s *wdog, int32_t delay, * 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 @@ -363,7 +364,7 @@ int wd_start(FAR struct wdog_s *wdog, int32_t delay, ****************************************************************************/ #ifdef CONFIG_SCHED_TICKLESS -unsigned int wd_timer(int ticks) +unsigned int wd_timer(int ticks, bool noswitches) { FAR struct wdog_s *wdog; #ifdef CONFIG_SMP @@ -387,12 +388,9 @@ unsigned int wd_timer(int ticks) /* Check if there are any active watchdogs to process */ - while (g_wdactivelist.head != NULL && ticks > 0) + wdog = (FAR struct wdog_s *)g_wdactivelist.head; + while (wdog != NULL && ticks > 0) { - /* Get the watchdog at the head of the list */ - - wdog = (FAR struct wdog_s *)g_wdactivelist.head; - #ifndef CONFIG_SCHED_TICKLESS_ALARM /* There is logic to handle the case where ticks is greater than * the watchdog lag, but if the scheduling is working properly @@ -411,8 +409,13 @@ unsigned int wd_timer(int ticks) ticks -= decr; g_wdtickbase += decr; - /* Check if the watchdog at the head of the list is ready to run */ + wdog = wdog->next; + } + /* Check if the watchdog at the head of the list is ready to run */ + + if (!noswitches) + { wd_expiration(); } @@ -423,7 +426,7 @@ unsigned int wd_timer(int ticks) /* Return the delay for the next watchdog to expire */ ret = g_wdactivelist.head ? - ((FAR struct wdog_s *)g_wdactivelist.head)->lag : 0; + MAX(((FAR struct wdog_s *)g_wdactivelist.head)->lag, 1) : 0; #ifdef CONFIG_SMP leave_critical_section(flags); diff --git a/sched/wdog/wdog.h b/sched/wdog/wdog.h index 24b75c76f9..c5279769d2 100644 --- a/sched/wdog/wdog.h +++ b/sched/wdog/wdog.h @@ -121,6 +121,7 @@ void weak_function wd_initialize(void); * 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 @@ -133,7 +134,7 @@ void weak_function wd_initialize(void); ****************************************************************************/ #ifdef CONFIG_SCHED_TICKLESS -unsigned int wd_timer(int ticks); +unsigned int wd_timer(int ticks, bool noswitches); #else void wd_timer(void); #endif