This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit c69cf36b7c5a7a0f0a3d7419cb2246f91fe1dc84
Author: ouyangxiangzhen <[email protected]>
AuthorDate: Thu Jan 8 11:09:30 2026 +0800

    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 <[email protected]>
---
 sched/sched/sched_timerexpiration.c | 157 ++++++------------------------------
 sched/wdog/wd_cancel.c              |  11 ++-
 sched/wdog/wd_initialize.c          |   4 +
 sched/wdog/wd_start.c               |  60 ++++----------
 sched/wdog/wdog.h                   |  64 ++++++++++++++-
 5 files changed, 113 insertions(+), 183 deletions(-)

diff --git a/sched/sched/sched_timerexpiration.c 
b/sched/sched/sched_timerexpiration.c
index cd3201e8cca..ea25b6e7c16 100644
--- a/sched/sched/sched_timerexpiration.c
+++ b/sched/sched/sched_timerexpiration.c
@@ -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);
 }
 
 /****************************************************************************
diff --git a/sched/wdog/wd_cancel.c b/sched/wdog/wd_cancel.c
index fafd9aa1a53..30fe9130b5c 100644
--- a/sched/wdog/wd_cancel.c
+++ b/sched/wdog/wd_cancel.c
@@ -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;
diff --git a/sched/wdog/wd_initialize.c b/sched/wdog/wd_initialize.c
index 563ad31c9d9..c2d18193ac3 100644
--- a/sched/wdog/wd_initialize.c
+++ b/sched/wdog/wd_initialize.c
@@ -41,6 +41,10 @@
 
 struct list_node g_wdactivelist = LIST_INITIAL_VALUE(g_wdactivelist);
 
+#ifdef CONFIG_SCHED_TICKLESS
+bool g_wdtimernested;
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
diff --git a/sched/wdog/wd_start.c b/sched/wdog/wd_start.c
index 0e5ce456085..f261125f8c9 100644
--- a/sched/wdog/wd_start.c
+++ b/sched/wdog/wd_start.c
@@ -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 */
diff --git a/sched/wdog/wdog.h b/sched/wdog/wdog.h
index 3993a6eb0e4..efcb61bc23a 100644
--- a/sched/wdog/wdog.h
+++ b/sched/wdog/wdog.h
@@ -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

Reply via email to