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 <wangchengdong@lixiang.com>
This commit is contained in:
wangchengdong
2025-12-16 15:08:29 +08:00
committed by archer
parent d7ce29774c
commit edf89ddedd
3 changed files with 128 additions and 12 deletions
+28 -3
View File
@@ -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
+23
View File
@@ -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
*
+77 -9
View File
@@ -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;
}