Take critical section instead of unsafe

This commit is contained in:
Dániel Buga 2024-12-07 14:45:16 +01:00
parent c1120c7138
commit edb8f21a74
No known key found for this signature in database
3 changed files with 22 additions and 14 deletions

View File

@ -411,15 +411,6 @@ impl SyncExecutor {
self.run_queue.dequeue_all(|p| { self.run_queue.dequeue_all(|p| {
let task = p.header(); let task = p.header();
if !task.state.run_dequeue() {
// If task is not running, ignore it. This can happen in the following scenario:
// - Task gets dequeued, poll starts
// - While task is being polled, it gets woken. It gets placed in the queue.
// - Task poll finishes, returning done=true
// - RUNNING bit is cleared, but the task is already in the queue.
return;
}
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
trace::task_exec_begin(self, &p); trace::task_exec_begin(self, &p);

View File

@ -81,7 +81,16 @@ impl RunQueue {
// safety: there are no concurrent accesses to `next` // safety: there are no concurrent accesses to `next`
next = unsafe { task.header().run_queue_item.next.get() }; next = unsafe { task.header().run_queue_item.next.get() };
let run_task = task.header().state.run_dequeue();
if run_task {
// If task is not running, ignore it. This can happen in the following scenario:
// - Task gets dequeued, poll starts
// - While task is being polled, it gets woken. It gets placed in the queue.
// - Task poll finishes, returning done=true
// - RUNNING bit is cleared, but the task is already in the queue.
on_task(task); on_task(task);
} }
} }
} }
}

View File

@ -63,11 +63,19 @@ impl RunQueue {
// If the task re-enqueues itself, the `next` pointer will get overwritten. // If the task re-enqueues itself, the `next` pointer will get overwritten.
// Therefore, first read the next pointer, and only then process the task. // Therefore, first read the next pointer, and only then process the task.
// safety: we know if the task is enqueued, no one else will touch the `next` pointer. let run_task = critical_section::with(|cs| {
let cs = unsafe { CriticalSection::new() };
next = task.header().run_queue_item.next.borrow(cs).get(); next = task.header().run_queue_item.next.borrow(cs).get();
task.header().state.run_dequeue(cs)
});
if run_task {
// If task is not running, ignore it. This can happen in the following scenario:
// - Task gets dequeued, poll starts
// - While task is being polled, it gets woken. It gets placed in the queue.
// - Task poll finishes, returning done=true
// - RUNNING bit is cleared, but the task is already in the queue.
on_task(task); on_task(task);
} }
} }
} }
}