Skip to content

Commit

Permalink
kernel/work: Fix race under with delayed work item cancellation
Browse files Browse the repository at this point in the history
The call to unschedule_locked() would return true ("successfully
unscheduled") even in the case where the underlying z_abort_timeout()
failed (because the callback was already unpended and
in-progress/complete/about-to-be-run, remember that timeout callbacks
are unsynchronized), leading to state bugs and races against the
callback behavior.

Correctly detect that case and propagate the error to the caller.

Fixes zephyrproject-rtos#51872

Signed-off-by: Andy Ross <andyross@google.com>
  • Loading branch information
andyross authored and stephanosio committed Feb 11, 2023
1 parent bb71ad5 commit d00f9b5
Showing 1 changed file with 6 additions and 3 deletions.
9 changes: 6 additions & 3 deletions kernel/work.c
Original file line number Diff line number Diff line change
Expand Up @@ -917,10 +917,13 @@ static inline bool unschedule_locked(struct k_work_delayable *dwork)
bool ret = false;
struct k_work *work = &dwork->work;

/* If scheduled, try to cancel. */
/* If scheduled, try to cancel. If it fails, that means the
* callback has been dequeued and will inevitably run (or has
* already run), so treat that as "undelayed" and return
* false.
*/
if (flag_test_and_clear(&work->flags, K_WORK_DELAYED_BIT)) {
z_abort_timeout(&dwork->timeout);
ret = true;
ret = z_abort_timeout(&dwork->timeout) == 0;
}

return ret;
Expand Down

0 comments on commit d00f9b5

Please sign in to comment.