This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 9a943e6d5a0 fix(wqueue): prevent notifier and immediate-work races
9a943e6d5a0 is described below
commit 9a943e6d5a07234e4b4347a17608911a86e5606e
Author: yushuailong <[email protected]>
AuthorDate: Fri Oct 9 18:44:08 2026 +0800
fix(wqueue): prevent notifier and immediate-work races
Remove matched notifier entries before queueing their callbacks so
NULL-qualified notifications cannot be scheduled repeatedly while a callback is
in flight.
Post immediate work while the queue lock still protects the semaphore from
concurrent queue destruction. Disable local preemption while holding the lock
so a newly awakened worker cannot preempt the submitter and spin on the same
lock.
Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <[email protected]>
---
sched/wqueue/kwork_notifier.c | 34 +++++++++++++++-------------------
sched/wqueue/kwork_queue.c | 9 ++++-----
2 files changed, 19 insertions(+), 24 deletions(-)
diff --git a/sched/wqueue/kwork_notifier.c b/sched/wqueue/kwork_notifier.c
index 8b3a3b5df40..cf4b64e96eb 100644
--- a/sched/wqueue/kwork_notifier.c
+++ b/sched/wqueue/kwork_notifier.c
@@ -152,7 +152,7 @@ static int work_notifier_key(void)
* Name: work_notifier_worker
*
* Description:
- * Forward to the real worker and free the notification.
+ * Forward to the real worker and recycle the notification entry.
*
****************************************************************************/
@@ -170,17 +170,9 @@ static void work_notifier_worker(FAR void *arg)
flags = spin_lock_irqsave(&g_notifier_lock);
- /* Remove the notification from the pending list */
+ /* Make the entry available for a subsequent notification setup. */
- notifier = work_notifier_find(notifier->key);
- if (notifier != NULL)
- {
- dq_rem(¬ifier->entry, &g_notifier_pending);
-
- /* Put the notification to the free list */
-
- dq_addlast(¬ifier->entry, &g_notifier_free);
- }
+ dq_addlast(¬ifier->entry, &g_notifier_free);
spin_unlock_irqrestore(&g_notifier_lock, flags);
}
@@ -389,17 +381,21 @@ void work_notifier_signal(enum work_evtype_e evtype,
if (info->evtype == evtype && info->qualifier == qualifier)
{
- /* Mark the notification as no longer pending */
+ /* Prevent another signal from matching this notification. */
+
+ dq_rem(¬ifier->entry, &g_notifier_pending);
- info->qualifier = NULL;
+ /* Keep the entry owned by the callback until it is recycled. */
- /* Schedule the work. The entire notifier entry is passed as an
- * argument to the work function because that function is
- * responsible for freeing the allocated memory.
- */
+ if (work_queue(info->qid, ¬ifier->work,
+ work_notifier_worker, notifier, 0) < 0)
+ {
+ /* Preserve the notification until the callback can be
+ * queued.
+ */
- work_queue(info->qid, ¬ifier->work,
- work_notifier_worker, entry, 0);
+ dq_addlast(¬ifier->entry, &g_notifier_pending);
+ }
}
}
diff --git a/sched/wqueue/kwork_queue.c b/sched/wqueue/kwork_queue.c
index 6e9b4ac1a07..a4a349951f5 100644
--- a/sched/wqueue/kwork_queue.c
+++ b/sched/wqueue/kwork_queue.c
@@ -93,11 +93,11 @@ static int work_qqueue(FAR struct kwork_wqueue_s *wqueue,
* logic or interrupt handling logic.
*/
- flags = spin_lock_irqsave(&wqueue->lock);
+ flags = spin_lock_irqsave_nopreempt(&wqueue->lock);
if (wqueue->exit)
{
- spin_unlock_irqrestore(&wqueue->lock, flags);
+ spin_unlock_irqrestore_nopreempt(&wqueue->lock, flags);
return -ESHUTDOWN;
}
@@ -144,15 +144,14 @@ static int work_qqueue(FAR struct kwork_wqueue_s *wqueue,
work_timer_reset(wqueue);
}
- spin_unlock_irqrestore(&wqueue->lock, flags);
-
if (delay == 0)
{
- /* Immediately wake up the worker thread. */
+ /* Post while the queue lock keeps the semaphore alive. */
nxsem_post(&wqueue->sem);
}
+ spin_unlock_irqrestore_nopreempt(&wqueue->lock, flags);
return OK;
}