mirror of
https://github.com/apache/nuttx.git
synced 2026-05-29 04:19:37 +08:00
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:
@@ -678,6 +678,7 @@ to communicate with tasks.
|
|||||||
|
|
||||||
- :c:func:`hrtimer_init`
|
- :c:func:`hrtimer_init`
|
||||||
- :c:func:`hrtimer_cancel`
|
- :c:func:`hrtimer_cancel`
|
||||||
|
- :c:func:`hrtimer_cancel_sync`
|
||||||
- :c:func:`hrtimer_start`
|
- :c:func:`hrtimer_start`
|
||||||
- High-resolution Timer Callback
|
- High-resolution Timer Callback
|
||||||
|
|
||||||
@@ -698,9 +699,33 @@ to communicate with tasks.
|
|||||||
|
|
||||||
.. c:function:: int hrtimer_cancel(FAR hrtimer_t *hrtimer)
|
.. c:function:: int hrtimer_cancel(FAR hrtimer_t *hrtimer)
|
||||||
|
|
||||||
This function cancels a high-resolution timer if it is pending.
|
If the timer is armed but has not yet expired, it will be removed from
|
||||||
The timer callback will not be called if the timer was successfully
|
the timer queue and the callback will not be invoked.
|
||||||
canceled.
|
|
||||||
|
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
|
:param hrtimer: Timer instance to cancel
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,29 @@ void hrtimer_init(FAR hrtimer_t *hrtimer,
|
|||||||
|
|
||||||
int hrtimer_cancel(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
|
* Name: hrtimer_start
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership. The
|
* 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 not use this file except in compliance with the
|
||||||
* License. You may obtain a copy of the License at
|
* License. You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
@@ -32,6 +32,14 @@
|
|||||||
|
|
||||||
#include "hrtimer/hrtimer.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
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -46,8 +54,8 @@
|
|||||||
* hrtimer red-black tree and will not be executed.
|
* hrtimer red-black tree and will not be executed.
|
||||||
*
|
*
|
||||||
* If the timer callback is currently executing, the timer will be marked
|
* If the timer callback is currently executing, the timer will be marked
|
||||||
* as canceled. The running callback is allowed to complete, but it will
|
* as canceled. The running callback is allowed to complete, but the timer
|
||||||
* not be re-armed or executed again.
|
* will not be re-armed or executed again.
|
||||||
*
|
*
|
||||||
* If the canceled timer was the earliest (head) timer in the tree, the
|
* If the canceled timer was the earliest (head) timer in the tree, the
|
||||||
* expiration of the underlying hardware timer will be updated to:
|
* expiration of the underlying hardware timer will be updated to:
|
||||||
@@ -65,17 +73,18 @@
|
|||||||
* OK (0) on success; a negated errno value on failure.
|
* OK (0) on success; a negated errno value on failure.
|
||||||
*
|
*
|
||||||
* Assumptions/Notes:
|
* Assumptions/Notes:
|
||||||
* - This function acquires the global hrtimer spinlock to protect the
|
* - This function acquires the global hrtimer spinlock to protect both
|
||||||
* red-black tree and timer state.
|
* the red-black tree and the timer state.
|
||||||
* - The caller must ensure that the timer structure is not freed until
|
* - The caller must ensure that the timer structure is not freed until
|
||||||
* it is guaranteed that any running callback has returned.
|
* it is guaranteed that any running callback has returned.
|
||||||
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int hrtimer_cancel(FAR hrtimer_t *hrtimer)
|
int hrtimer_cancel(FAR hrtimer_t *hrtimer)
|
||||||
{
|
{
|
||||||
FAR hrtimer_t *first;
|
FAR hrtimer_t *first;
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
|
|
||||||
DEBUGASSERT(hrtimer != NULL);
|
DEBUGASSERT(hrtimer != NULL);
|
||||||
|
|
||||||
@@ -83,7 +92,7 @@ int hrtimer_cancel(FAR hrtimer_t *hrtimer)
|
|||||||
|
|
||||||
flags = spin_lock_irqsave(&g_hrtimer_spinlock);
|
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);
|
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.
|
/* The callback is currently executing.
|
||||||
*
|
*
|
||||||
* Mark the timer as canceled so it will not be re-armed or
|
* 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
|
* NOTE: The timer node is expected to have already been removed
|
||||||
* from the tree when the callback started executing.
|
* 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);
|
spin_unlock_irqrestore(&g_hrtimer_spinlock, flags);
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user