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

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

commit 580c599bd507ebca1f45d3eca1d451dfd99529b4
Author: ouyangxiangzhen <[email protected]>
AuthorDate: Thu Apr 9 14:46:58 2026 +0800

    sched/hrtimer: Fix overflow in hrtimer_reprogram
    
    Fix overflow issues in hrtimer_reprogram():
    
    - Add HRTIMER_GUARD_DELAY = INT64_MAX - (1 << 48) ns.  The headroom
      below INT64_MAX accommodates inter-core clock drift in SMP builds
      when each CPU independently updates the shared g_hrtimer_guard.
    - Set HRTIMER_MAX_DELAY to (INT64_MAX >> 1) + 1u so the maximum delay
      fits while leaving room for the guard.
    - Add hrtimer_last_expired() returning g_hrtimer_guard.expired minus
      HRTIMER_GUARD_DELAY, and compute the reprogram delay from it with
      HRTIMER_TIME_BEFORE_EQ, clamping to TICK2NSEC(g_oneshot_maxticks)
      under CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP.
    - Fix the ALARM_ARCH escape used in hrtimer_reprogram() to
      CONFIG_SCHED_TICKLESS_ALARM.
    
    Assisted-By: mimo-v2.6-pro
    Signed-off-by: ouyangxiangzhen <[email protected]>
---
 include/nuttx/hrtimer.h            | 17 ++++++++++++++---
 sched/hrtimer/hrtimer.h            | 38 ++++++++++++++++++++++++++++++++++----
 sched/hrtimer/hrtimer_gettime.c    |  3 +--
 sched/hrtimer/hrtimer_initialize.c |  2 +-
 sched/hrtimer/hrtimer_process.c    |  4 ++++
 5 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/include/nuttx/hrtimer.h b/include/nuttx/hrtimer.h
index 701a4ee8f54..94cd6f7595f 100644
--- a/include/nuttx/hrtimer.h
+++ b/include/nuttx/hrtimer.h
@@ -41,11 +41,22 @@
 
 /* The maximum delay tick should be INT64_MAX. However, if there are expired
  * hrtimer in the queue, HRTIMER_TIME_BEFORE/AFTER might be incorrect, so we
- * limited the delay to INT64_MAX >> 1, assuming all expired hrtimer can be
- * processed within HRTIMER_MAX_DELAY.
+ * limited the delay to (INT64_MAX >> 1) + 1u, assuming all expired hrtimer
+ * can be processed within HRTIMER_MAX_DELAY - 1u.
+ *
+ * g_hrtimer_guard.expired is set to now + HRTIMER_GUARD_DELAY in the
+ * hrtimer_process. The guard delay is intentionally set to
+ * INT64_MAX - (1ull << 48) rather than INT64_MAX for the following reason:
+ * In SMP configurations, each CPU core independently updates shared
+ * g_hrtimer_guard.expired. Due to interrupt and lock latency, the current
+ * time across cores are not perfectly synchronized and may exhibit small
+ * forward/backward drift.
+ * The (1ull << 48) headroom (~0.3 days in nanoseconds) accommodates
+ * this inter-core time desynchronization.
  */
 
-#define HRTIMER_MAX_DELAY              (INT64_MAX >> 1)
+#define HRTIMER_GUARD_DELAY ((uint64_t)INT64_MAX - (1ull << 48))
+#define HRTIMER_MAX_DELAY   (((uint64_t)INT64_MAX >> 1) + 1u)
 
 /****************************************************************************
  * Public Types
diff --git a/sched/hrtimer/hrtimer.h b/sched/hrtimer/hrtimer.h
index 752f64465f5..52466a548d9 100644
--- a/sched/hrtimer/hrtimer.h
+++ b/sched/hrtimer/hrtimer.h
@@ -81,11 +81,12 @@ RB_HEAD(hrtimer_tree_s, hrtimer_s);
 
 extern seqcount_t g_hrtimer_lock;
 
+extern struct hrtimer_s g_hrtimer_guard;
+
 #ifdef CONFIG_HRTIMER_TREE
 /* Red-Black tree containing all active high-resolution timers */
 
 extern struct hrtimer_tree_s g_hrtimer_tree;
-extern struct hrtimer_s      g_hrtimer_guard;
 extern struct FAR hrtimer_s *g_hrtimer_head;
 #else
 /* List containing all active high-resolution timers */
@@ -127,6 +128,25 @@ void hrtimer_process(uint64_t now);
  * Inline Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: hrtimer_last_expired
+ *
+ * Description:
+ *   Return the last expired time of the hrtimer.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   The last expired time in nanoseconds.
+ *
+ ****************************************************************************/
+
+static inline_function uint64_t hrtimer_last_expired(void)
+{
+  return g_hrtimer_guard.expired - HRTIMER_GUARD_DELAY;
+}
+
 /****************************************************************************
  * Name: hrtimer_reprogram
  *
@@ -154,12 +174,22 @@ static inline_function void hrtimer_reprogram(uint64_t 
next_expired)
    */
 
 #ifdef CONFIG_SCHED_TICKLESS
-  int ret = 0;
+  int             ret;
   struct timespec ts;
+  uint64_t        delay;
+  uint64_t        expired = hrtimer_last_expired();
+
+  delay = HRTIMER_TIME_BEFORE_EQ(expired, next_expired) ?
+          next_expired - expired : 0u;
+
+#  ifdef CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP
+  delay = delay < TICK2NSEC((uint64_t)g_oneshot_maxticks) ?
+          delay : TICK2NSEC((uint64_t)g_oneshot_maxticks);
+#  endif
 
-  clock_nsec2time(&ts, next_expired);
+  clock_nsec2time(&ts, expired + delay);
 
-#  ifdef CONFIG_ALARM_ARCH
+#  ifdef CONFIG_SCHED_TICKLESS_ALARM
   ret = up_alarm_start(&ts);
 #  else
   struct timespec current;
diff --git a/sched/hrtimer/hrtimer_gettime.c b/sched/hrtimer/hrtimer_gettime.c
index 9d2b5aa3a27..17376a58dfb 100644
--- a/sched/hrtimer/hrtimer_gettime.c
+++ b/sched/hrtimer/hrtimer_gettime.c
@@ -51,8 +51,7 @@
 
 uint64_t hrtimer_gettime(FAR hrtimer_t *timer)
 {
-  uint64_t expire = hrtimer_read_64(&timer->expired);
-  int64_t  remain = expire - clock_systime_nsec();
+  int64_t remain = hrtimer_read_64(&timer->expired) - clock_systime_nsec();
 
   return remain < 0 ? 0u : remain;
 }
diff --git a/sched/hrtimer/hrtimer_initialize.c 
b/sched/hrtimer/hrtimer_initialize.c
index 77f9af5bce2..f5cbba6c4a5 100644
--- a/sched/hrtimer/hrtimer_initialize.c
+++ b/sched/hrtimer/hrtimer_initialize.c
@@ -66,7 +66,7 @@ struct hrtimer_s g_hrtimer_guard =
   { &g_hrtimer_list, &g_hrtimer_list },
 #endif
   NULL,
-  INT64_MAX
+  HRTIMER_GUARD_DELAY
 };
 
 #ifdef CONFIG_HRTIMER_TREE
diff --git a/sched/hrtimer/hrtimer_process.c b/sched/hrtimer/hrtimer_process.c
index 8974964a57c..6d295be8ea2 100644
--- a/sched/hrtimer/hrtimer_process.c
+++ b/sched/hrtimer/hrtimer_process.c
@@ -134,6 +134,10 @@ void hrtimer_process(uint64_t now)
 
   hrtimer_unmark_running(cpu);
 
+  /* Note that the g_hrtimer_guard.expired is not monotonic. */
+
+  g_hrtimer_guard.expired = now + HRTIMER_GUARD_DELAY;
+
   /* Schedule the next timer expiration */
 
   if (expired != now)

Reply via email to