mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
[!] 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:
parent
94cfb1180b
commit
de5973268b
8 changed files with 105 additions and 203 deletions
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue