mirror of
https://github.com/apache/nuttx.git
synced 2026-05-23 14:58:13 +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_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
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user