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(&notifier->entry, &g_notifier_pending);
-
-      /* Put the notification to the free list */
-
-      dq_addlast(&notifier->entry, &g_notifier_free);
-    }
+  dq_addlast(&notifier->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(&notifier->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, &notifier->work,
+                         work_notifier_worker, notifier, 0) < 0)
+            {
+              /* Preserve the notification until the callback can be
+               * queued.
+               */
 
-          work_queue(info->qid, &notifier->work,
-                     work_notifier_worker, entry, 0);
+              dq_addlast(&notifier->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;
 }
 

Reply via email to