From 6b9289c0862fa86ff3fcafe05011abb42c677e6f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 15 Aug 2022 12:59:04 -0700 Subject: [PATCH] Optimize poison guards to ZSTs when panic=abort --- library/std/src/sync/poison.rs | 51 ++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 741312d5537e9..1e978bec4b44b 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -1,9 +1,13 @@ use crate::error::Error; use crate::fmt; + +#[cfg(panic = "unwind")] use crate::sync::atomic::{AtomicBool, Ordering}; +#[cfg(panic = "unwind")] use crate::thread; pub struct Flag { + #[cfg(panic = "unwind")] failed: AtomicBool, } @@ -21,7 +25,10 @@ pub struct Flag { impl Flag { #[inline] pub const fn new() -> Flag { - Flag { failed: AtomicBool::new(false) } + Flag { + #[cfg(panic = "unwind")] + failed: AtomicBool::new(false), + } } /// Check the flag for an unguarded borrow, where we only care about existing poison. @@ -33,11 +40,15 @@ impl Flag { /// Check the flag for a guarded borrow, where we may also set poison when `done`. #[inline] pub fn guard(&self) -> LockResult { - let ret = Guard { panicking: thread::panicking() }; + let ret = Guard { + #[cfg(panic = "unwind")] + panicking: thread::panicking(), + }; if self.get() { Err(PoisonError::new(ret)) } else { Ok(ret) } } #[inline] + #[cfg(panic = "unwind")] pub fn done(&self, guard: &Guard) { if !guard.panicking && thread::panicking() { self.failed.store(true, Ordering::Relaxed); @@ -45,17 +56,30 @@ impl Flag { } #[inline] + #[cfg(not(panic = "unwind"))] + pub fn done(&self, _guard: &Guard) {} + + #[inline] + #[cfg(panic = "unwind")] pub fn get(&self) -> bool { self.failed.load(Ordering::Relaxed) } + #[inline(always)] + #[cfg(not(panic = "unwind"))] + pub fn get(&self) -> bool { + false + } + #[inline] pub fn clear(&self) { + #[cfg(panic = "unwind")] self.failed.store(false, Ordering::Relaxed) } } pub struct Guard { + #[cfg(panic = "unwind")] panicking: bool, } @@ -95,6 +119,8 @@ pub struct Guard { #[stable(feature = "rust1", since = "1.0.0")] pub struct PoisonError { guard: T, + #[cfg(not(panic = "unwind"))] + _never: !, } /// An enumeration of possible errors associated with a [`TryLockResult`] which @@ -165,11 +191,27 @@ impl PoisonError { /// /// This is generally created by methods like [`Mutex::lock`](crate::sync::Mutex::lock) /// or [`RwLock::read`](crate::sync::RwLock::read). + /// + /// This method may panic if std was built with `panic="abort"`. + #[cfg(panic = "unwind")] #[stable(feature = "sync_poison", since = "1.2.0")] pub fn new(guard: T) -> PoisonError { PoisonError { guard } } + /// Creates a `PoisonError`. + /// + /// This is generally created by methods like [`Mutex::lock`](crate::sync::Mutex::lock) + /// or [`RwLock::read`](crate::sync::RwLock::read). + /// + /// This method may panic if std was built with `panic="abort"`. + #[cfg(not(panic = "unwind"))] + #[stable(feature = "sync_poison", since = "1.2.0")] + #[track_caller] + pub fn new(_guard: T) -> PoisonError { + panic!("PoisonError created in a libstd built with panic=\"abort\"") + } + /// Consumes this error indicating that a lock is poisoned, returning the /// underlying guard to allow access regardless. /// @@ -225,6 +267,7 @@ impl From> for TryLockError { impl fmt::Debug for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { + #[cfg(panic = "unwind")] TryLockError::Poisoned(..) => "Poisoned(..)".fmt(f), TryLockError::WouldBlock => "WouldBlock".fmt(f), } @@ -235,6 +278,7 @@ impl fmt::Debug for TryLockError { impl fmt::Display for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { + #[cfg(panic = "unwind")] TryLockError::Poisoned(..) => "poisoned lock: another task failed inside", TryLockError::WouldBlock => "try_lock failed because the operation would block", } @@ -247,6 +291,7 @@ impl Error for TryLockError { #[allow(deprecated, deprecated_in_future)] fn description(&self) -> &str { match *self { + #[cfg(panic = "unwind")] TryLockError::Poisoned(ref p) => p.description(), TryLockError::WouldBlock => "try_lock failed because the operation would block", } @@ -255,6 +300,7 @@ impl Error for TryLockError { #[allow(deprecated)] fn cause(&self) -> Option<&dyn Error> { match *self { + #[cfg(panic = "unwind")] TryLockError::Poisoned(ref p) => Some(p), _ => None, } @@ -267,6 +313,7 @@ where { match result { Ok(t) => Ok(f(t)), + #[cfg(panic = "unwind")] Err(PoisonError { guard }) => Err(PoisonError::new(f(guard))), } }