This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 735e4890708013c611b4c63c64d3fc1bb3436cdb Author: wangchengdong <[email protected]> AuthorDate: Wed Oct 29 10:37:51 2025 +0800 [!] sched/event: Replace semaphore with direct scheduler operations in event The current event implementation uses semaphores for wait and post operations. Since semaphores are relatively heavy-weight and intended for resource-based synchronization, this is suboptimal. So this patch replaced the semaphore-based mechanism with direct scheduler operations to improve performance and reduce memory footprint. This patch also introduce a new task state TSTATE_WAIT_EVENT to indicate the task is waiting for a event. BREAKING CHANGE: This commit introduced a new task state TSTATE_WAIT_EVENT so apps/nshlib/, procfs/ and tools/pynuttx/nxgdb/ are needed to be updated accordingly. Signed-off-by: Chengdong Wang [email protected] --- include/nuttx/event.h | 3 +- include/nuttx/sched.h | 3 ++ sched/event/event_post.c | 40 ++++++++++++--- sched/event/event_wait.c | 125 ++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 140 insertions(+), 31 deletions(-) diff --git a/include/nuttx/event.h b/include/nuttx/event.h index 365443c8664..569a6b951b1 100644 --- a/include/nuttx/event.h +++ b/include/nuttx/event.h @@ -30,7 +30,6 @@ #include <nuttx/config.h> #include <nuttx/list.h> -#include <nuttx/semaphore.h> /**************************************************************************** * Pre-processor Definitions @@ -65,7 +64,7 @@ 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 */ - sem_t sem; /* Wait sem of current task */ + FAR struct tcb_s *wtcb; /* The waiting task */ }; struct nxevent_s diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 34308781ce1..53490bc7601 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -253,6 +253,9 @@ enum tstate_e TSTATE_TASK_INACTIVE, /* BLOCKED - Initialized but not yet activated */ TSTATE_WAIT_SEM, /* BLOCKED - Waiting for a semaphore */ TSTATE_WAIT_SIG, /* BLOCKED - Waiting for a signal */ +#ifdef CONFIG_SCHED_EVENTS + TSTATE_WAIT_EVENT, /* BLOCKED - Waiting for a event */ +#endif #if !defined(CONFIG_DISABLE_MQUEUE) || !defined(CONFIG_DISABLE_MQUEUE_SYSV) TSTATE_WAIT_MQNOTEMPTY, /* BLOCKED - Waiting for a MQ to become not empty. */ TSTATE_WAIT_MQNOTFULL, /* BLOCKED - Waiting for a MQ to become not full. */ diff --git a/sched/event/event_post.c b/sched/event/event_post.c index 07b9f0b4f23..c717d58eec7 100644 --- a/sched/event/event_post.c +++ b/sched/event/event_post.c @@ -24,7 +24,12 @@ * Included Files ****************************************************************************/ -#include <nuttx/sched.h> +#include <nuttx/config.h> + +#include <nuttx/irq.h> +#include <nuttx/clock.h> + +#include "sched/sched.h" #include "event.h" @@ -68,13 +73,15 @@ int nxevent_post(FAR nxevent_t *event, nxevent_mask_t events, nxevent_flags_t eflags) { + 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; irqstate_t flags; bool waitall; bool postall; - int ret = 0; + bool need_switch; if (event == NULL) { @@ -92,6 +99,9 @@ int nxevent_post(FAR nxevent_t *event, nxevent_mask_t events, event->events |= events ? events : ~0; } + need_switch = false; + rtcb = this_task(); + if (!list_is_empty(&event->list)) { postall = ((eflags & NXEVENT_POST_ALL) != 0); @@ -106,10 +116,21 @@ int nxevent_post(FAR nxevent_t *event, nxevent_mask_t events, { list_delete(&wait->node); - ret = nxsem_post(&wait->sem); - if (ret < 0) + wtcb = wait->wtcb; + + /* Remove the task from waiting list */ + + dq_rem((FAR dq_entry_t *)wtcb, list_waitingforsignal()); + + 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) { - continue; + need_switch = true; } if (!waitall) @@ -135,7 +156,14 @@ int nxevent_post(FAR nxevent_t *event, nxevent_mask_t events, } } + if (need_switch) + { + /* Switch context to the highest priority ready-to-run task */ + + up_switch_context(this_task(), rtcb); + } + leave_critical_section(flags); - return ret; + return OK; } diff --git a/sched/event/event_wait.c b/sched/event/event_wait.c index 04d62cee249..b9e1b7c971c 100644 --- a/sched/event/event_wait.c +++ b/sched/event/event_wait.c @@ -24,10 +24,87 @@ * Included Files ****************************************************************************/ -#include <nuttx/sched.h> +#include <nuttx/config.h> + +#include <nuttx/irq.h> +#include <nuttx/clock.h> + +#include "sched/sched.h" #include "event.h" +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxevent_timeout + * + * Description: + * A timeout elapsed while waiting for timeout. + * + * Assumptions: + * This function executes in the context of the timer interrupt handler. + * Local interrupts are assumed to be disabled on entry. + * + * Input Parameters: + * arg - Parameter to pass to wdentry. + * + ****************************************************************************/ + +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 */ + + wait = (FAR nxevent_wait_t *)(uintptr_t)arg; + wtcb = wait->wtcb; + + /* We must be in a critical section in order to call up_switch_context() + * below. + */ + + flags = enter_critical_section(); + + /* There may be a race condition -- make sure the task is + * still waiting for a signal + */ + + if (wtcb->task_state == TSTATE_WAIT_EVENT) + { + /* Remove the wait from the event's waiting list */ + + if (list_in_list(&(wait->node))) + { + list_delete(&(wait->node)); + } + + /* Mark the errno value for the thread. */ + + wtcb->errcode = ETIMEDOUT; + + FAR struct tcb_s *rtcb = this_task(); + + /* Remove the task from waiting list */ + + dq_rem((FAR dq_entry_t *)wtcb, list_waitingforsignal()); + + /* Add the task to ready-to-run task list, and + * perform the context switch if one is needed + */ + + if (nxsched_add_readytorun(wtcb)) + { + up_switch_context(this_task(), rtcb); + } + } + + leave_critical_section(flags); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -66,9 +143,9 @@ nxevent_mask_t nxevent_tickwait_wait(FAR nxevent_t *event, nxevent_flags_t eflags, uint32_t delay) { + FAR struct tcb_s *wtcb; irqstate_t flags; bool waitany; - int ret; DEBUGASSERT(event != NULL && wait != NULL && up_interrupt_context() == false); @@ -121,41 +198,43 @@ nxevent_mask_t nxevent_tickwait_wait(FAR nxevent_t *event, { /* Initialize event wait */ - nxsem_init(&(wait->sem), 0, 0); + wtcb = this_task(); wait->expect = events; wait->eflags = eflags; + wait->wtcb = wtcb; list_add_tail(&event->list, &(wait->node)); - leave_critical_section(flags); - /* Wait for the event */ + wd_start(&wtcb->waitdog, delay, nxevent_timeout, (uintptr_t)&wait); - if (delay == UINT32_MAX) - { - ret = nxsem_wait_uninterruptible(&(wait->sem)); - } - else - { - ret = nxsem_tickwait_uninterruptible(&(wait->sem), delay); - } + /* 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). + */ - /* Destroy local variables */ + wtcb->errcode = OK; - nxsem_destroy(&(wait->sem)); + /* Add the task to the specified blocked task list */ - flags = enter_critical_section(); - if (ret == 0) + wtcb->task_state = TSTATE_WAIT_EVENT; + + dq_addlast((FAR dq_entry_t *)wtcb, list_waitingforsignal()); + + /* Now, perform the context switch if one is needed */ + + up_switch_context(this_task(), wtcb); + + DEBUGASSERT(!list_in_list(&(wait->node))); + + if (wtcb->errcode == OK) { events = wait->expect; - DEBUGASSERT(!list_in_list(&(wait->node))); } else { - if (list_in_list(&(wait->node))) - { - list_delete(&(wait->node)); - } - events = 0; } }
