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 5a209a853ec sched/wqueue: restore -ENOENT from work_cancel() for 
unqueued work
5a209a853ec is described below

commit 5a209a853ec0dac623a2d5dfa81dea546b22820d
Author: raiden00pl <[email protected]>
AuthorDate: Mon Sep 7 09:05:14 2026 +0200

    sched/wqueue: restore -ENOENT from work_cancel() for unqueued work
    
    work_cancel() used to return -ENOENT when the work structure was not
    in the queue, and callers depend on that: aio_cancel() tears down the
    AIO container (file_put() + aioc_free()) only when work_cancel()
    reports success, because a work item that is not queued may already be
    executing on a worker thread (see the comment in fs/aio/aio_cancel.c).
    
    Since commit 6f72f5481d ("sched/wqueue: Refactor delayed and periodical
    workqueue") work_cancel() returns OK unconditionally, and commit
    d2e01b90553 ("sched/wqueue: harden custom queue lifecycle") kept that
    behaviour and dropped -ENOENT from the function documentation.  Under
    SMP the LTP aio_cancel tests then free the aio container and its file
    while the lpwork thread is still executing aio_write_worker() on it,
    which ends in a page fault in file_write() (f_inode == NULL) and a
    panic.
    
    Return -ENOENT again when the work is not queued, and document it.
    For the synchronous variant "not queued" alone does not tell whether
    the callback is running: the worker scan does, so report OK when a
    running callback was found and waited for, and -ENOENT only when the
    work was neither queued nor running.
    
    Assisted-by: Claude Code
    Signed-off-by: raiden00pl <[email protected]>
---
 sched/wqueue/kwork_cancel.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/sched/wqueue/kwork_cancel.c b/sched/wqueue/kwork_cancel.c
index 2329abaf708..99c7774f485 100644
--- a/sched/wqueue/kwork_cancel.c
+++ b/sched/wqueue/kwork_cancel.c
@@ -48,6 +48,7 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, 
bool sync,
 {
   irqstate_t flags;
   pid_t self = sync ? nxsched_gettid() : INVALID_PROCESS_ID;
+  int ret = -ENOENT;
 
   if (wqueue == NULL || work == NULL)
     {
@@ -83,8 +84,18 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, 
bool sync,
             {
               work_timer_reset(wqueue);
             }
+
+          ret = OK;
         }
 
+      /* Otherwise the work is not queued: either it was never queued or a
+       * worker has already dequeued it and may be executing its callback
+       * right now.  Only the scan below can tell.  Report -ENOENT if the
+       * work is neither queued nor running, so that callers (e.g.
+       * aio_cancel()) do not free resources that the callback is still
+       * using.
+       */
+
       if (sync)
         {
           for (wndx = 0; wndx < wqueue->nthreads; wndx++)
@@ -93,6 +104,7 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, 
bool sync,
                 {
                   worker[wndx].wait_count++;
                   sync_wait = &worker[wndx].wait;
+                  ret = OK;
                   break;
                 }
             }
@@ -102,7 +114,7 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, 
bool sync,
 
       if (sync_wait == NULL)
         {
-          return OK;
+          return ret;
         }
 
       nxsem_wait_uninterruptible(sync_wait);
@@ -130,6 +142,8 @@ static int work_qcancel(FAR struct kwork_wqueue_s *wqueue, 
bool sync,
  *   Zero on success, a negated errno on failure
  *
  *   -EINVAL - An invalid work queue was specified
+ *   -ENOENT - The work is not queued (and, for the sync variant, not
+ *             running either)
  *
  ****************************************************************************/
 

Reply via email to