From 39f54c15240901cde4cfdfec766d0778a476df10 Mon Sep 17 00:00:00 2001 From: wangchengdong Date: Wed, 29 Oct 2025 10:38:17 +0800 Subject: [PATCH] sched/event: Add nxevent_wait_irq() to handle the task cancel If the thread is blocked waiting on a event, then the thread must be unblocked from the evnet to handle the task cancellation. Signed-off-by: Chengdong Wang wangchengdong@lixiang.com --- sched/event/CMakeLists.txt | 3 +- sched/event/Make.defs | 1 + sched/event/event.h | 5 +- sched/event/event_post.c | 2 + sched/event/event_wait.c | 9 ++-- sched/event/event_waitirq.c | 92 +++++++++++++++++++++++++++++++++++++ sched/task/task_cancelpt.c | 12 +++++ 7 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 sched/event/event_waitirq.c diff --git a/sched/event/CMakeLists.txt b/sched/event/CMakeLists.txt index f823773953d..0791055ff2c 100644 --- a/sched/event/CMakeLists.txt +++ b/sched/event/CMakeLists.txt @@ -32,7 +32,8 @@ if(CONFIG_SCHED_EVENTS) event_destroy.c event_wait.c event_clear.c - event_getmask.c) + event_getmask.c + event_waitirq.c) endif() target_sources(sched PRIVATE ${CSRCS}) diff --git a/sched/event/Make.defs b/sched/event/Make.defs index d6e04059ed2..0c72072e69e 100644 --- a/sched/event/Make.defs +++ b/sched/event/Make.defs @@ -24,6 +24,7 @@ ifeq ($(CONFIG_SCHED_EVENTS),y) CSRCS += event_init.c event_post.c event_reset.c event_destroy.c event_wait.c event_clear.c event_getmask.c + CSRCS += event_waitirq.c endif # Include event build support diff --git a/sched/event/event.h b/sched/event/event.h index 83c477f6648..e89a26a569f 100644 --- a/sched/event/event.h +++ b/sched/event/event.h @@ -31,12 +31,13 @@ #include #include -#include #include /**************************************************************************** - * Public Type Definitions + * Public Function Definitions ****************************************************************************/ +void nxevent_wait_irq(FAR struct tcb_s *wtcb, int errcode); + #endif /* __SCHED_EVENT_EVENT_H */ diff --git a/sched/event/event_post.c b/sched/event/event_post.c index c717d58eec7..db1630cd471 100644 --- a/sched/event/event_post.c +++ b/sched/event/event_post.c @@ -118,6 +118,8 @@ int nxevent_post(FAR nxevent_t *event, nxevent_mask_t events, wtcb = wait->wtcb; + wtcb->waitobj = NULL; + /* Remove the task from waiting list */ dq_rem((FAR dq_entry_t *)wtcb, list_waitingforsignal()); diff --git a/sched/event/event_wait.c b/sched/event/event_wait.c index b9e1b7c971c..e55cb4dbe49 100644 --- a/sched/event/event_wait.c +++ b/sched/event/event_wait.c @@ -60,8 +60,8 @@ static void nxevent_timeout(wdparm_t arg) /* Get waiting tcb from parameter */ - wait = (FAR nxevent_wait_t *)(uintptr_t)arg; - wtcb = wait->wtcb; + 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. @@ -82,6 +82,8 @@ static void nxevent_timeout(wdparm_t arg) list_delete(&(wait->node)); } + wtcb->waitobj = NULL; + /* Mark the errno value for the thread. */ wtcb->errcode = ETIMEDOUT; @@ -199,13 +201,14 @@ nxevent_mask_t nxevent_tickwait_wait(FAR nxevent_t *event, /* Initialize event wait */ wtcb = this_task(); + wtcb->waitobj = (FAR void *)wait; wait->expect = events; wait->eflags = eflags; wait->wtcb = wtcb; list_add_tail(&event->list, &(wait->node)); - wd_start(&wtcb->waitdog, delay, nxevent_timeout, (uintptr_t)&wait); + wd_start(&wtcb->waitdog, delay, nxevent_timeout, (uintptr_t)wtcb); /* Remove the tcb task from the ready-to-run list. */ diff --git a/sched/event/event_waitirq.c b/sched/event/event_waitirq.c new file mode 100644 index 00000000000..6bd3dffffa1 --- /dev/null +++ b/sched/event/event_waitirq.c @@ -0,0 +1,92 @@ +/**************************************************************************** + * sched/event/event_waitirq.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "sched/sched.h" +#include "event/event.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxevent_wait_irq + * + * Description: + * An error event has occurred and the event wait must be terminated with + * an error. + * + ****************************************************************************/ + +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)); + } + + /* Remove the task from the event waiting list */ + + dq_rem((FAR dq_entry_t *)wtcb, list_waitingforsignal()); + + /* Indicate that the wait is over */ + + wtcb->waitobj = NULL; + + /* Store the error code for the thread */ + + wtcb->errcode = errcode; + + /* Add the task to the ready-to-run list and perform a context + * switch if one is needed. + */ + + if (nxsched_add_readytorun(wtcb)) + { + up_switch_context(this_task(), rtcb); + } +} diff --git a/sched/task/task_cancelpt.c b/sched/task/task_cancelpt.c index f7462a262c9..74d62c255df 100644 --- a/sched/task/task_cancelpt.c +++ b/sched/task/task_cancelpt.c @@ -67,6 +67,7 @@ #include "signal/signal.h" #include "mqueue/mqueue.h" #include "task/task.h" +#include "event/event.h" /**************************************************************************** * Public Functions @@ -165,6 +166,17 @@ bool nxnotify_cancellation(FAR struct tcb_s *tcb) nxsig_wait_irq(tcb, SIG_CANCEL_TIMEOUT, SI_USER, ECANCELED); } +#ifdef CONFIG_SCHED_EVENTS + /* If the thread is blocked waiting on a event, then the + * thread must be unblocked to handle the cancellation. + */ + + else if (tcb->task_state == TSTATE_WAIT_EVENT) + { + nxevent_wait_irq(tcb, ECANCELED); + } +#endif + #if !defined(CONFIG_DISABLE_MQUEUE) || !defined(CONFIG_DISABLE_MQUEUE_SYSV) /* If the thread is blocked waiting on a message queue, then * the thread must be unblocked to handle the cancellation.