Skip to content

Commit d7a763d

Browse files
committed
Handle FUTEX_OWNER_DIED properly
1 parent 20c7b2c commit d7a763d

File tree

16 files changed

+88
-66
lines changed

16 files changed

+88
-66
lines changed

library/std/src/sync/mutex.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,11 @@ impl<T: ?Sized> Mutex<T> {
313313
/// ```
314314
#[stable(feature = "rust1", since = "1.0.0")]
315315
pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
316-
unsafe {
317-
self.inner.lock();
318-
MutexGuard::new(self)
316+
if self.inner.lock() == sys::MutexState::Poisoned {
317+
self.poison.set();
319318
}
319+
320+
unsafe { MutexGuard::new(self) }
320321
}
321322

322323
/// Attempts to acquire this lock.

library/std/src/sync/poison.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ impl Flag {
7575
#[cfg(panic = "unwind")]
7676
self.failed.store(false, Ordering::Relaxed)
7777
}
78+
79+
#[inline]
80+
pub fn set(&self) {
81+
#[cfg(panic = "unwind")]
82+
self.failed.store(true, Ordering::Relaxed)
83+
}
7884
}
7985

8086
#[derive(Clone)]

library/std/src/sync/reentrant_lock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ impl<T: ?Sized> ReentrantLock<T> {
289289
if self.owner.contains(this_thread) {
290290
self.increment_lock_count().expect("lock count overflow in reentrant mutex");
291291
} else {
292-
self.mutex.lock();
292+
let _ = self.mutex.lock();
293293
self.owner.set(Some(this_thread));
294294
debug_assert_eq!(*self.lock_count.get(), 0);
295295
*self.lock_count.get() = 1;

library/std/src/sys/pal/unix/pi_futex.rs

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
#![cfg(any(target_os = "linux", target_os = "android"))]
22

3+
use crate::io;
4+
use crate::ptr::null;
35
use crate::sync::atomic::AtomicU32;
46
use crate::sys::cvt;
5-
use crate::sys::os::errno;
6-
use crate::{io, ptr};
7-
8-
pub enum FutexLockError {
9-
TryAgain,
10-
DeadLock,
11-
Other(io::Error),
12-
}
137

148
pub const fn unlocked() -> u32 {
159
0
@@ -23,25 +17,26 @@ pub fn is_contended(futex_val: u32) -> bool {
2317
(futex_val & libc::FUTEX_WAITERS) != 0
2418
}
2519

26-
pub fn futex_lock(futex: &AtomicU32) -> Result<(), FutexLockError> {
27-
if (unsafe {
28-
libc::syscall(
29-
libc::SYS_futex,
30-
futex as *const AtomicU32,
31-
libc::FUTEX_LOCK_PI | libc::FUTEX_PRIVATE_FLAG,
32-
0,
33-
ptr::null::<u32>(),
34-
// remaining args are unused
35-
)
36-
} == -1)
37-
{
38-
Err(match errno() {
39-
libc::EAGAIN | libc::EINTR => FutexLockError::TryAgain,
40-
libc::EDEADLK => FutexLockError::DeadLock,
41-
errno => FutexLockError::Other(io::Error::from_raw_os_error(errno)),
42-
})
43-
} else {
44-
Ok(())
20+
pub fn is_owned_died(futex_val: u32) -> bool {
21+
(futex_val & libc::FUTEX_OWNER_DIED) != 0
22+
}
23+
24+
pub fn futex_lock(futex: &AtomicU32) -> io::Result<()> {
25+
loop {
26+
match cvt(unsafe {
27+
libc::syscall(
28+
libc::SYS_futex,
29+
futex as *const AtomicU32,
30+
libc::FUTEX_LOCK_PI | libc::FUTEX_PRIVATE_FLAG,
31+
0,
32+
null::<u32>(),
33+
// remaining args are unused
34+
)
35+
}) {
36+
Ok(_) => return Ok(()),
37+
Err(e) if e.raw_os_error() == Some(libc::EINTR) => continue,
38+
Err(e) => return Err(e),
39+
}
4540
}
4641
}
4742

library/std/src/sys/sync/condvar/futex.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl Condvar {
5050
let r = futex_wait(&self.futex, futex_value, timeout);
5151

5252
// Lock the mutex again.
53-
mutex.lock();
53+
let _ = mutex.lock();
5454

5555
r
5656
}

library/std/src/sys/sync/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod rwlock;
66
mod thread_parking;
77

88
pub use condvar::Condvar;
9-
pub use mutex::Mutex;
9+
pub use mutex::{Mutex, MutexState};
1010
pub use once::{Once, OnceState};
1111
#[allow(unused)] // Only used on some platforms.
1212
use once_box::OnceBox;

library/std/src/sys/sync/mutex/fuchsia.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
//!
3838
//! [mutex in Fuchsia's libsync]: https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/ulib/sync/mutex.c
3939
40+
use super::MutexState;
4041
use crate::sync::atomic::AtomicU32;
4142
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
4243
use crate::sys::futex::zircon::{
@@ -88,7 +89,7 @@ impl Mutex {
8889
}
8990

9091
#[inline]
91-
pub fn lock(&self) {
92+
pub fn lock(&self) -> MutexState {
9293
let thread_self = unsafe { zx_thread_self() };
9394
if let Err(state) =
9495
self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed)
@@ -97,6 +98,7 @@ impl Mutex {
9798
self.lock_contested(state, thread_self);
9899
}
99100
}
101+
MutexState::Normal
100102
}
101103

102104
/// # Safety

library/std/src/sys/sync/mutex/futex.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::MutexState;
12
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
23
use crate::sys::futex::{self, futex_wait, futex_wake};
34

@@ -24,10 +25,11 @@ impl Mutex {
2425
}
2526

2627
#[inline]
27-
pub fn lock(&self) {
28+
pub fn lock(&self) -> MutexState {
2829
if self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_err() {
2930
self.lock_contended();
3031
}
32+
MutexState::Normal
3133
}
3234

3335
#[cold]

library/std/src/sys/sync/mutex/itron.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! `TA_INHERIT` are available.
33
#![forbid(unsafe_op_in_unsafe_fn)]
44

5+
use super::MutexState;
56
use crate::sys::pal::itron::abi;
67
use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting, fail};
78
use crate::sys::pal::itron::spin::SpinIdOnceCell;
@@ -37,9 +38,10 @@ impl Mutex {
3738
}
3839
}
3940

40-
pub fn lock(&self) {
41+
pub fn lock(&self) -> MutexState {
4142
let mtx = self.raw();
4243
expect_success(unsafe { abi::loc_mtx(mtx) }, &"loc_mtx");
44+
MutexState::Normal
4345
}
4446

4547
pub unsafe fn unlock(&self) {

library/std/src/sys/sync/mutex/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
#[derive(Copy, Clone, Eq, PartialEq)]
2+
pub enum MutexState {
3+
Normal,
4+
Poisoned,
5+
}
6+
17
cfg_if::cfg_if! {
28
if #[cfg(any(
39
target_os = "linux",

library/std/src/sys/sync/mutex/no_threads.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::MutexState;
12
use crate::cell::Cell;
23

34
pub struct Mutex {
@@ -16,8 +17,9 @@ impl Mutex {
1617
}
1718

1819
#[inline]
19-
pub fn lock(&self) {
20+
pub fn lock(&self) -> MutexState {
2021
assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex");
22+
MutexState::Normal
2123
}
2224

2325
#[inline]

library/std/src/sys/sync/mutex/pi_futex.rs

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
use super::MutexState;
12
use crate::sync::atomic::AtomicU32;
23
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
34
use crate::sys::pi_futex as pi;
5+
46
pub struct Mutex {
57
futex: AtomicU32,
68
}
@@ -17,36 +19,30 @@ impl Mutex {
1719
}
1820

1921
#[inline]
20-
pub fn lock(&self) {
22+
pub fn lock(&self) -> MutexState {
2123
if self.futex.compare_exchange(pi::unlocked(), pi::locked(), Acquire, Relaxed).is_err() {
22-
self.lock_contended();
24+
self.lock_contended()
25+
} else {
26+
MutexState::Normal
2327
}
2428
}
2529

2630
#[cold]
27-
fn lock_contended(&self) {
28-
loop {
29-
// Spin first to speed things up if the lock is released quickly.
30-
let state = self.spin();
31-
32-
// If it's unlocked now, attempt to take the lock.
33-
if state == pi::unlocked() {
34-
if self.try_lock() {
35-
return;
36-
}
37-
};
31+
fn lock_contended(&self) -> MutexState {
32+
// Spin first to speed things up if the lock is released quickly.
33+
let state = self.spin();
3834

39-
if let Err(e) = pi::futex_lock(&self.futex) {
40-
const MSG_PREFIX: &str = "failed to lock mutex";
41-
match e {
42-
pi::FutexLockError::TryAgain => (), // Try again in this case.
43-
pi::FutexLockError::DeadLock => panic!("{MSG_PREFIX}: deadlock detected"),
44-
pi::FutexLockError::Other(e) => panic!("{MSG_PREFIX}: {e}"),
45-
}
46-
} else {
47-
return;
35+
// If it's unlocked now, attempt to take the lock.
36+
if state == pi::unlocked() {
37+
if self.try_lock() {
38+
return MutexState::Normal;
4839
}
49-
}
40+
};
41+
42+
pi::futex_lock(&self.futex).expect("failed to lock mutex");
43+
44+
let state = self.futex.load(Relaxed);
45+
if pi::is_owned_died(state) { MutexState::Poisoned } else { MutexState::Normal }
5046
}
5147

5248
fn spin(&self) -> u32 {

library/std/src/sys/sync/mutex/pthread.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::MutexState;
12
use crate::cell::UnsafeCell;
23
use crate::io::Error;
34
use crate::mem::{MaybeUninit, forget};
@@ -102,7 +103,7 @@ impl Mutex {
102103
}
103104

104105
#[inline]
105-
pub fn lock(&self) {
106+
pub fn lock(&self) -> MutexState {
106107
#[cold]
107108
#[inline(never)]
108109
fn fail(r: i32) -> ! {
@@ -121,6 +122,8 @@ impl Mutex {
121122
if r != 0 {
122123
fail(r)
123124
}
125+
126+
MutexState::Normal
124127
}
125128

126129
#[inline]

library/std/src/sys/sync/mutex/sgx.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::MutexState;
12
use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable, try_lock_or_false};
23
use crate::sys::sync::OnceBox;
34

@@ -17,7 +18,7 @@ impl Mutex {
1718
}
1819

1920
#[inline]
20-
pub fn lock(&self) {
21+
pub fn lock(&self) -> MutexState {
2122
let mut guard = self.get().lock();
2223
if *guard.lock_var() {
2324
// Another thread has the lock, wait
@@ -27,6 +28,7 @@ impl Mutex {
2728
// We are just now obtaining the lock
2829
*guard.lock_var_mut() = true;
2930
}
31+
MutexState::Normal
3032
}
3133

3234
#[inline]

library/std/src/sys/sync/mutex/windows7.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
1515
//! is that there are no guarantees of fairness.
1616
17+
use super::MutexState;
1718
use crate::cell::UnsafeCell;
1819
use crate::sys::c;
1920

@@ -36,10 +37,11 @@ impl Mutex {
3637
}
3738

3839
#[inline]
39-
pub fn lock(&self) {
40+
pub fn lock(&self) -> MutexState {
4041
unsafe {
4142
c::AcquireSRWLockExclusive(raw(self));
4243
}
44+
MutexState::Normal
4345
}
4446

4547
#[inline]

library/std/src/sys/sync/mutex/xous.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::MutexState;
12
use crate::os::xous::ffi::{blocking_scalar, do_yield};
23
use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
34
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
@@ -34,14 +35,14 @@ impl Mutex {
3435
}
3536

3637
#[inline]
37-
pub unsafe fn lock(&self) {
38+
pub unsafe fn lock(&self) -> MutexState {
3839
// Try multiple times to acquire the lock without resorting to the ticktimer
3940
// server. For locks that are held for a short amount of time, this will
4041
// result in the ticktimer server never getting invoked. The `locked` value
4142
// will be either 0 or 1.
4243
for _attempts in 0..3 {
4344
if unsafe { self.try_lock() } {
44-
return;
45+
return MutexState::Normal;
4546
}
4647
do_yield();
4748
}
@@ -51,7 +52,7 @@ impl Mutex {
5152
// locked, then the value will be more than 1, for example if there are multiple other
5253
// threads waiting on this lock.
5354
if unsafe { self.try_lock_or_poison() } {
54-
return;
55+
return MutexState::Normal;
5556
}
5657

5758
// When this mutex is dropped, we will need to deregister it with the server.
@@ -65,6 +66,8 @@ impl Mutex {
6566
crate::os::xous::services::TicktimerScalar::LockMutex(self.index()).into(),
6667
)
6768
.expect("failure to send LockMutex command");
69+
70+
MutexState::Normal
6871
}
6972

7073
#[inline]

0 commit comments

Comments
 (0)