From bc17563a8f40dd2ce93f47ca0a537f4b34c45b02 Mon Sep 17 00:00:00 2001 From: ligd Date: Wed, 17 Aug 2022 15:42:00 +0800 Subject: [PATCH] wqueue: fix race-condition on work_queue CPU0 CPU1 work_queue(a) work_queue(a) -> work_cancel(a) -> work_cancel(a) -> enter_critical() -> sq_addlast(a) -> leave_critical() -> enter_critical() -> sq_addlast(a) // double add, wrong -> leave_critical() Also, this happens in mulit-threads in one CPU. Fix: work_cancel() should in critical section. Signed-off-by: ligd --- sched/wqueue/kwork_queue.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sched/wqueue/kwork_queue.c b/sched/wqueue/kwork_queue.c index 2a62b68b83b..8890370d646 100644 --- a/sched/wqueue/kwork_queue.c +++ b/sched/wqueue/kwork_queue.c @@ -110,16 +110,16 @@ int work_queue(int qid, FAR struct work_s *work, worker_t worker, irqstate_t flags; int ret = OK; - /* Remove the entry from the timer and work queue. */ - - work_cancel(qid, work); - /* Interrupts are disabled so that this logic can be called from with * task logic or from interrupt handling logic. */ flags = enter_critical_section(); + /* Remove the entry from the timer and work queue. */ + + work_cancel(qid, work); + /* Initialize the work structure. */ work->worker = worker; /* Work callback. non-NULL means queued */