[!] sched/event: Remove wait object dependency from event implementation

The current event implementation relies on a dedicated wait object,
    which introduces several issues:
        1. Increases memory usage
        2. Complicates the event logic
        3. Makes the API design less clean, as it requires a separate
                nxevent_tickwait_wait() function

    This patch removes the event’s dependency on the wait object
    and eliminates the nxevent_tickwait_wait() API accordingly.

    BREAKING CHANGE: this commit removed the nxevent_tickwait_wait function
    so the related docs should be updated accordingly

Signed-off-by: Chengdong Wang wangchengdong@lixiang.com
This commit is contained in:
wangchengdong 2025-10-29 11:03:46 +08:00 committed by Alan C. Assis
parent 94cfb1180b
commit de5973268b
8 changed files with 105 additions and 203 deletions

View file

@ -29,7 +29,7 @@
#include <nuttx/config.h>
#include <nuttx/list.h>
#include <nuttx/queue.h>
/****************************************************************************
* Pre-processor Definitions
@ -37,7 +37,8 @@
/* Initializers */
#define NXEVENT_INITIALIZER(e, v) {LIST_INITIAL_VALUE((e).list), (v)}
#define EVENT_WAITLIST_INITIALIZER {NULL, NULL}
#define NXEVENT_INITIALIZER(e, v) {EVENT_WAITLIST_INITIALIZER, (v)}
/* Event Wait Flags */
@ -50,26 +51,18 @@
#define NXEVENT_POST_ALL (1 << 0) /* Bit 0: Post ALL */
#define NXEVENT_POST_SET (1 << 1) /* Bit 1: Set event after post */
#define EVENT_WAITLIST(event) (&((event)->waitlist))
/****************************************************************************
* Public Type Definitions
****************************************************************************/
typedef struct nxevent_s nxevent_t;
typedef struct nxevent_wait_s nxevent_wait_t;
typedef unsigned long nxevent_mask_t;
typedef unsigned long nxevent_flags_t;
struct nxevent_wait_s
{
struct list_node node; /* Wait node of current task */
nxevent_mask_t expect; /* Expect events of wait task */
nxevent_flags_t eflags; /* Event flags of wait task */
FAR struct tcb_s *wtcb; /* The waiting task */
};
struct nxevent_s
{
struct list_node list; /* Waiting list of nxevent_wait_t */
dq_queue_t waitlist; /* Waiting list of nxevent_wait_t */
volatile nxevent_mask_t events; /* Pending Events */
};
@ -215,40 +208,6 @@ int nxevent_post(FAR nxevent_t *event, nxevent_mask_t events,
nxevent_mask_t nxevent_wait(FAR nxevent_t *event, nxevent_mask_t events,
nxevent_flags_t eflags);
/****************************************************************************
* Name: nxevent_tickwait_wait
*
* Description:
* Wait for all of the specified events for the specified tick time.
*
* This routine waits on event object event until all of the specified
* events have been delivered to the event object, or the maximum wait time
* timeout has expired. A thread may wait on up to 32 distinctly numbered
* events that are expressed as bits in a single 32-bit word.
*
* Input Parameters:
* event - Address of the event object
* wait - Address of the event wait object
* events - Set of events to wait
* - Set events to 0 will indicate wait from any events
* eflags - Events flags
* delay - Ticks to wait from the start time until the event is
* posted. If ticks is zero, then this function is equivalent
* to nxevent_trywait().
*
* Returned Value:
* This is an internal OS interface and should not be used by applications.
* Return of matching events upon success.
* 0 if matching events were not received within the specified time.
*
****************************************************************************/
nxevent_mask_t nxevent_tickwait_wait(FAR nxevent_t *event,
FAR nxevent_wait_t *wait,
nxevent_mask_t events,
nxevent_flags_t eflags,
uint32_t delay);
/****************************************************************************
* Name: nxevent_tickwait
*

View file

@ -42,6 +42,7 @@
#include <nuttx/irq.h>
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
#include <nuttx/event.h>
#include <nuttx/queue.h>
#include <nuttx/wdog.h>
#include <nuttx/fs/fs.h>
@ -653,6 +654,11 @@ struct tcb_s
FAR void *waitobj; /* Object thread waiting on */
#ifdef CONFIG_SCHED_EVENTS
nxevent_mask_t expect; /* expected event mask */
nxevent_flags_t eflags; /* event wait flags */
#endif
/* POSIX Signal Control Fields ********************************************/
sigset_t sigprocmask; /* Signals that are blocked */

View file

@ -30,9 +30,9 @@
#include <nuttx/config.h>
#include <nuttx/irq.h>
#include <nuttx/list.h>
#include <nuttx/queue.h>
#include <nuttx/event.h>
#include <nuttx/sched.h>
/****************************************************************************
* Public Function Definitions

View file

@ -49,5 +49,5 @@
void nxevent_init(FAR nxevent_t *event, nxevent_mask_t events)
{
event->events = events;
list_initialize(&event->list);
dq_init(EVENT_WAITLIST(event));
}

View file

@ -33,10 +33,6 @@
#include "event.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
@ -45,28 +41,18 @@
* Name: nxevent_post
*
* Description:
* Post one or more events to an event object.
*
* This routine posts one or more events to an event object. All tasks
* waiting on the event object event whose waiting conditions become
* met by this posting immediately unpend.
*
* Posting differs from setting in that posted events are merged together
* with the current set of events tracked by the event object.
* Post one or more events to the specified event object. This function
* wakes up any tasks that are waiting for the posted events, depending
* on their wait condition (any/all).
*
* Input Parameters:
* event - Address of the event object
* events - Set of events to post to event
* - Set events to 0 will be considered as any,
* waking up the waiting thread immediately.
*
* event - Pointer to the event object.
* events - Bitmask of events to post.
* eflags - Posting behavior flags, such as:
* NXEVENT_POST_SET: overwrite existing events.
* NXEVENT_POST_ALL: wake all waiting tasks.
* Returned Value:
* This is an internal OS interface and should not be used by applications.
* It follows the NuttX internal error return policy: Zero (OK) is
* returned on success. A negated errno value is returned on failure.
*
* Assumptions:
* This function may be called from an interrupt handler.
* OK on success; -EINVAL if the event pointer is NULL.
*
****************************************************************************/
@ -76,9 +62,10 @@ int nxevent_post(FAR nxevent_t *event, nxevent_mask_t events,
FAR struct tcb_s *wtcb;
FAR struct tcb_s *rtcb;
nxevent_mask_t clear = 0;
FAR nxevent_wait_t *wait;
FAR nxevent_wait_t *tmp;
FAR dq_entry_t *entry;
FAR dq_entry_t *tmp;
irqstate_t flags;
dq_queue_t *waitlist;
bool waitall;
bool postall;
bool need_switch;
@ -99,56 +86,51 @@ int nxevent_post(FAR nxevent_t *event, nxevent_mask_t events,
event->events |= events ? events : ~0;
}
need_switch = false;
rtcb = this_task();
postall = ((eflags & NXEVENT_POST_ALL) != 0);
rtcb = this_task();
waitlist = EVENT_WAITLIST(event);
if (!list_is_empty(&event->list))
dq_for_every_safe(waitlist, entry, tmp)
{
postall = ((eflags & NXEVENT_POST_ALL) != 0);
wtcb = (FAR struct tcb_s *)entry;
waitall = ((wtcb->eflags & NXEVENT_WAIT_ALL) != 0);
list_for_every_entry_safe(&event->list, wait, tmp,
nxevent_wait_t, node)
/* Check if this task's wait condition is satisfied */
if ((!waitall && (wtcb->expect & event->events) != 0) ||
(waitall && ((wtcb->expect & event->events) == wtcb->expect)))
{
waitall = ((wait->eflags & NXEVENT_WAIT_ALL) != 0);
dq_rem((FAR dq_entry_t *)wtcb, waitlist);
if ((!waitall && ((wait->expect & event->events) != 0)) ||
(waitall && ((wait->expect & event->events) == wait->expect)))
/* Stop timeout watchdog */
wd_cancel(&wtcb->waitdog);
wtcb->waitobj = NULL;
/* Make task ready-to-run */
if (nxsched_add_readytorun(wtcb) && !need_switch)
{
list_delete(&wait->node);
/* Higher priority task is ready */
wtcb = wait->wtcb;
need_switch = true;
}
wtcb->waitobj = NULL;
/* If waiting for any event, mark received ones */
/* Remove the task from waiting list */
if (!waitall)
{
wtcb->expect &= event->events;
}
dq_rem((FAR dq_entry_t *)wtcb, list_waitingforsignal());
if ((wtcb->eflags & NXEVENT_WAIT_NOCLEAR) == 0)
{
clear |= wtcb->expect;
}
wd_cancel(&wtcb->waitdog);
/* Add the task to ready-to-run task list, and
* perform the context switch if one is needed
*/
if (nxsched_add_readytorun(wtcb) && !need_switch)
{
need_switch = true;
}
if (!waitall)
{
wait->expect &= event->events;
}
if ((wait->eflags & NXEVENT_WAIT_NOCLEAR) == 0)
{
clear |= wait->expect;
}
if (!postall && (event->events & ~clear) == 0)
{
break;
}
if (!postall && (event->events & ~clear) == 0)
{
break;
}
}

View file

@ -55,13 +55,11 @@
static void nxevent_timeout(wdparm_t arg)
{
FAR struct tcb_s *wtcb;
FAR nxevent_wait_t *wait;
irqstate_t flags;
/* Get waiting tcb from parameter */
wtcb = (FAR struct tcb_s *)(uintptr_t)arg;
wait = wtcb->waitobj;
/* We must be in a critical section in order to call up_switch_context()
* below.
@ -86,7 +84,7 @@ static void nxevent_timeout(wdparm_t arg)
****************************************************************************/
/****************************************************************************
* Name: nxevent_tickwait_wait
* Name: nxevent_tickwait
*
* Description:
* Wait for all of the specified events for the specified tick time.
@ -98,7 +96,6 @@ static void nxevent_timeout(wdparm_t arg)
*
* Input Parameters:
* event - Address of the event object
* wait - Address of the event wait object
* events - Set of events to wait
* - Set events to 0 will indicate wait from any events
* eflags - Events flags
@ -113,18 +110,14 @@ static void nxevent_timeout(wdparm_t arg)
*
****************************************************************************/
nxevent_mask_t nxevent_tickwait_wait(FAR nxevent_t *event,
FAR nxevent_wait_t *wait,
nxevent_mask_t events,
nxevent_flags_t eflags,
uint32_t delay)
nxevent_mask_t nxevent_tickwait(FAR nxevent_t *event, nxevent_mask_t events,
nxevent_flags_t eflags, uint32_t delay)
{
FAR struct tcb_s *wtcb;
FAR struct tcb_s *rtcb = this_task();
irqstate_t flags;
bool waitany;
DEBUGASSERT(event != NULL && wait != NULL &&
up_interrupt_context() == false);
DEBUGASSERT(event != NULL && up_interrupt_context() == false);
waitany = ((eflags & NXEVENT_WAIT_ALL) == 0);
@ -172,43 +165,48 @@ nxevent_mask_t nxevent_tickwait_wait(FAR nxevent_t *event,
else
{
/* Initialize event wait */
/* Start the watchdog with interrupts still disabled */
wtcb = this_task();
wtcb->waitobj = (FAR void *)wait;
wait->expect = events;
wait->eflags = eflags;
wait->wtcb = wtcb;
wd_start(&rtcb->waitdog, delay, nxevent_timeout, (uintptr_t)rtcb);
list_add_tail(&event->list, &(wait->node));
wd_start(&wtcb->waitdog, delay, nxevent_timeout, (uintptr_t)wtcb);
/* Remove the tcb task from the ready-to-run list. */
nxsched_remove_self(wtcb);
/* Set the errno value to zero (preserving the original errno)
* value).
/* First, verify that the task is not already waiting on a
* event
*/
wtcb->errcode = OK;
DEBUGASSERT(rtcb->waitobj == NULL);
/* Add the task to the specified blocked task list */
/* Save the waited on event in the TCB */
wtcb->task_state = TSTATE_WAIT_EVENT;
rtcb->waitobj = event;
rtcb->expect = events;
rtcb->eflags = eflags;
dq_addlast((FAR dq_entry_t *)wtcb, list_waitingforsignal());
/* Set the errno value to zero (preserving the original errno)
* value). We reuse the per-thread errno to pass information
* between nxevent_wait_irq() and this functions.
*/
rtcb->errcode = OK;
/* Add the TCB to the prioritized event wait queue, after
* checking this is not the idle task - descheduling that
* isn't going to end well.
*/
DEBUGASSERT(!is_idle_task(rtcb));
nxsched_remove_self(rtcb);
rtcb->task_state = TSTATE_WAIT_EVENT;
nxsched_add_prioritized(rtcb, EVENT_WAITLIST(event));
/* Now, perform the context switch if one is needed */
up_switch_context(this_task(), wtcb);
up_switch_context(this_task(), rtcb);
DEBUGASSERT(!list_in_list(&(wait->node)));
if (wtcb->errcode == OK)
if (rtcb->errcode == OK)
{
events = wait->expect;
events = rtcb->expect;
}
else
{
@ -221,41 +219,6 @@ nxevent_mask_t nxevent_tickwait_wait(FAR nxevent_t *event,
return events;
}
/****************************************************************************
* Name: nxevent_tickwait
*
* Description:
* Wait for all of the specified events for the specified tick time.
*
* This routine waits on event object event until all of the specified
* events have been delivered to the event object, or the maximum wait time
* timeout has expired. A thread may wait on up to 32 distinctly numbered
* events that are expressed as bits in a single 32-bit word.
*
* Input Parameters:
* event - Address of the event object
* events - Set of events to wait
* - Set events to 0 will indicate wait from any events
* eflags - Events flags
* delay - Ticks to wait from the start time until the event is
* posted. If ticks is zero, then this function is equivalent
* to nxevent_trywait().
*
* Returned Value:
* This is an internal OS interface and should not be used by applications.
* Return of matching events upon success.
* 0 if matching events were not received within the specified time.
*
****************************************************************************/
nxevent_mask_t nxevent_tickwait(FAR nxevent_t *event, nxevent_mask_t events,
nxevent_flags_t eflags, uint32_t delay)
{
nxevent_wait_t wait;
return nxevent_tickwait_wait(event, &wait, events, eflags, delay);
}
/****************************************************************************
* Name: nxevent_wait
*

View file

@ -51,27 +51,12 @@
void nxevent_wait_irq(FAR struct tcb_s *wtcb, int errcode)
{
/* It is possible that an interrupt/context switch beat us to the punch
* and already changed the task's state.
*/
DEBUGASSERT(wtcb != NULL);
FAR struct tcb_s *rtcb = this_task();
FAR nxevent_wait_t *wait = wtcb->waitobj;
DEBUGASSERT(wait != NULL);
/* Remove the wait structure from the event's waiting list */
if (list_in_list(&(wait->node)))
{
list_delete(&(wait->node));
}
FAR nxevent_t *event = wtcb->waitobj;
/* Remove the task from the event waiting list */
dq_rem((FAR dq_entry_t *)wtcb, list_waitingforsignal());
dq_rem((FAR dq_entry_t *)wtcb, EVENT_WAITLIST(event));
/* Indicate that the wait is over */

View file

@ -270,6 +270,13 @@ static void tasklist_initialize(void)
tlist[TSTATE_WAIT_SEM].attr = TLIST_ATTR_PRIORITIZED |
TLIST_ATTR_OFFSET;
#ifdef CONFIG_SCHED_EVENTS
/* TSTATE_WAIT_EVENT */
tlist[TSTATE_WAIT_EVENT].list = (FAR void *)offsetof(nxevent_t, waitlist);
tlist[TSTATE_WAIT_EVENT].attr = TLIST_ATTR_PRIORITIZED |
TLIST_ATTR_OFFSET;
#endif
/* TSTATE_WAIT_SIG */
tlist[TSTATE_WAIT_SIG].list = list_waitingforsignal();