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 8e653753655a91829190c524e49aac3766336dc6
Author: ouyangxiangzhen <ouyangxiangz...@xiaomi.com>
AuthorDate: Fri Mar 28 17:15:34 2025 +0800

    sched: Remove unnecessary tick++ for absolute wdog timer.
    
    To improve the absolute timer accuracy, this commit move the tick++ to 
relative wdog timer.
    
    Signed-off-by: ouyangxiangzhen <ouyangxiangz...@xiaomi.com>
---
 sched/signal/sig_timedwait.c | 10 +++++++++-
 sched/timer/timer_settime.c  | 11 ++++++++++-
 sched/wdog/wd_start.c        | 40 ++++++++++++++++++----------------------
 3 files changed, 37 insertions(+), 24 deletions(-)

diff --git a/sched/signal/sig_timedwait.c b/sched/signal/sig_timedwait.c
index 219de4ee13..22cd6bd160 100644
--- a/sched/signal/sig_timedwait.c
+++ b/sched/signal/sig_timedwait.c
@@ -304,7 +304,15 @@ int nxsig_clockwait(int clockid, int flags,
 
       if ((flags & TIMER_ABSTIME) == 0)
         {
-          expect = clock_systime_ticks() + clock_time2ticks(rqtp);
+          /* delay+1 is to prevent the insufficient sleep time if we are
+           * currently near the boundary to the next tick.
+           * | current_tick | current_tick + 1 | current_tick + 2 | .... |
+           * |           ^ Here we get the current tick
+           * In this case we delay 1 tick, timer will be triggered at
+           * current_tick + 1, which is not enough for at least 1 tick.
+           */
+
+          expect = clock_systime_ticks() + clock_time2ticks(rqtp) + 1;
           wd_start_abstick(&rtcb->waitdog, expect,
                            nxsig_timeout, (uintptr_t)rtcb);
         }
diff --git a/sched/timer/timer_settime.c b/sched/timer/timer_settime.c
index 47e882ba21..9bc9578cb0 100644
--- a/sched/timer/timer_settime.c
+++ b/sched/timer/timer_settime.c
@@ -328,7 +328,16 @@ int timer_settime(timer_t timerid, int flags,
        */
 
       delay = clock_time2ticks(&value->it_value);
-      timer->pt_expected = clock_systime_ticks() + delay;
+
+      /* delay+1 is to prevent the insufficient sleep time if we are
+       * currently near the boundary to the next tick.
+       * | current_tick | current_tick + 1 | current_tick + 2 | .... |
+       * |           ^ Here we get the current tick
+       * In this case we delay 1 tick, timer will be triggered at
+       * current_tick + 1, which is not enough for at least 1 tick.
+       */
+
+      timer->pt_expected = clock_systime_ticks() + delay + 1;
     }
 
   /* Then start the watchdog */
diff --git a/sched/wdog/wd_start.c b/sched/wdog/wd_start.c
index 3d84dd2d3e..4741ac0a41 100644
--- a/sched/wdog/wd_start.c
+++ b/sched/wdog/wd_start.c
@@ -119,14 +119,10 @@ static void wdentry_period(wdparm_t arg)
 
   wdperiod->func(wdperiod->wdog.arg);
 
-  /* Since we set `ticks++` at `wd_start_abstick`,
-   * we need to use `expired - 1` here to avoid time drift.
-   */
-
   if (wdperiod->period != 0)
     {
       wd_start_abstick(&wdperiod->wdog,
-                       wdperiod->wdog.expired + wdperiod->period - 1,
+                       wdperiod->wdog.expired + wdperiod->period,
                        wdentry_period, wdperiod->wdog.arg);
     }
 }
@@ -323,23 +319,6 @@ int wd_start_abstick(FAR struct wdog_s *wdog, clock_t 
ticks,
       return -EINVAL;
     }
 
-  /* Calculate ticks+1, forcing the delay into a range that we can handle.
-   *
-   * NOTE that one is added to the delay.  This is correct and must not be
-   * changed:  The contract for the use wdog_start is that the wdog will
-   * delay FOR AT LEAST as long as requested, but may delay longer due to
-   * variety of factors.  The wdog logic has no knowledge of the the phase
-   * of the system timer when it is started:  The next timer interrupt may
-   * occur immediately or may be delayed for almost a full cycle. In order
-   * to meet the contract requirement, the requested time is also always
-   * incremented by one so that the delay is always at least as long as
-   * requested.
-   *
-   * There is extensive documentation about this time issue elsewhere.
-   */
-
-  ticks++;
-
   /* NOTE:  There is a race condition here... the caller may receive
    * the watchdog between the time that wd_start_abstick is called and
    * the critical section is established.
@@ -437,6 +416,23 @@ int wd_start(FAR struct wdog_s *wdog, sclock_t delay,
       return -EINVAL;
     }
 
+  /* Calculate delay+1, forcing the delay into a range that we can handle.
+   *
+   * NOTE that one is added to the delay.  This is correct and must not be
+   * changed:  The contract for the use wdog_start is that the wdog will
+   * delay FOR AT LEAST as long as requested, but may delay longer due to
+   * variety of factors.  The wdog logic has no knowledge of the the phase
+   * of the system timer when it is started:  The next timer interrupt may
+   * occur immediately or may be delayed for almost a full cycle. In order
+   * to meet the contract requirement, the requested time is also always
+   * incremented by one so that the delay is always at least as long as
+   * requested.
+   *
+   * There is extensive documentation about this time issue elsewhere.
+   */
+
+  delay++;
+
   return wd_start_abstick(wdog, clock_systime_ticks() + delay,
                           wdentry, arg);
 }

Reply via email to