This is an automated email from the ASF dual-hosted git repository. archer pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit edf89ddedd1f01c34df7f0c0c5bc35be6e323515 Author: wangchengdong <[email protected]> AuthorDate: Tue Dec 16 15:08:29 2025 +0800 sched/hrtimer: add safe synchronous hrtimer cancel API Add a safe synchronous hrtimer cancel API, hrtimer_cancel_sync(). If the timer callback is currently executing, this function waits until the callback has completed and the timer state transitions to HRTIMER_STATE_INACTIVE. Signed-off-by: Chengdong Wang <[email protected]> --- Documentation/reference/os/time_clock.rst | 31 +++++++++-- include/nuttx/hrtimer.h | 23 +++++++++ sched/hrtimer/hrtimer_cancel.c | 86 +++++++++++++++++++++++++++---- 3 files changed, 128 insertions(+), 12 deletions(-) diff --git a/Documentation/reference/os/time_clock.rst b/Documentation/reference/os/time_clock.rst index e2f7f4a9ace..49d88b057a4 100644 --- a/Documentation/reference/os/time_clock.rst +++ b/Documentation/reference/os/time_clock.rst @@ -678,6 +678,7 @@ to communicate with tasks. - :c:func:`hrtimer_init` - :c:func:`hrtimer_cancel` +- :c:func:`hrtimer_cancel_sync` - :c:func:`hrtimer_start` - High-resolution Timer Callback @@ -698,9 +699,33 @@ to communicate with tasks. .. c:function:: int hrtimer_cancel(FAR hrtimer_t *hrtimer) - This function cancels a high-resolution timer if it is pending. - The timer callback will not be called if the timer was successfully - canceled. + 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. + + This function is non-blocking and does not wait for a running callback + to finish. + + :param hrtimer: Timer instance to cancel + + :return: ``OK`` on success; negated errno on failure. + + **POSIX Compatibility:** This is a NON-POSIX interface. + +.. c:function:: int hrtimer_cancel_sync(FAR hrtimer_t *hrtimer) + + Cancel a high-resolution timer and wait synchronously until the timer + 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. + + This function may sleep and must not be called from interrupt context. :param hrtimer: Timer instance to cancel diff --git a/include/nuttx/hrtimer.h b/include/nuttx/hrtimer.h index ddbff6707d6..3f68adf6f08 100644 --- a/include/nuttx/hrtimer.h +++ b/include/nuttx/hrtimer.h @@ -168,6 +168,29 @@ void hrtimer_init(FAR hrtimer_t *hrtimer, int hrtimer_cancel(FAR hrtimer_t *hrtimer); +/**************************************************************************** + * Name: hrtimer_cancel_sync + * + * 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. + * + * Input Parameters: + * hrtimer - Pointer to the high-resolution timer instance to cancel. + * + * Returned Value: + * OK (0) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int hrtimer_cancel_sync(FAR hrtimer_t *hrtimer); + /**************************************************************************** * Name: hrtimer_start * diff --git a/sched/hrtimer/hrtimer_cancel.c b/sched/hrtimer/hrtimer_cancel.c index 44dc7b1784f..bf974d240aa 100644 --- a/sched/hrtimer/hrtimer_cancel.c +++ b/sched/hrtimer/hrtimer_cancel.c @@ -6,7 +6,7 @@ * 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 to you under the Apache License, Version 2.0 (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 * @@ -32,6 +32,14 @@ #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 + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -46,8 +54,8 @@ * hrtimer red-black tree 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 it will - * not be re-armed or executed again. + * as canceled. The running callback is allowed to complete, but the timer + * will not be re-armed or executed again. * * If the canceled timer was the earliest (head) timer in the tree, the * expiration of the underlying hardware timer will be updated to: @@ -65,17 +73,18 @@ * OK (0) on success; a negated errno value on failure. * * Assumptions/Notes: - * - This function acquires the global hrtimer spinlock to protect the - * red-black tree and timer state. + * - 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) { FAR hrtimer_t *first; - irqstate_t flags; - int ret = OK; + irqstate_t flags; + int ret = OK; DEBUGASSERT(hrtimer != NULL); @@ -83,7 +92,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer) flags = spin_lock_irqsave(&g_hrtimer_spinlock); - /* Capture the current earliest timer before removal */ + /* Capture the current earliest timer before any modification */ first = (FAR hrtimer_t *)RB_MIN(hrtimer_tree_s, &g_hrtimer_tree); @@ -103,7 +112,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer) /* The callback is currently executing. * * Mark the timer as canceled so it will not be re-armed or - * executed again. The running callback is allowed to complete. + * executed again. The running callback is allowed to complete. * * NOTE: The timer node is expected to have already been removed * from the tree when the callback started executing. @@ -138,3 +147,62 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer) spin_unlock_irqrestore(&g_hrtimer_spinlock, flags); return ret; } + +/**************************************************************************** + * Name: hrtimer_cancel_sync + * + * 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. + * + * Input Parameters: + * hrtimer - Pointer to the high-resolution timer instance to cancel. + * + * Returned Value: + * OK (0) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int hrtimer_cancel_sync(FAR hrtimer_t *hrtimer) +{ + int ret; + bool cansleep; + + DEBUGASSERT(hrtimer != NULL); + + /* Determine whether sleeping is permitted in the current context */ + + cansleep = !up_interrupt_context() && + !is_idle_task(this_task()); + + /* Request cancellation of the timer */ + + ret = hrtimer_cancel(hrtimer); + if (ret < 0) + { + return ret; + } + + /* 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 + * and the state becomes inactive. + */ + + while (hrtimer->state != HRTIMER_STATE_INACTIVE) + { + if (cansleep) + { + nxsched_msleep(HRTIMER_CANCEL_SYNC_DELAY_MS); + } + } + + return OK; +}
