Rollup merge of #93843 - solid-rs:fix-kmc-solid-condvar, r=m-ou-se

kmc-solid: Fix wait queue manipulation errors in the `Condvar` implementation

This PR fixes a number of bugs in the `Condvar` wait queue implementation used by the [`*-kmc-solid_*`](https://doc.rust-lang.org/nightly/rustc/platform-support/kmc-solid.html) Tier 3 targets. These bugs can occur when there are multiple threads waiting on the same `Condvar` and sometimes manifest as an `unwrap` failure.
This commit is contained in:
Matthias Krüger 2022-02-10 12:10:02 +01:00 committed by GitHub
commit 8c60f44877
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -15,10 +15,12 @@ unsafe impl Sync for Condvar {}
pub type MovableCondvar = Condvar; pub type MovableCondvar = Condvar;
impl Condvar { impl Condvar {
#[inline]
pub const fn new() -> Condvar { pub const fn new() -> Condvar {
Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) } Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) }
} }
#[inline]
pub unsafe fn init(&mut self) {} pub unsafe fn init(&mut self) {}
pub unsafe fn notify_one(&self) { pub unsafe fn notify_one(&self) {
@ -190,7 +192,7 @@ pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull<Waiter>) {
let insert_after = { let insert_after = {
let mut cursor = head.last; let mut cursor = head.last;
loop { loop {
if waiter.priority <= cursor.as_ref().priority { if waiter.priority >= cursor.as_ref().priority {
// `cursor` and all previous waiters have the same or higher // `cursor` and all previous waiters have the same or higher
// priority than `current_task_priority`. Insert the new // priority than `current_task_priority`. Insert the new
// waiter right after `cursor`. // waiter right after `cursor`.
@ -206,7 +208,7 @@ pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull<Waiter>) {
if let Some(mut insert_after) = insert_after { if let Some(mut insert_after) = insert_after {
// Insert `waiter` after `insert_after` // Insert `waiter` after `insert_after`
let insert_before = insert_after.as_ref().prev; let insert_before = insert_after.as_ref().next;
waiter.prev = Some(insert_after); waiter.prev = Some(insert_after);
insert_after.as_mut().next = Some(waiter_ptr); insert_after.as_mut().next = Some(waiter_ptr);
@ -214,6 +216,8 @@ pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull<Waiter>) {
waiter.next = insert_before; waiter.next = insert_before;
if let Some(mut insert_before) = insert_before { if let Some(mut insert_before) = insert_before {
insert_before.as_mut().prev = Some(waiter_ptr); insert_before.as_mut().prev = Some(waiter_ptr);
} else {
head.last = waiter_ptr;
} }
} else { } else {
// Insert `waiter` to the front // Insert `waiter` to the front
@ -240,11 +244,11 @@ pub unsafe fn remove(&mut self, mut waiter_ptr: NonNull<Waiter>) -> bool {
match (waiter.prev, waiter.next) { match (waiter.prev, waiter.next) {
(Some(mut prev), Some(mut next)) => { (Some(mut prev), Some(mut next)) => {
prev.as_mut().next = Some(next); prev.as_mut().next = Some(next);
next.as_mut().next = Some(prev); next.as_mut().prev = Some(prev);
} }
(None, Some(mut next)) => { (None, Some(mut next)) => {
head.first = next; head.first = next;
next.as_mut().next = None; next.as_mut().prev = None;
} }
(Some(mut prev), None) => { (Some(mut prev), None) => {
prev.as_mut().next = None; prev.as_mut().next = None;
@ -271,6 +275,7 @@ pub unsafe fn is_queued(&self, waiter: NonNull<Waiter>) -> bool {
unsafe { waiter.as_ref().task != 0 } unsafe { waiter.as_ref().task != 0 }
} }
#[inline]
pub fn pop_front(&mut self) -> Option<abi::ID> { pub fn pop_front(&mut self) -> Option<abi::ID> {
unsafe { unsafe {
let head = self.head.as_mut()?; let head = self.head.as_mut()?;