You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by li...@apache.org on 2026/01/26 08:37:16 UTC
(nuttx) branch master updated (78d05ff811c -> 281f9fc0c0f)
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
from 78d05ff811c arm64: remove busy wait flag
new 47ce6590b77 sched/hrtimer: Fixed hrtimer_starttimer.
new d18fd4640e0 sched/hrtimer: Fix functional correctness issue in SMP.
new b2fadb8529e sched/hrtimer: Fix functional correctness issue in synchronization.
new 65bc3db6243 sched/hrtimer: Add hrtimer_wait to simplify the wait.
new 89dbed25a0d sched/hrtimer: Replace hrtimer_gettime with clock_systime_nsec.
new 4d283260abd sched/hrtimer: Add hrtimer_gettime.
new a6d64a1a83d sched/hrtimer: Simplify the hrtimer_cancel.
new 0048a5c21bb sched/hrtimer: Fix the functional correctness issue in hrtimer_start.
new fdf3eb0d560 sched/hrtimer: Update the documentation.
new f1b355f118a sched/hrtimer: Update the comments.
new 281f9fc0c0f sched/hrtimer: Rename the HRTIMER_CANCEL_SYNC_DELAY timeout.
The 11 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../reference/os/hrtimer_state_machine.png | Bin 357712 -> 0 bytes
Documentation/reference/os/time_clock.rst | 165 ++++++++++--
include/nuttx/clock.h | 22 ++
include/nuttx/hrtimer.h | 70 +++--
sched/hrtimer/CMakeLists.txt | 10 +-
sched/hrtimer/Make.defs | 1 +
sched/hrtimer/hrtimer.h | 298 ++++++++++++++++++---
sched/hrtimer/hrtimer_cancel.c | 127 +++------
.../hrtimer/hrtimer_gettime.c | 36 +--
sched/hrtimer/hrtimer_initialize.c | 6 +-
sched/hrtimer/hrtimer_process.c | 39 ++-
sched/hrtimer/hrtimer_start.c | 45 ++--
sched/sched/sched_timer.c | 2 +-
13 files changed, 582 insertions(+), 239 deletions(-)
delete mode 100644 Documentation/reference/os/hrtimer_state_machine.png
copy libs/libc/pthread/pthread_condattr_destroy.c => sched/hrtimer/hrtimer_gettime.c (72%)
(nuttx) 02/11: sched/hrtimer: Fix functional correctness issue in SMP.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit d18fd4640e05ce42c90f409eaa4438d167a76f45
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Thu Jan 15 10:58:21 2026 +0800
sched/hrtimer: Fix functional correctness issue in SMP.
Since the hrtimer->expired is not monotonic, it can not be used as the
version. This commit added the ownership encoding to ensure the
invariant that the cancelled the timer can not modify the hrtimer again.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
include/nuttx/hrtimer.h | 39 +++++++------
sched/hrtimer/hrtimer.h | 112 ++++++++++++++++++++++++++++++++++++-
sched/hrtimer/hrtimer_cancel.c | 74 +++++++++++++-----------
sched/hrtimer/hrtimer_initialize.c | 2 +-
sched/hrtimer/hrtimer_process.c | 17 ++----
sched/hrtimer/hrtimer_start.c | 4 ++
6 files changed, 185 insertions(+), 63 deletions(-)
diff --git a/include/nuttx/hrtimer.h b/include/nuttx/hrtimer.h
index e77041f1105..16db12805d1 100644
--- a/include/nuttx/hrtimer.h
+++ b/include/nuttx/hrtimer.h
@@ -125,23 +125,31 @@ extern "C"
* Name: hrtimer_cancel
*
* Description:
- * Cancel a high-resolution timer.
- *
- * If the timer is armed but has not yet expired, it will be removed from
- * the timer queue and the callback will not be invoked.
- *
- * If the timer callback is currently executing, this function will mark
- * the timer as canceled and return immediately. The running callback is
- * allowed to complete, but it will not be invoked again.
+ * Cancel a high-resolution timer asynchronously. This function set the
+ * timer to the cancelled state. The caller will acquire the limited
+ * ownership of the hrtimer, which allow the caller restart the hrtimer,
+ * but the callback function may still be executing on another CPU, which
+ * prevent the caller from freeing the hrtimer. The caller must call
+ * `hrtimer_cancel` to wait for the callback to be finished. Please use
+ * the function with care. Concurrency errors are prone to occur in this
+ * use case.
*
* This function is non-blocking and does not wait for a running callback
* to finish.
*
* Input Parameters:
- * hrtimer - Timer instance to cancel
+ * hrtimer - Pointer to the high-resolution timer instance to cancel.
*
* Returned Value:
- * OK on success; a negated errno value on failure.
+ * OK (0) on success; a negated errno value on failure.
+ * > 0 on if the timer callback is running.
+ *
+ * Assumptions/Notes:
+ * - This function acquires the global hrtimer spinlock to protect both
+ * the red-black tree and the timer state.
+ * - The caller must ensure that the timer structure is not freed until
+ * it is guaranteed that any running callback has returned.
+ *
****************************************************************************/
int hrtimer_cancel(FAR hrtimer_t *hrtimer);
@@ -152,12 +160,11 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer);
* Description:
* Cancel a high-resolution timer and wait until it becomes inactive.
*
- * - Calls hrtimer_cancel() to request timer cancellation.
- * - If the timer callback is running, waits until it completes and
- * the timer state transitions to HRTIMER_STATE_INACTIVE.
- * - If sleeping is allowed (normal task context), yields CPU briefly
- * to avoid busy-waiting.
- * - Otherwise (interrupt or idle task context), spins until completion.
+ * Cancel a high-resolution timer and synchronously wait the callback to
+ * be finished. This function set the timer to the cancelled state and wait
+ * for all references to be released. The caller will then acquire full
+ * ownership of the hrtimer. After the function returns, the caller can
+ * safely deallocate the hrtimer.
*
* Input Parameters:
* hrtimer - Pointer to the high-resolution timer instance to cancel.
diff --git a/sched/hrtimer/hrtimer.h b/sched/hrtimer/hrtimer.h
index fabcbcf2dd2..ff1d40a947a 100644
--- a/sched/hrtimer/hrtimer.h
+++ b/sched/hrtimer/hrtimer.h
@@ -71,7 +71,7 @@ extern struct list_node g_hrtimer_list;
*/
#ifdef CONFIG_SMP
-extern FAR hrtimer_t *g_hrtimer_running[CONFIG_SMP_NCPUS];
+extern uintptr_t g_hrtimer_running[CONFIG_SMP_NCPUS];
#endif
/****************************************************************************
@@ -310,5 +310,115 @@ static inline_function bool hrtimer_is_first(FAR hrtimer_t *hrtimer)
#endif
}
+/****************************************************************************
+ * Name: hrtimer_mark_running
+ *
+ * Description:
+ * Mark the timer as running.
+ *
+ * Input Parameters:
+ * timer - The timer to be marked.
+ * cpu - The CPU core Id.
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumption:
+ * The caller must hold the lock.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+# define hrtimer_mark_running(timer, cpu) \
+ (g_hrtimer_running[cpu] = (uintptr_t)(timer))
+#else
+# define hrtimer_mark_running(timer, cpu) UNUSED(cpu)
+#endif
+#define hrtimer_unmark_running(cpu) hrtimer_mark_running(NULL, cpu)
+
+/****************************************************************************
+ * Name: hrtimer_is_running
+ *
+ * Description:
+ * Check if the CPU core is running the timer.
+ *
+ * Input Parameters:
+ * timer - The timer to be marked.
+ * cpu - The CPU core Id.
+ *
+ * Returned Value:
+ * true if the CPU core is running the timer, false otherwise.
+ *
+ * Assumption:
+ * The caller must hold the lock.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+# define hrtimer_is_running(timer, cpu) \
+ (g_hrtimer_running[cpu] == (uintptr_t)(timer))
+#else
+# define hrtimer_is_running(timer, cpu) (true)
+#endif
+#define hrtimer_is_cancelling(timer, cpu) \
+ hrtimer_is_running((uintptr_t)(timer) | 0x1u, cpu)
+
+/****************************************************************************
+ * Name: hrtimer_cancel_running
+ *
+ * Description:
+ * Cancel the timer, revoke the ownership of the cancelled timer, and
+ * return the references count to the timer.
+ *
+ * Input Parameters:
+ * hrtimer - The cancelled timer.
+ *
+ * Returned Value:
+ * The references count to the timer.
+ *
+ * Assumption:
+ * The caller must hold the queue lock.
+ *
+ ****************************************************************************/
+
+static inline_function
+int hrtimer_cancel_running(FAR hrtimer_t *timer)
+{
+ int refs = 0;
+#ifdef CONFIG_SMP
+ uintptr_t cancelled = (uintptr_t)timer | 0x1u;
+ int cpu;
+
+ /* Check if the timer is referenced by any CPU core.
+ * Generally, only one reference to a timer can exist at the same time.
+ * However, when a timer may be restarted at the cancelled state,
+ * more references to the timer may exist.
+ */
+
+ unroll_loop(CONFIG_SMP_NCPUS) /* Tell the compiler to unroll the loop. */
+
+ for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++)
+ {
+ /* This is a faster implementation equivalent to
+ * (g_hrtimer_running[cpu] & (~(uintptr_t)0x1u)) == timer,
+ * Assuming the pointer of the timer is at least 2-bytes aligned
+ * (the last bit must be zero).
+ */
+
+ if ((g_hrtimer_running[cpu] ^ cancelled) <= 0x1u)
+ {
+ /* Set the timer to the cancelled state and revoke the write
+ * ownership of the timer from the queue.
+ */
+
+ g_hrtimer_running[cpu] = cancelled;
+ refs++;
+ }
+ }
+#endif
+
+ return refs;
+}
+
#endif /* CONFIG_HRTIMER */
#endif /* __SCHED_HRTIMER_HRTIMER_H */
diff --git a/sched/hrtimer/hrtimer_cancel.c b/sched/hrtimer/hrtimer_cancel.c
index a93f9ba437d..43a6d2f371e 100644
--- a/sched/hrtimer/hrtimer_cancel.c
+++ b/sched/hrtimer/hrtimer_cancel.c
@@ -60,11 +60,12 @@
#ifdef CONFIG_SMP
static inline_function bool hrtimer_is_active(FAR hrtimer_t *hrtimer)
{
+ int cpu;
bool is_active = false;
- for (int i = 0; i < CONFIG_SMP_NCPUS; i++)
+ for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++)
{
- if (g_hrtimer_running[i] == hrtimer)
+ if (hrtimer_is_cancelling(hrtimer, cpu))
{
is_active = true;
break;
@@ -83,16 +84,21 @@ static inline_function bool hrtimer_is_active(FAR hrtimer_t *hrtimer)
* Name: hrtimer_cancel
*
* Description:
- * Cancel a high-resolution timer.
+ * Cancel a high-resolution timer asynchronously.
*
- * If the timer is currently armed, it will be removed from the active
- * hrtimer container (tree or list) and will not be executed.
+ * If the timer is currently pending, it will be removed from the
+ * hrtimer queue and will not be executed.
*
- * If the timer callback is currently executing, the timer will be marked
- * as canceled. The running callback is allowed to complete, but the timer
- * will not be re-armed or executed again.
+ * If the timer callback is currently executing. This function set the
+ * timer to the cancelled state. The caller will acquire the limited
+ * ownership of the hrtimer, which allow the caller restart the hrtimer,
+ * but the callback function may still be executing on another CPU,
+ * which prevent the caller from freeing the hrtimer.
+ * The caller must call `hrtimer_cancel_sync` to wait for the callback
+ * to be finished. Please use the function with care.
+ * Concurrency errors are prone to occur in this use case.
*
- * If the canceled timer was the earliest (head) timer in the container,
+ * If the canceled timer was the earliest expired timer in the queue,
* the expiration of the underlying hardware timer will be updated to the
* expiration time of the next earliest timer
*
@@ -104,6 +110,7 @@ static inline_function bool hrtimer_is_active(FAR hrtimer_t *hrtimer)
*
* Returned Value:
* OK (0) on success; a negated errno value on failure.
+ * > 0 on if the timer callback is running.
*
* Assumptions/Notes:
* - This function acquires the global hrtimer spinlock to protect
@@ -117,7 +124,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
{
FAR hrtimer_t *first;
irqstate_t flags;
- int ret = OK;
+ int ret;
DEBUGASSERT(hrtimer != NULL);
@@ -125,17 +132,15 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
flags = spin_lock_irqsave(&g_hrtimer_spinlock);
+ /* Ensure no core can write the hrtimer. */
+
+ ret = hrtimer_cancel_running(hrtimer);
+
if (hrtimer_is_armed(hrtimer))
{
hrtimer_remove(hrtimer);
}
- /* If the timer was running, increment its expiration count to prevent
- * it from being re-armed by the callback.
- */
-
- hrtimer->expired++;
-
/* If the canceled timer was the earliest one, update the hardware timer */
if (hrtimer_is_first(hrtimer))
@@ -157,10 +162,13 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
* Name: hrtimer_cancel_sync
*
* Description:
- * Cancel a high-resolution timer and wait until it becomes inactive.
+ * Cancel a high-resolution timer and synchronously wait the callback to
+ * be finished.
*
- * - Calls hrtimer_cancel() to request timer cancellation.
- * - If the timer callback is running, waits until it completes.
+ * If the timer callback is running, this function set the timer to the
+ * cancelled state and wait for all all references to be released.
+ * The caller will then acquire full ownership of the hrtimer. After the
+ * function returns, the caller can safely deallocate the hrtimer.
* - If sleeping is allowed (normal task context), yields CPU briefly
* to avoid busy-waiting.
* - Otherwise (interrupt or idle task context), spins until completion.
@@ -182,26 +190,24 @@ int hrtimer_cancel_sync(FAR hrtimer_t *hrtimer)
/* Request cancellation of the timer */
ret = hrtimer_cancel(hrtimer);
- if (ret < 0)
+ if (ret > 0)
{
- return ret;
- }
-
- /* Wait until all cpu finish running the timer callback.
- *
- * If sleeping is permitted, yield the CPU briefly to avoid
- * busy-waiting. Otherwise, spin until the callback completes.
- */
+ /* Wait until the timer transitions to the inactive state.
+ *
+ * If sleeping is permitted, yield the CPU briefly to avoid
+ * busy-waiting. Otherwise, spin until the callback completes.
+ */
#ifdef CONFIG_SMP
- while (hrtimer_is_active(hrtimer))
- {
- if (!up_interrupt_context() &&
- !is_idle_task(this_task()))
+ while (hrtimer_is_active(hrtimer))
{
- nxsched_msleep(HRTIMER_CANCEL_SYNC_DELAY_MS);
+ if (!up_interrupt_context() &&
+ !is_idle_task(this_task()))
+ {
+ nxsched_msleep(HRTIMER_CANCEL_SYNC_DELAY_MS);
+ }
}
- }
#endif
+ }
return ret;
}
diff --git a/sched/hrtimer/hrtimer_initialize.c b/sched/hrtimer/hrtimer_initialize.c
index a79d52b8e26..43010f074d2 100644
--- a/sched/hrtimer/hrtimer_initialize.c
+++ b/sched/hrtimer/hrtimer_initialize.c
@@ -37,7 +37,7 @@
*/
#ifdef CONFIG_SMP
-FAR hrtimer_t *g_hrtimer_running[CONFIG_SMP_NCPUS];
+uintptr_t g_hrtimer_running[CONFIG_SMP_NCPUS];
#endif
/* Global spinlock protecting the high-resolution timer subsystem.
diff --git a/sched/hrtimer/hrtimer_process.c b/sched/hrtimer/hrtimer_process.c
index ff7f945b6d3..97266cacf8c 100644
--- a/sched/hrtimer/hrtimer_process.c
+++ b/sched/hrtimer/hrtimer_process.c
@@ -75,9 +75,7 @@ void hrtimer_process(uint64_t now)
hrtimer_entry_t func;
uint64_t expired;
uint64_t period;
-#ifdef CONFIG_SMP
int cpu = this_cpu();
-#endif
/* Lock the hrtimer container to protect access */
@@ -108,9 +106,8 @@ void hrtimer_process(uint64_t now)
hrtimer_remove(hrtimer);
-#ifdef CONFIG_SMP
- g_hrtimer_running[cpu] = hrtimer;
-#endif
+ hrtimer_mark_running(hrtimer, cpu);
+
/* Leave critical section before invoking the callback */
spin_unlock_irqrestore(&g_hrtimer_spinlock, flags);
@@ -123,22 +120,18 @@ void hrtimer_process(uint64_t now)
flags = spin_lock_irqsave(&g_hrtimer_spinlock);
-#ifdef CONFIG_SMP
- g_hrtimer_running[cpu] = NULL;
-#endif
-
/* If the timer is periodic and has not been rearmed or
* cancelled concurrently,
* compute next expiration and reinsert into container
*/
- if (period > 0 && hrtimer->expired == expired)
+ if (period != 0u && hrtimer_is_running(hrtimer, cpu))
{
hrtimer->expired += period;
/* Ensure no overflow occurs */
- DEBUGASSERT(hrtimer->expired > period);
+ DEBUGASSERT(hrtimer->expired >= period);
hrtimer->func = func;
hrtimer_insert(hrtimer);
@@ -149,6 +142,8 @@ void hrtimer_process(uint64_t now)
hrtimer = hrtimer_get_first();
}
+ hrtimer_unmark_running(cpu);
+
/* Schedule the next timer expiration */
if (hrtimer != NULL)
diff --git a/sched/hrtimer/hrtimer_start.c b/sched/hrtimer/hrtimer_start.c
index 81f688de23d..61ed886dd39 100644
--- a/sched/hrtimer/hrtimer_start.c
+++ b/sched/hrtimer/hrtimer_start.c
@@ -73,6 +73,10 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
flags = spin_lock_irqsave(&g_hrtimer_spinlock);
+ /* Ensure no core can write the hrtimer. */
+
+ hrtimer_cancel_running(hrtimer);
+
if (hrtimer_is_armed(hrtimer))
{
hrtimer_remove(hrtimer);
(nuttx) 06/11: sched/hrtimer: Add hrtimer_gettime.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 4d283260abdda098d8ac3d93e6770068f2f7faae
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Thu Jan 15 11:09:52 2026 +0800
sched/hrtimer: Add hrtimer_gettime.
This commit added hrtimer_gettime API to support the query of the
rest of the delay time of the hrtimer in nanoseconds.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
include/nuttx/hrtimer.h | 19 ++++++++++++++
sched/hrtimer/CMakeLists.txt | 10 +++++--
sched/hrtimer/Make.defs | 1 +
sched/hrtimer/hrtimer_gettime.c | 58 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 86 insertions(+), 2 deletions(-)
diff --git a/include/nuttx/hrtimer.h b/include/nuttx/hrtimer.h
index 16db12805d1..bd8b05c2c52 100644
--- a/include/nuttx/hrtimer.h
+++ b/include/nuttx/hrtimer.h
@@ -199,6 +199,25 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
uint64_t expired,
enum hrtimer_mode_e mode);
+/****************************************************************************
+ * Name: hrtimer_gettime
+ *
+ * Description:
+ * Get the rest of the delay time of the hrtimer in nanoseconds.
+ *
+ * Input Parameters:
+ * timer - The hrtimer to be queried.
+ *
+ * Returned Value
+ * The time until next expiration in nanoseconds.
+ *
+ * Assumption:
+ * The timer should not be NULL.
+ *
+ ****************************************************************************/
+
+uint64_t hrtimer_gettime(FAR hrtimer_t *timer);
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/sched/hrtimer/CMakeLists.txt b/sched/hrtimer/CMakeLists.txt
index d7b0639dc25..83328f3ce43 100644
--- a/sched/hrtimer/CMakeLists.txt
+++ b/sched/hrtimer/CMakeLists.txt
@@ -23,8 +23,14 @@
# Add hrtimer-related files to the build
set(CSRCS)
if(CONFIG_HRTIMER)
- list(APPEND CSRCS hrtimer_cancel.c hrtimer_initialize.c hrtimer_process.c
- hrtimer_start.c)
+ list(
+ APPEND
+ CSRCS
+ hrtimer_cancel.c
+ hrtimer_initialize.c
+ hrtimer_process.c
+ hrtimer_start.c
+ hrtimer_gettime.c)
endif()
target_sources(sched PRIVATE ${CSRCS})
diff --git a/sched/hrtimer/Make.defs b/sched/hrtimer/Make.defs
index 65fb6ab3161..c95a9a4dc91 100644
--- a/sched/hrtimer/Make.defs
+++ b/sched/hrtimer/Make.defs
@@ -24,6 +24,7 @@
ifeq ($(CONFIG_HRTIMER),y)
CSRCS += hrtimer_cancel.c hrtimer_initialize.c hrtimer_process.c hrtimer_start.c
+ CSRCS += hrtimer_gettime.c
endif
# Include hrtimer build support
diff --git a/sched/hrtimer/hrtimer_gettime.c b/sched/hrtimer/hrtimer_gettime.c
new file mode 100644
index 00000000000..9d2b5aa3a27
--- /dev/null
+++ b/sched/hrtimer/hrtimer_gettime.c
@@ -0,0 +1,58 @@
+/****************************************************************************
+ * sched/hrtimer/hrtimer_gettime.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "hrtimer/hrtimer.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: hrtimer_gettime
+ *
+ * Description:
+ * Get the rest of the delay time of the hrtimer in nanoseconds.
+ *
+ * Input Parameters:
+ * timer - The hrtimer to be queried.
+ *
+ * Returned Value
+ * The time until next expiration in nanoseconds.
+ *
+ * Assumption:
+ * The timer should not be NULL.
+ *
+ ****************************************************************************/
+
+uint64_t hrtimer_gettime(FAR hrtimer_t *timer)
+{
+ uint64_t expire = hrtimer_read_64(&timer->expired);
+ int64_t remain = expire - clock_systime_nsec();
+
+ return remain < 0 ? 0u : remain;
+}
(nuttx) 10/11: sched/hrtimer: Update the comments.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit f1b355f118a8ed9b5da6bd35920f0c1ed4be48a1
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Mon Jan 26 11:23:45 2026 +0800
sched/hrtimer: Update the comments.
This commit updated the comments.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
sched/hrtimer/hrtimer_cancel.c | 4 ++--
sched/hrtimer/hrtimer_process.c | 10 +++++-----
sched/hrtimer/hrtimer_start.c | 6 +++---
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/sched/hrtimer/hrtimer_cancel.c b/sched/hrtimer/hrtimer_cancel.c
index d77330c186d..0415511bead 100644
--- a/sched/hrtimer/hrtimer_cancel.c
+++ b/sched/hrtimer/hrtimer_cancel.c
@@ -83,7 +83,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
DEBUGASSERT(hrtimer != NULL);
- /* Enter critical section to protect the hrtimer container */
+ /* Acquire the lock and seize the ownership of the hrtimer queue. */
flags = write_seqlock_irqsave(&g_hrtimer_lock);
@@ -107,7 +107,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
}
}
- /* Leave critical section */
+ /* Release the lock and give up the ownership of the hrtimer queue. */
write_sequnlock_irqrestore(&g_hrtimer_lock, flags);
return ret;
diff --git a/sched/hrtimer/hrtimer_process.c b/sched/hrtimer/hrtimer_process.c
index d29a1240614..2b701cd85ae 100644
--- a/sched/hrtimer/hrtimer_process.c
+++ b/sched/hrtimer/hrtimer_process.c
@@ -77,7 +77,7 @@ void hrtimer_process(uint64_t now)
uint64_t period;
int cpu = this_cpu();
- /* Lock the hrtimer container to protect access */
+ /* Acquire the lock and seize the ownership of the hrtimer queue. */
flags = write_seqlock_irqsave(&g_hrtimer_lock);
@@ -102,7 +102,7 @@ void hrtimer_process(uint64_t now)
break;
}
- /* Remove the expired timer from the timer container */
+ /* Remove the expired timer from the timer queue */
hrtimer_remove(hrtimer);
@@ -121,8 +121,8 @@ void hrtimer_process(uint64_t now)
flags = write_seqlock_irqsave(&g_hrtimer_lock);
/* If the timer is periodic and has not been rearmed or
- * cancelled concurrently,
- * compute next expiration and reinsert into container
+ * cancelled concurrently, calculate next expiration and
+ * re-insert into the timer queue.
*/
if (period != 0u && hrtimer_is_running(hrtimer, cpu))
@@ -153,7 +153,7 @@ void hrtimer_process(uint64_t now)
hrtimer_reprogram(hrtimer->expired);
}
- /* Leave critical section */
+ /* Release the lock and give up the ownership of the hrtimer queue. */
write_sequnlock_irqrestore(&g_hrtimer_lock, flags);
}
diff --git a/sched/hrtimer/hrtimer_start.c b/sched/hrtimer/hrtimer_start.c
index 3f6b9e09118..8d26a9fafed 100644
--- a/sched/hrtimer/hrtimer_start.c
+++ b/sched/hrtimer/hrtimer_start.c
@@ -82,7 +82,7 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
DEBUGASSERT(hrtimer != NULL);
- /* Protect container manipulation with spinlock and disable interrupts */
+ /* Acquire the lock and seize the ownership of the hrtimer queue. */
flags = write_seqlock_irqsave(&g_hrtimer_lock);
@@ -98,7 +98,7 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
hrtimer->func = func;
hrtimer->expired = next_expired;
- /* Insert the timer into the container */
+ /* Insert the timer into the hrtimer queue. */
hrtimer_insert(hrtimer);
@@ -109,7 +109,7 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
hrtimer_reprogram(hrtimer->expired);
}
- /* Release spinlock and restore interrupts */
+ /* Release the lock and give up the ownership of the hrtimer queue. */
write_sequnlock_irqrestore(&g_hrtimer_lock, flags);
(nuttx) 05/11: sched/hrtimer: Replace hrtimer_gettime with clock_systime_nsec.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 89dbed25a0d8eac52b7b3d684f697bfb046e9bbc
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Wed Jan 7 20:56:55 2026 +0800
sched/hrtimer: Replace hrtimer_gettime with clock_systime_nsec.
This commit move the hrtimer_gettime to clock_systime_nsec to improve
the code reusability.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
include/nuttx/clock.h | 22 ++++++++++++++++++++++
sched/hrtimer/hrtimer.h | 24 ------------------------
sched/hrtimer/hrtimer_start.c | 2 +-
sched/sched/sched_timer.c | 2 +-
4 files changed, 24 insertions(+), 26 deletions(-)
diff --git a/include/nuttx/clock.h b/include/nuttx/clock.h
index 9dbf64dbd3b..6c176e6ef06 100644
--- a/include/nuttx/clock.h
+++ b/include/nuttx/clock.h
@@ -733,6 +733,28 @@ clock_t clock_systime_ticks(void);
void clock_systime_timespec(FAR struct timespec *ts);
+/****************************************************************************
+ * Name: clock_systime_nsec
+ *
+ * Description:
+ * Return the current value of the system timer counter as
+ * uint64_t nanoseconds.
+ *
+ * Input Parameters:
+ * ts - Location to return the time
+ *
+ * Returned Value:
+ * The current system time in nanoseconds.
+ *
+ ****************************************************************************/
+
+static inline_function uint64_t clock_systime_nsec(void)
+{
+ struct timespec ts;
+ clock_systime_timespec(&ts);
+ return clock_time2nsec(&ts);
+}
+
/****************************************************************************
* Name: clock_cpuload
*
diff --git a/sched/hrtimer/hrtimer.h b/sched/hrtimer/hrtimer.h
index 42801ff4d8a..9ec29bc227f 100644
--- a/sched/hrtimer/hrtimer.h
+++ b/sched/hrtimer/hrtimer.h
@@ -110,30 +110,6 @@ void hrtimer_process(uint64_t now);
* Inline Functions
****************************************************************************/
-/****************************************************************************
- * Name: hrtimer_gettime
- *
- * Description:
- * Get the current high-resolution time in nanoseconds.
- *
- * Returned Value:
- * Current time in nanoseconds.
- ****************************************************************************/
-
-static inline_function
-uint64_t hrtimer_gettime(void)
-{
- struct timespec ts;
-
- /* Get current time from platform-specific timer */
-
- clock_systime_timespec(&ts);
-
- /* Convert timespec to nanoseconds */
-
- return clock_time2nsec(&ts);
-}
-
/****************************************************************************
* Name: hrtimer_reprogram
*
diff --git a/sched/hrtimer/hrtimer_start.c b/sched/hrtimer/hrtimer_start.c
index 86b37f3cce2..d270dd21eee 100644
--- a/sched/hrtimer/hrtimer_start.c
+++ b/sched/hrtimer/hrtimer_start.c
@@ -92,7 +92,7 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
}
else
{
- hrtimer->expired = hrtimer_gettime() + expired;
+ hrtimer->expired = clock_systime_nsec() + expired;
}
/* Ensure expiration time does not overflow */
diff --git a/sched/sched/sched_timer.c b/sched/sched/sched_timer.c
index 5f5c4bc0b50..9bf3c39aa8b 100644
--- a/sched/sched/sched_timer.c
+++ b/sched/sched/sched_timer.c
@@ -135,7 +135,7 @@ void nxsched_process_timer(void)
HRTIMER_MODE_REL);
}
- hrtimer_process(hrtimer_gettime());
+ hrtimer_process(clock_systime_nsec());
#else
/* Fallback: process one scheduler tick */
(nuttx) 01/11: sched/hrtimer: Fixed hrtimer_starttimer.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 47ce6590b77fd63549e1ea9989005d4748b50d8f
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Wed Jan 7 20:19:39 2026 +0800
sched/hrtimer: Fixed hrtimer_starttimer.
This commit fixed the functional correctness issues in tick mode
and non-tickless alarm mode.
- In tick mode, we do not need reprogram the timer.
- In non-tickless alarm mode, the up_timer_start receive the relative time as the parameter.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
sched/hrtimer/hrtimer.h | 28 ++++++++++++++--------------
sched/hrtimer/hrtimer_cancel.c | 2 +-
sched/hrtimer/hrtimer_process.c | 2 +-
sched/hrtimer/hrtimer_start.c | 2 +-
4 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/sched/hrtimer/hrtimer.h b/sched/hrtimer/hrtimer.h
index 2e64624fa6a..fabcbcf2dd2 100644
--- a/sched/hrtimer/hrtimer.h
+++ b/sched/hrtimer/hrtimer.h
@@ -124,10 +124,10 @@ uint64_t hrtimer_gettime(void)
}
/****************************************************************************
- * Name: hrtimer_starttimer
+ * Name: hrtimer_reprogram
*
* Description:
- * Start the hardware timer to expire at a specified nanosecond time.
+ * Reprogram the hardware timer to expire at a specified nanosecond time.
* Converts the nanosecond time to timespec and calls the platform-specific
* timer start function.
*
@@ -138,23 +138,23 @@ uint64_t hrtimer_gettime(void)
* OK (0) on success, negated errno on failure.
****************************************************************************/
-static inline_function
-int hrtimer_starttimer(uint64_t ns)
+static inline_function void hrtimer_reprogram(uint64_t next_expired)
{
- struct timespec ts;
+#ifdef CONFIG_SCHED_TICKLESS
int ret;
-
- /* Convert nanoseconds to timespec */
-
- clock_nsec2time(&ts, ns);
-
-#ifdef CONFIG_ALARM_ARCH
+ struct timespec ts;
+# ifdef CONFIG_SCHED_TICKLESS_ALARM
+ clock_nsec2time(&ts, next_expired);
ret = up_alarm_start(&ts);
-#elif defined(CONFIG_TIMER_ARCH)
+# else
+ struct timespec current;
+ up_timer_gettime(¤t);
+ clock_nsec2time(&ts, next_expired);
+ clock_timespec_subtract(&ts, ¤t, &ts);
ret = up_timer_start(&ts);
+# endif
+ DEBUGASSERT(ret == 0);
#endif
-
- return ret;
}
/****************************************************************************
diff --git a/sched/hrtimer/hrtimer_cancel.c b/sched/hrtimer/hrtimer_cancel.c
index b0b66c624b4..a93f9ba437d 100644
--- a/sched/hrtimer/hrtimer_cancel.c
+++ b/sched/hrtimer/hrtimer_cancel.c
@@ -143,7 +143,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
first = hrtimer_get_first();
if (first != NULL)
{
- ret = hrtimer_starttimer(first->expired);
+ hrtimer_reprogram(first->expired);
}
}
diff --git a/sched/hrtimer/hrtimer_process.c b/sched/hrtimer/hrtimer_process.c
index 314e410d244..ff7f945b6d3 100644
--- a/sched/hrtimer/hrtimer_process.c
+++ b/sched/hrtimer/hrtimer_process.c
@@ -155,7 +155,7 @@ void hrtimer_process(uint64_t now)
{
/* Start timer for the next earliest expiration */
- (void)hrtimer_starttimer(hrtimer->expired);
+ hrtimer_reprogram(hrtimer->expired);
}
/* Leave critical section */
diff --git a/sched/hrtimer/hrtimer_start.c b/sched/hrtimer/hrtimer_start.c
index ca35a62422f..81f688de23d 100644
--- a/sched/hrtimer/hrtimer_start.c
+++ b/sched/hrtimer/hrtimer_start.c
@@ -103,7 +103,7 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
if (hrtimer_is_first(hrtimer))
{
- ret = hrtimer_starttimer(hrtimer->expired);
+ hrtimer_reprogram(hrtimer->expired);
}
/* Release spinlock and restore interrupts */
(nuttx) 09/11: sched/hrtimer: Update the documentation.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit fdf3eb0d5601616f6a56c18ee94ce251383ee082
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Mon Jan 26 10:07:58 2026 +0800
sched/hrtimer: Update the documentation.
This commit updated the documentation for hrtimer.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
.../reference/os/hrtimer_state_machine.png | Bin 357712 -> 0 bytes
Documentation/reference/os/time_clock.rst | 165 ++++++++++++++++++---
2 files changed, 143 insertions(+), 22 deletions(-)
diff --git a/Documentation/reference/os/hrtimer_state_machine.png b/Documentation/reference/os/hrtimer_state_machine.png
deleted file mode 100644
index 27fa6474710..00000000000
Binary files a/Documentation/reference/os/hrtimer_state_machine.png and /dev/null differ
diff --git a/Documentation/reference/os/time_clock.rst b/Documentation/reference/os/time_clock.rst
index f178f980751..7beb20824e1 100644
--- a/Documentation/reference/os/time_clock.rst
+++ b/Documentation/reference/os/time_clock.rst
@@ -630,35 +630,134 @@ require nanosecond-level task timing, which tick-based timers
like wdog cannot provide. Reducing the tick interval to micro-
or nanoseconds is impractical, as it would overload the CPU with interrupts.
+High-resolution Timer (HRTimer) is a timer abstraction capable of achieving
+nanosecond-level timing resolution, primarily used in scenarios requiring
+high-resolution clock events. With the advancement of integrated circuit
+technology, modern high-resolution timer hardware, such as the typical x86
+HPET, can already meet sub-nanosecond timing requirements and offer
+femtosecond-level jitter control.
+
+Although the current hardware timer abstraction (`up_alarm/up_timer`)
+in the NuttX kernel already supports nanosecond-level timing, its software
+timer abstraction, wdog, and the timer timeout interrupt handling process
+remain at microsecond-level (tick) resolution, which falls short of
+high-resolution timing demands.
+
To address this, NuttX provides a high-resolution timer (hrtimer),
-which delivers true nanosecond-level precision. Unlike wdog’s list-based timers,
-hrtimer uses a red-black tree for efficient management of large numbers of timers,
-an important advantage in hard real-time systems like vehicle control.
+which delivers true nanosecond-level precision. HRTimer primarily provides
+the following functional interfaces:
+
+**Set a timer in nanoseconds**: Configure a software timer to trigger at
+ a specified nanosecond time.
+
+**Cancel a timer**: Cancel the software timer.
+
+**Handle timer timeout**: Execute timeout processing after the timer event
+ is triggered.
A user can register an hrtimer callback to execute after a specified delay.
The callback runs in the timer interrupt context, so only limited NuttX interfaces
are available, such as ``mq_send()``, ``sigqueue()``, ``nxevent_post()``, or ``kill()``,
to communicate with tasks.
-High-resolution timers (hrtimers) use a spinlock to protect internal timer data structures,
-allowing them to be safely accessed from interrupt context. This design makes hrtimers
-suitable for high-frequency timer operations.
-
-However, in SMP systems, a potential issue arises when a user cancels a timer that is currently
-executing: the timer instance may be freed prematurely while its callback is still running.
-To address this problem, a state machine is introduced in the hrtimer implementation:
-
-.. image:: hrtimer_state_machine.png
- :alt: hrtimer state machine
-
-Users may call ``hrtimer_cancel_sync()`` to synchronously cancel a timer and wait until the
-timer becomes fully inactive. In contrast, ``hrtimer_cancel()`` is a non-blocking variant
-that returns immediately without waiting for the timer to stop executing.
+The hrtimer implementation mainly includes the following interfaces:
+
+**hrtimer_start(timer, func, arg, delay)**: Asynchronously starts a
+ timer that has completed or has been asynchronously canceled (its
+ callback function might still be executing).
+
+**hrtimer_cancel(timer)**: Asynchronously cancels a timer. Note that
+ the semantics of this interface are completely different from Linux's
+ `try_to_cancel`. It ensures that the timer can definitely be canceled
+ successfully, but may need to wait for its callback function to finish
+ execution.
+
+**hrtimer_cancel_sync(timer)**: Synchronously cancels a timer. If the timer's
+ callback function is still executing, this function will spin-wait until
+ the callback completes. It ensures that the user can always obtain
+ ownership of the timer.
+
+The state-machine diagram of the HRTimer is as follows:
+
+.. code-block:: text
+
+ +------------------------------------------------------+
+ | HRTIMER State Diagram |
+ +------------------------------------------------------+
+ | |
+ | +----------------------+ |
+ | | HRTIMER_COMPLETED | |
+ | | (private) | |
+ | +----------------------+ |
+ | | |
+ | | hrtimer_start |
+ | | |
+ | | |
+ | v |
+ | +----------------------+ |
+ | | HRTIMER_PENDING |---------------------+ |
+ | +-->| (shared) |<---+ | |
+ | | +----------------------+ | | |
+ | | | |timer callback | |
+ | | |hrtimer_expiry |return non-zero | |
+ | | | | | |
+ | | v | | |
+ | | +----------------------+ | | |
+ | | | HRTIMER_RUNNING |----+ | |
+ | | | (shared) | | |
+ | | +----------------------+ | |
+ | | | | |
+ | | | | |
+ | | |timer return zero | |
+ | | |or | |
+ | | |hrtimer_cancel | |
+ | | | | |
+ | | v | |
+ | | +----------------------+ | |
+ | | | HRTIMER_CANCELED |<--------+ |
+ | +---------------| (half_shared) | |
+ | hrtimer_start +----------------------+ |
+ | | |
+ | hrtimer_cancel_sync| |
+ | wait all cores | |
+ | v |
+ | +----------------------+ |
+ | | HRTIMER_COMPLETED | |
+ | | (private) | |
+ | +----------------------+ |
+ | ^ | |
+ | | | |
+ | +--+ |
+ | hrtimer_cancel |
+ +------------------------------------------------------+
+
+The specific definitions of the states are as follows:
+
+**HRTIMER_PENDING|shared**: `hrtimer->func != NULL`. That is, the hrtimer has
+been inserted into the hrtimer queue and is waiting to be executed.
+
+**HRTIMER_COMPLETED|private**: `hrtimer->func == NULL` ∧
+`∀c ∈ [0, CONFIG_SMP_NCPUS), (g_hrtimer_running[c] & ~(1u)) != hrtimer`
+That is, the hrtimer is not in a pending state, and no core is currently
+executing the hrtimer's callback function.
+
+**HRTIMER_RUNNING|shared**: `hrtimer->func == NULL` ∧
+`∃c ∈ [0, CONFIG_SMP_NCPUS), g_hrtimer_running[c] == hrtimer`.
+That is, the hrtimer is not in a pending state, and there exists at least one
+core that is currently executing the hrtimer’s callback function.
+
+**HRTIMER_CANCELED|half_shared**: `hrtimer->func == NULL` ∧
+`∀c ∈ [0, CONFIG_SMP_NCPUS), g_hrtimer_running[c] != hrtimer`.
+That is, the hrtimer is not in a pending state, and all cores have lost
+ownership of the hrtimer—meaning they can no longer read from or write to the
+hrtimer—though its callback function may still be in the process of being
+executed.
- :c:func:`hrtimer_init`
- :c:func:`hrtimer_cancel`
- :c:func:`hrtimer_cancel_sync`
- :c:func:`hrtimer_start`
+- :c:func:`hrtimer_gettime`
- High-resolution Timer Callback
.. c:function:: void hrtimer_init(FAR hrtimer_t *hrtimer, hrtentry_t func)
@@ -676,6 +775,8 @@ that returns immediately without waiting for the timer to stop executing.
.. c:function:: int hrtimer_cancel(FAR hrtimer_t *hrtimer)
+ Cancel a high-resolution timer asynchronously.
+
If the timer is armed but has not yet expired, it will be removed from
the timer queue and the callback will not be invoked.
@@ -683,8 +784,9 @@ that returns immediately without waiting for the timer to stop executing.
the timer as canceled and return immediately. The running callback is
allowed to complete, but it will not be invoked again.
- This function is non-blocking and does not wait for a running callback
- to finish.
+ After the function completes, the caller acquires limited ownership,
+ allowing timer restart but not freeing. Callback may still be executing
+ on another CPU. Use with caution to avoid concurrency issues.
:param hrtimer: Timer instance to cancel
@@ -698,9 +800,9 @@ that returns immediately without waiting for the timer to stop executing.
becomes inactive.
This function first calls hrtimer_cancel() to request cancellation of
- the timer. If the timer callback is currently executing, this function
- will wait until the callback has completed and the timer state has
- transitioned to HRTIMER_STATE_INACTIVE.
+ the timer. It sets timer to canceled state and waits for all
+ references to be released. Caller acquires full ownership and can
+ safely deallocate the timer after this function returns.
This function may sleep and must not be called from interrupt context.
@@ -726,8 +828,27 @@ that returns immediately without waiting for the timer to stop executing.
**POSIX Compatibility:** This is a NON-POSIX interface.
+.. c:function:: uint64_t hrtimer_gettime(FAR hrtimer_t *timer)
+
+ Get the remaining time until timer expiration.
+
+ :param timer: Timer instance to query
+
+ :return: Remaining time in nanoseconds until next expiration.
+
+ **Assumptions:**
+ - Timer is not NULL.
+
+ **POSIX Compatibility:** This is a NON-POSIX interface.
+
.. c:type:: uint64_t (*hrtimer_entry_t)(FAR hrtimer_t *hrtimer, \
uint64_t expired)
**High-resolution Timer Callback**: when a hrtimer expires,
the callback function with this type is called.
+
+ :param timer: The hrtimer pointer passed to callback function,
+ do not modify the hrtimer when executing callback function.
+ :param expired: Time in nanoseconds when timer expired
+
+ :return: Next delay in nanoseconds until next expiration.
(nuttx) 08/11: sched/hrtimer: Fix the functional correctness issue in hrtimer_start.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 0048a5c21bbf0cf1a1dadb856f892c500a2b6b19
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Thu Jan 15 11:56:14 2026 +0800
sched/hrtimer: Fix the functional correctness issue in hrtimer_start.
This commit fixed the functional correctness issue in hrtimer_start by
adding HRTIMER_MAX_DELAY fr the HRTIMER_MODE_REL.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
include/nuttx/hrtimer.h | 12 ++++++++++++
sched/hrtimer/hrtimer_start.c | 31 +++++++++++++++----------------
2 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/include/nuttx/hrtimer.h b/include/nuttx/hrtimer.h
index bd8b05c2c52..f416cbb18d4 100644
--- a/include/nuttx/hrtimer.h
+++ b/include/nuttx/hrtimer.h
@@ -36,6 +36,18 @@
#include <stdint.h>
#include <sys/tree.h>
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* 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.
+ */
+
+#define HRTIMER_MAX_DELAY (INT64_MAX >> 1)
+
/****************************************************************************
* Public Types
****************************************************************************/
diff --git a/sched/hrtimer/hrtimer_start.c b/sched/hrtimer/hrtimer_start.c
index d270dd21eee..3f6b9e09118 100644
--- a/sched/hrtimer/hrtimer_start.c
+++ b/sched/hrtimer/hrtimer_start.c
@@ -64,9 +64,22 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
uint64_t expired,
enum hrtimer_mode_e mode)
{
+ uint64_t next_expired;
irqstate_t flags;
int ret = OK;
+ /* Compute absolute expiration time */
+
+ if (mode == HRTIMER_MODE_ABS)
+ {
+ next_expired = expired;
+ }
+ else
+ {
+ expired = expired <= HRTIMER_MAX_DELAY ? expired : HRTIMER_MAX_DELAY;
+ next_expired = clock_systime_nsec() + expired;
+ }
+
DEBUGASSERT(hrtimer != NULL);
/* Protect container manipulation with spinlock and disable interrupts */
@@ -82,22 +95,8 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
hrtimer_remove(hrtimer);
}
- hrtimer->func = func;
-
- /* Compute absolute expiration time */
-
- if (mode == HRTIMER_MODE_ABS)
- {
- hrtimer->expired = expired;
- }
- else
- {
- hrtimer->expired = clock_systime_nsec() + expired;
- }
-
- /* Ensure expiration time does not overflow */
-
- DEBUGASSERT(hrtimer->expired >= expired);
+ hrtimer->func = func;
+ hrtimer->expired = next_expired;
/* Insert the timer into the container */
(nuttx) 03/11: sched/hrtimer: Fix functional correctness issue in synchronization.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit b2fadb8529e48526dcec134bbd1ac0a267650f2b
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Wed Jan 7 20:34:14 2026 +0800
sched/hrtimer: Fix functional correctness issue in synchronization.
On 32-bit platform with 64-bit pointer, read/write to the
`g_hrtimer_running` is not atomic, we should protect it with the
seqcount to ensure the value we read is correct.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
sched/hrtimer/hrtimer.h | 76 +++++++++++++++++++++++++++++++++++---
sched/hrtimer/hrtimer_cancel.c | 4 +-
sched/hrtimer/hrtimer_initialize.c | 4 +-
sched/hrtimer/hrtimer_process.c | 10 +++--
sched/hrtimer/hrtimer_start.c | 4 +-
5 files changed, 82 insertions(+), 16 deletions(-)
diff --git a/sched/hrtimer/hrtimer.h b/sched/hrtimer/hrtimer.h
index ff1d40a947a..f3d6e80a2aa 100644
--- a/sched/hrtimer/hrtimer.h
+++ b/sched/hrtimer/hrtimer.h
@@ -31,6 +31,7 @@
#include <nuttx/arch.h>
#include <nuttx/clock.h>
#include <nuttx/hrtimer.h>
+#include <nuttx/seqlock.h>
#ifdef CONFIG_HRTIMER
@@ -52,9 +53,9 @@ RB_HEAD(hrtimer_tree_s, hrtimer_node_s);
* Public Data
****************************************************************************/
-/* Spinlock protecting access to the hrtimer container and timer state */
+/* Seqcount protecting access to the hrtimer queue and timer state */
-extern spinlock_t g_hrtimer_spinlock;
+extern seqcount_t g_hrtimer_lock;
#ifdef CONFIG_HRTIMER_TREE
/* Red-Black tree containing all active high-resolution timers */
@@ -310,6 +311,72 @@ static inline_function bool hrtimer_is_first(FAR hrtimer_t *hrtimer)
#endif
}
+/****************************************************************************
+ * Name: hrtimer_read_64/32
+ *
+ * Description:
+ * Internal function to read the value in the queue atomically.
+ * Do not use this function if you are not sure about the thread-safe
+ * of the value you are reading.
+ *
+ * Input Parameters:
+ * ptr - The pointer to be read.
+ *
+ * Returned Value:
+ * The value in the queue.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_64BIT
+/* On 64-bit architectures, read/write uint64_t is atomic. */
+# define hrtimer_read_64(ptr) (*(FAR volatile uint64_t *)(ptr))
+#else
+static inline_function
+uint64_t hrtimer_read_64(FAR const uint64_t *ptr)
+{
+ uint64_t val;
+ uint32_t seq;
+
+ do
+ {
+ seq = read_seqbegin(&g_hrtimer_lock);
+ val = *ptr;
+ }
+ while (read_seqretry(&g_hrtimer_lock, seq));
+
+ return val;
+}
+#endif
+
+#if UINT_MAX >= UINT32_MAX
+/* On 32/64-bit architectures, read/write uint32_t is atomic. */
+# define hrtimer_read_32(ptr) (*(FAR volatile uint32_t *)(ptr))
+#else
+static inline_function
+uint32_t hrtimer_read_32(FAR const uint32_t *ptr)
+{
+ uint32_t val;
+ uint32_t seq;
+
+ do
+ {
+ seq = read_seqbegin(&g_hrtimer_lock);
+ val = *ptr;
+ }
+ while (read_seqretry(&g_hrtimer_lock, seq));
+
+ return val;
+}
+#endif
+
+/* Generic function to read the value in the queue atomically. */
+
+#define hrtimer_read(ptr) \
+ (sizeof(*(ptr)) == 8u ? \
+ hrtimer_read_64((FAR const uint64_t *)(ptr)) : \
+ (sizeof(*(ptr)) == 4u ? \
+ hrtimer_read_32((FAR const uint32_t *)(ptr)) : 0u))
+
/****************************************************************************
* Name: hrtimer_mark_running
*
@@ -349,14 +416,11 @@ static inline_function bool hrtimer_is_first(FAR hrtimer_t *hrtimer)
* Returned Value:
* true if the CPU core is running the timer, false otherwise.
*
- * Assumption:
- * The caller must hold the lock.
- *
****************************************************************************/
#ifdef CONFIG_SMP
# define hrtimer_is_running(timer, cpu) \
- (g_hrtimer_running[cpu] == (uintptr_t)(timer))
+ (hrtimer_read(&g_hrtimer_running[cpu]) == (uintptr_t)(timer))
#else
# define hrtimer_is_running(timer, cpu) (true)
#endif
diff --git a/sched/hrtimer/hrtimer_cancel.c b/sched/hrtimer/hrtimer_cancel.c
index 43a6d2f371e..8cf5a322606 100644
--- a/sched/hrtimer/hrtimer_cancel.c
+++ b/sched/hrtimer/hrtimer_cancel.c
@@ -130,7 +130,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
/* Enter critical section to protect the hrtimer container */
- flags = spin_lock_irqsave(&g_hrtimer_spinlock);
+ flags = write_seqlock_irqsave(&g_hrtimer_lock);
/* Ensure no core can write the hrtimer. */
@@ -154,7 +154,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
/* Leave critical section */
- spin_unlock_irqrestore(&g_hrtimer_spinlock, flags);
+ write_sequnlock_irqrestore(&g_hrtimer_lock, flags);
return ret;
}
diff --git a/sched/hrtimer/hrtimer_initialize.c b/sched/hrtimer/hrtimer_initialize.c
index 43010f074d2..c097f9f99ae 100644
--- a/sched/hrtimer/hrtimer_initialize.c
+++ b/sched/hrtimer/hrtimer_initialize.c
@@ -47,7 +47,7 @@ uintptr_t g_hrtimer_running[CONFIG_SMP_NCPUS];
* timer container is modified.
*/
-spinlock_t g_hrtimer_spinlock = SP_UNLOCKED;
+seqcount_t g_hrtimer_lock = SEQLOCK_INITIALIZER;
/* Container for all active high-resolution timers.
*
@@ -89,7 +89,7 @@ struct list_node g_hrtimer_list = LIST_INITIAL_VALUE(g_hrtimer_list);
* - The tree key is the absolute expiration time stored in
* hrtimer_node_s and compared via hrtimer_compare().
* - All accesses to the tree must be serialized using
- * g_hrtimer_spinlock.
+ * g_hrtimer_lock.
* - These generated functions are used internally by the hrtimer
* core (e.g., hrtimer_start(), hrtimer_cancel(), and expire paths).
****************************************************************************/
diff --git a/sched/hrtimer/hrtimer_process.c b/sched/hrtimer/hrtimer_process.c
index 97266cacf8c..9111d3991e8 100644
--- a/sched/hrtimer/hrtimer_process.c
+++ b/sched/hrtimer/hrtimer_process.c
@@ -79,7 +79,7 @@ void hrtimer_process(uint64_t now)
/* Lock the hrtimer container to protect access */
- flags = spin_lock_irqsave(&g_hrtimer_spinlock);
+ flags = write_seqlock_irqsave(&g_hrtimer_lock);
/* Fetch the earliest active timer */
@@ -110,7 +110,7 @@ void hrtimer_process(uint64_t now)
/* Leave critical section before invoking the callback */
- spin_unlock_irqrestore(&g_hrtimer_spinlock, flags);
+ write_sequnlock_irqrestore(&g_hrtimer_lock, flags);
/* Invoke the timer callback */
@@ -118,7 +118,9 @@ void hrtimer_process(uint64_t now)
/* Re-enter critical section to update timer state */
- flags = spin_lock_irqsave(&g_hrtimer_spinlock);
+ flags = write_seqlock_irqsave(&g_hrtimer_lock);
+
+ hrtimer_mark_running(NULL, cpu);
/* If the timer is periodic and has not been rearmed or
* cancelled concurrently,
@@ -155,5 +157,5 @@ void hrtimer_process(uint64_t now)
/* Leave critical section */
- spin_unlock_irqrestore(&g_hrtimer_spinlock, flags);
+ write_sequnlock_irqrestore(&g_hrtimer_lock, flags);
}
diff --git a/sched/hrtimer/hrtimer_start.c b/sched/hrtimer/hrtimer_start.c
index 61ed886dd39..86b37f3cce2 100644
--- a/sched/hrtimer/hrtimer_start.c
+++ b/sched/hrtimer/hrtimer_start.c
@@ -71,7 +71,7 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
/* Protect container manipulation with spinlock and disable interrupts */
- flags = spin_lock_irqsave(&g_hrtimer_spinlock);
+ flags = write_seqlock_irqsave(&g_hrtimer_lock);
/* Ensure no core can write the hrtimer. */
@@ -112,7 +112,7 @@ int hrtimer_start(FAR hrtimer_t *hrtimer, hrtimer_entry_t func,
/* Release spinlock and restore interrupts */
- spin_unlock_irqrestore(&g_hrtimer_spinlock, flags);
+ write_sequnlock_irqrestore(&g_hrtimer_lock, flags);
return ret;
}
(nuttx) 07/11: sched/hrtimer: Simplify the hrtimer_cancel.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit a6d64a1a83de1b893a7eabb39be2f4550811b325
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Thu Jan 15 11:13:38 2026 +0800
sched/hrtimer: Simplify the hrtimer_cancel.
This commit simplified the hrtimer_cancel.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
sched/hrtimer/hrtimer_cancel.c | 14 +++++++-------
sched/hrtimer/hrtimer_process.c | 4 +---
2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/sched/hrtimer/hrtimer_cancel.c b/sched/hrtimer/hrtimer_cancel.c
index bed9011a7f1..d77330c186d 100644
--- a/sched/hrtimer/hrtimer_cancel.c
+++ b/sched/hrtimer/hrtimer_cancel.c
@@ -94,16 +94,16 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
if (hrtimer_is_armed(hrtimer))
{
hrtimer_remove(hrtimer);
- }
- /* If the canceled timer was the earliest one, update the hardware timer */
+ /* Update the hardware timer if the queue head changed. */
- if (hrtimer_is_first(hrtimer))
- {
- first = hrtimer_get_first();
- if (first != NULL)
+ if (hrtimer_is_first(hrtimer))
{
- hrtimer_reprogram(first->expired);
+ first = hrtimer_get_first();
+ if (first != NULL)
+ {
+ hrtimer_reprogram(first->expired);
+ }
}
}
diff --git a/sched/hrtimer/hrtimer_process.c b/sched/hrtimer/hrtimer_process.c
index 9111d3991e8..d29a1240614 100644
--- a/sched/hrtimer/hrtimer_process.c
+++ b/sched/hrtimer/hrtimer_process.c
@@ -120,8 +120,6 @@ void hrtimer_process(uint64_t now)
flags = write_seqlock_irqsave(&g_hrtimer_lock);
- hrtimer_mark_running(NULL, cpu);
-
/* If the timer is periodic and has not been rearmed or
* cancelled concurrently,
* compute next expiration and reinsert into container
@@ -129,7 +127,7 @@ void hrtimer_process(uint64_t now)
if (period != 0u && hrtimer_is_running(hrtimer, cpu))
{
- hrtimer->expired += period;
+ hrtimer->expired = expired + period;
/* Ensure no overflow occurs */
(nuttx) 11/11: sched/hrtimer: Rename the HRTIMER_CANCEL_SYNC_DELAY timeout.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 281f9fc0c0f8e2363beedfb899027f26891d5934
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Mon Jan 26 11:48:27 2026 +0800
sched/hrtimer: Rename the HRTIMER_CANCEL_SYNC_DELAY timeout.
This commit renamed the HRTIMER_CANCEL_SYNC_DELAY_MS to
HRTIMER_CANCEL_SYNC_DELAY_US.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
sched/hrtimer/hrtimer.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sched/hrtimer/hrtimer.h b/sched/hrtimer/hrtimer.h
index 9ec29bc227f..606cd086350 100644
--- a/sched/hrtimer/hrtimer.h
+++ b/sched/hrtimer/hrtimer.h
@@ -43,7 +43,7 @@
/* Delay used while waiting for a running hrtimer callback to complete */
-#define HRTIMER_CANCEL_SYNC_DELAY_MS 5
+#define HRTIMER_CANCEL_SYNC_DELAY_US CONFIG_USEC_PER_TICK
/****************************************************************************
* Public Types
@@ -513,7 +513,7 @@ static inline_function void hrtimer_wait(FAR hrtimer_t *timer)
{
if (!up_interrupt_context() && !is_idle_task(this_task()))
{
- nxsched_msleep(HRTIMER_CANCEL_SYNC_DELAY_MS);
+ nxsched_usleep(HRTIMER_CANCEL_SYNC_DELAY_US);
}
/* Otherwise, spin-wait is enough. */
(nuttx) 04/11: sched/hrtimer: Add hrtimer_wait to simplify the wait.
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ligd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 65bc3db6243c3ac4aa8d0f7bc41945cbd24d1bbc
Author: ouyangxiangzhen <ou...@xiaomi.com>
AuthorDate: Wed Jan 7 20:45:01 2026 +0800
sched/hrtimer: Add hrtimer_wait to simplify the wait.
This commit added hrtimer_wait to simplify the wait.
Signed-off-by: ouyangxiangzhen <ou...@xiaomi.com>
---
sched/hrtimer/hrtimer.h | 66 ++++++++++++++++++++++++++++++++++++++++++
sched/hrtimer/hrtimer_cancel.c | 63 ++--------------------------------------
2 files changed, 69 insertions(+), 60 deletions(-)
diff --git a/sched/hrtimer/hrtimer.h b/sched/hrtimer/hrtimer.h
index f3d6e80a2aa..42801ff4d8a 100644
--- a/sched/hrtimer/hrtimer.h
+++ b/sched/hrtimer/hrtimer.h
@@ -33,8 +33,18 @@
#include <nuttx/hrtimer.h>
#include <nuttx/seqlock.h>
+#include "sched/sched.h"
+
#ifdef CONFIG_HRTIMER
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Delay used while waiting for a running hrtimer callback to complete */
+
+#define HRTIMER_CANCEL_SYNC_DELAY_MS 5
+
/****************************************************************************
* Public Types
****************************************************************************/
@@ -484,5 +494,61 @@ int hrtimer_cancel_running(FAR hrtimer_t *timer)
return refs;
}
+/****************************************************************************
+ * Name: hrtimer_wait
+ *
+ * Description:
+ * Wait for all references to be released before the timer can be freed.
+ *
+ * Input Parameters:
+ * timer - The hrtimer to be waited.
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumption:
+ * The periodical hrtimer should be cancelled before calling this function.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+static inline_function void hrtimer_wait(FAR hrtimer_t *timer)
+{
+ int cpu;
+
+ DEBUGASSERT(timer && timer->func == NULL);
+
+ /* Wait until all references have been released. */
+
+ for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++)
+ {
+ /* The timer should not be restarted again.
+ * Or there will be ownership invariant violation.
+ */
+
+ DEBUGASSERT(!hrtimer_is_running(timer, cpu));
+
+ /* If sleeping is permitted, yield the CPU briefly to avoid
+ * busy-waiting. Otherwise, spin until the callback completes
+ * and the state becomes inactive.
+ */
+
+ while (hrtimer_is_cancelling(timer, cpu))
+ {
+ if (!up_interrupt_context() && !is_idle_task(this_task()))
+ {
+ nxsched_msleep(HRTIMER_CANCEL_SYNC_DELAY_MS);
+ }
+
+ /* Otherwise, spin-wait is enough. */
+ }
+ }
+
+ /* Finally, we acquire the ownership of this hrtimer. */
+}
+#else
+# define hrtimer_wait(timer) /* Nothing to wait in non-SMP. */
+#endif
+
#endif /* CONFIG_HRTIMER */
#endif /* __SCHED_HRTIMER_HRTIMER_H */
diff --git a/sched/hrtimer/hrtimer_cancel.c b/sched/hrtimer/hrtimer_cancel.c
index 8cf5a322606..bed9011a7f1 100644
--- a/sched/hrtimer/hrtimer_cancel.c
+++ b/sched/hrtimer/hrtimer_cancel.c
@@ -29,53 +29,8 @@
#include <nuttx/clock.h>
#include <errno.h>
-#include "sched/sched.h"
#include "hrtimer/hrtimer.h"
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* Delay used while waiting for a running hrtimer callback to complete */
-
-#define HRTIMER_CANCEL_SYNC_DELAY_MS 5
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: hrtimer_is_active
- *
- * Description:
- * Check whether a high-resolution timer is currently running on any CPU.
- *
- * Input Parameters:
- * hrtimer - Pointer to the high-resolution timer to check.
- *
- * Returned Value:
- * true - The timer is active on at least one CPU.
- * false - The timer is not active.
- ****************************************************************************/
-#ifdef CONFIG_SMP
-static inline_function bool hrtimer_is_active(FAR hrtimer_t *hrtimer)
-{
- int cpu;
- bool is_active = false;
-
- for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++)
- {
- if (hrtimer_is_cancelling(hrtimer, cpu))
- {
- is_active = true;
- break;
- }
- }
-
- return is_active;
-}
-#endif
-
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -192,21 +147,9 @@ int hrtimer_cancel_sync(FAR hrtimer_t *hrtimer)
ret = hrtimer_cancel(hrtimer);
if (ret > 0)
{
- /* Wait until the timer transitions to the inactive state.
- *
- * If sleeping is permitted, yield the CPU briefly to avoid
- * busy-waiting. Otherwise, spin until the callback completes.
- */
-#ifdef CONFIG_SMP
- while (hrtimer_is_active(hrtimer))
- {
- if (!up_interrupt_context() &&
- !is_idle_task(this_task()))
- {
- nxsched_msleep(HRTIMER_CANCEL_SYNC_DELAY_MS);
- }
- }
-#endif
+ /* Wait until all the timer callbacks finish. */
+
+ hrtimer_wait(hrtimer);
}
return ret;