mirror of
https://github.com/apache/nuttx.git
synced 2026-09-13 22:20:24 +00:00
sched/wqueue: restore -ENOENT from work_cancel() for unqueued work
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
Some checks are pending
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
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 commit6f72f5481d("sched/wqueue: Refactor delayed and periodical workqueue") work_cancel() returns OK unconditionally, and commitd2e01b9055("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 <raiden00@railab.me>
This commit is contained in:
parent
221a4b2e4c
commit
5a209a853e
1 changed files with 15 additions and 1 deletions
|
|
@ -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)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue