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 <liguiding1@xiaomi.com>
This commit is contained in:
ligd 2022-08-17 15:42:00 +08:00 committed by Petro Karashchenko
parent 4c19130d1d
commit bc17563a8f

View File

@ -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 */