diff options
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/collections/mod.rs | 12 | ||||
| -rw-r--r-- | library/std/src/ffi/os_str.rs | 2 | ||||
| -rw-r--r-- | library/std/src/fs.rs | 19 | ||||
| -rw-r--r-- | library/std/src/io/buffered/bufreader/buffer.rs | 2 | ||||
| -rw-r--r-- | library/std/src/io/error.rs | 2 | ||||
| -rw-r--r-- | library/std/src/io/mod.rs | 9 | ||||
| -rw-r--r-- | library/std/src/lib.rs | 2 | ||||
| -rw-r--r-- | library/std/src/path.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sync/lazy_lock.rs | 9 | ||||
| -rw-r--r-- | library/std/src/sync/nonpoison.rs | 5 | ||||
| -rw-r--r-- | library/std/src/sync/nonpoison/mutex.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sync/nonpoison/rwlock.rs | 1081 | ||||
| -rw-r--r-- | library/std/src/sync/poison/mutex.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sync/poison/rwlock.rs | 699 | ||||
| -rw-r--r-- | library/std/src/sys/fd/unix.rs | 6 | ||||
| -rw-r--r-- | library/std/src/sys/fs/mod.rs | 15 | ||||
| -rw-r--r-- | library/std/src/sys/fs/unix.rs | 20 | ||||
| -rw-r--r-- | library/std/src/sys/mod.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sys/pal/uefi/time.rs | 4 | ||||
| -rw-r--r-- | library/std/src/sys/pal/unix/mod.rs | 50 | ||||
| -rw-r--r-- | library/std/src/thread/local.rs | 8 |
21 files changed, 1574 insertions, 379 deletions
diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index 889ed3c5380..6104a02c739 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -26,7 +26,7 @@ //! should be considered. Detailed discussions of strengths and weaknesses of //! individual collections can be found on their own documentation pages. //! -//! ### Use a `Vec` when: +//! ### Use a [`Vec`] when: //! * You want to collect items up to be processed or sent elsewhere later, and //! don't care about any properties of the actual values being stored. //! * You want a sequence of elements in a particular order, and will only be @@ -35,25 +35,25 @@ //! * You want a resizable array. //! * You want a heap-allocated array. //! -//! ### Use a `VecDeque` when: +//! ### Use a [`VecDeque`] when: //! * You want a [`Vec`] that supports efficient insertion at both ends of the //! sequence. //! * You want a queue. //! * You want a double-ended queue (deque). //! -//! ### Use a `LinkedList` when: +//! ### Use a [`LinkedList`] when: //! * You want a [`Vec`] or [`VecDeque`] of unknown size, and can't tolerate //! amortization. //! * You want to efficiently split and append lists. //! * You are *absolutely* certain you *really*, *truly*, want a doubly linked //! list. //! -//! ### Use a `HashMap` when: +//! ### Use a [`HashMap`] when: //! * You want to associate arbitrary keys with an arbitrary value. //! * You want a cache. //! * You want a map, with no extra functionality. //! -//! ### Use a `BTreeMap` when: +//! ### Use a [`BTreeMap`] when: //! * You want a map sorted by its keys. //! * You want to be able to get a range of entries on-demand. //! * You're interested in what the smallest or largest key-value pair is. @@ -65,7 +65,7 @@ //! * There is no meaningful value to associate with your keys. //! * You just want a set. //! -//! ### Use a `BinaryHeap` when: +//! ### Use a [`BinaryHeap`] when: //! //! * You want to store a bunch of elements, but only ever want to process the //! "biggest" or "most important" one at any given time. diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 8d7edc732af..1214490caad 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -137,7 +137,7 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - #[rustc_const_unstable(feature = "const_pathbuf_osstring_new", issue = "141520")] + #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "CURRENT_RUSTC_VERSION")] pub const fn new() -> OsString { OsString { inner: Buf::from_string(String::new()) } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index d4a584f4d14..1ed4f2f9f0c 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3156,6 +3156,25 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result fs_imp::set_permissions(path.as_ref(), perm.0) } +/// Set the permissions of a file, unless it is a symlink. +/// +/// Note that the non-final path elements are allowed to be symlinks. +/// +/// # Platform-specific behavior +/// +/// Currently unimplemented on Windows. +/// +/// On Unix platforms, this results in a [`FilesystemLoop`] error if the last element is a symlink. +/// +/// This behavior may change in the future. +/// +/// [`FilesystemLoop`]: crate::io::ErrorKind::FilesystemLoop +#[doc(alias = "chmod", alias = "SetFileAttributes")] +#[unstable(feature = "set_permissions_nofollow", issue = "141607")] +pub fn set_permissions_nofollow<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> { + fs_imp::set_permissions_nofollow(path.as_ref(), perm) +} + impl DirBuilder { /// Creates a new set of options with default mode/security settings for all /// platforms and also non-recursive. diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 574288e579e..9b600cd5575 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -122,7 +122,7 @@ impl Buffer { /// Remove bytes that have already been read from the buffer. pub fn backshift(&mut self) { - self.buf.copy_within(self.pos.., 0); + self.buf.copy_within(self.pos..self.filled, 0); self.filled -= self.pos; self.pos = 0; } diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 562fdbf4ff7..dcfa189823f 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -18,7 +18,7 @@ use crate::{error, fmt, result, sys}; /// This type is broadly used across [`std::io`] for any operation which may /// produce an error. /// -/// This typedef is generally used to avoid writing out [`io::Error`] directly and +/// This type alias is generally used to avoid writing out [`io::Error`] directly and /// is otherwise a direct mapping to [`Result`]. /// /// While usual Rust style is to import types directly, aliases of [`Result`] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index d351ee5e739..ff0e29e04c2 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2461,7 +2461,7 @@ pub trait BufRead: Read { /// delimiter or EOF is found. /// /// If successful, this function will return the total number of bytes read, - /// including the delimiter byte. + /// including the delimiter byte if found. /// /// This is useful for efficiently skipping data such as NUL-terminated strings /// in binary file formats without buffering. @@ -2489,7 +2489,7 @@ pub trait BufRead: Read { /// ``` /// use std::io::{self, BufRead}; /// - /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0"); + /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0!"); /// /// // read name /// let mut name = Vec::new(); @@ -2509,6 +2509,11 @@ pub trait BufRead: Read { /// .expect("reading from cursor won't fail"); /// assert_eq!(num_bytes, 11); /// assert_eq!(animal, b"Crustacean\0"); + /// + /// // reach EOF + /// let num_bytes = cursor.skip_until(b'\0') + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 1); /// ``` #[stable(feature = "bufread_skip_until", since = "1.83.0")] fn skip_until(&mut self, byte: u8) -> Result<usize> { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ab417b6c72f..f0de03c9a28 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -15,7 +15,7 @@ //! //! If you already know the name of what you are looking for, the fastest way to //! find it is to use the <a href="#" onclick="window.searchState.focus();">search -//! bar</a> at the top of the page. +//! button</a> at the top of the page. //! //! Otherwise, you may want to jump to one of these useful sections: //! diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 23e957484a5..3899fbf86db 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1191,7 +1191,7 @@ impl PathBuf { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - #[rustc_const_unstable(feature = "const_pathbuf_osstring_new", issue = "141520")] + #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "CURRENT_RUSTC_VERSION")] pub const fn new() -> PathBuf { PathBuf { inner: OsString::new() } } diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index a40e29a772a..3231125f7a1 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -244,7 +244,11 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> { #[inline] #[stable(feature = "lazy_cell", since = "1.80.0")] pub fn force(this: &LazyLock<T, F>) -> &T { - this.once.call_once(|| { + this.once.call_once_force(|state| { + if state.is_poisoned() { + panic_poisoned(); + } + // SAFETY: `call_once` only runs this closure once, ever. let data = unsafe { &mut *this.data.get() }; let f = unsafe { ManuallyDrop::take(&mut data.f) }; @@ -257,8 +261,7 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> { // * the closure was called and initialized `value`. // * the closure was called and panicked, so this point is never reached. // * the closure was not called, but a previous call initialized `value`. - // * the closure was not called because the Once is poisoned, so this point - // is never reached. + // * the closure was not called because the Once is poisoned, which we handled above. // So `value` has definitely been initialized and will not be modified again. unsafe { &*(*this.data.get()).value } } diff --git a/library/std/src/sync/nonpoison.rs b/library/std/src/sync/nonpoison.rs index 2bbf226dc2c..b3ae376e70d 100644 --- a/library/std/src/sync/nonpoison.rs +++ b/library/std/src/sync/nonpoison.rs @@ -33,5 +33,10 @@ impl fmt::Display for WouldBlock { pub use self::mutex::MappedMutexGuard; #[unstable(feature = "nonpoison_mutex", issue = "134645")] pub use self::mutex::{Mutex, MutexGuard}; +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; mod mutex; +mod rwlock; diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index b6861c78f00..fd1e671d7a3 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -100,7 +100,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex<T>, } -/// A [`MutexGuard`] is not `Send` to maximize platform portablity. +/// A [`MutexGuard`] is not `Send` to maximize platform portability. /// /// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to /// release mutex locks on the same thread they were acquired. diff --git a/library/std/src/sync/nonpoison/rwlock.rs b/library/std/src/sync/nonpoison/rwlock.rs new file mode 100644 index 00000000000..eb0aef99cc1 --- /dev/null +++ b/library/std/src/sync/nonpoison/rwlock.rs @@ -0,0 +1,1081 @@ +use crate::cell::UnsafeCell; +use crate::fmt; +use crate::marker::PhantomData; +use crate::mem::{self, ManuallyDrop, forget}; +use crate::ops::{Deref, DerefMut}; +use crate::ptr::NonNull; +use crate::sync::nonpoison::{TryLockResult, WouldBlock}; +use crate::sys::sync as sys; + +/// A reader-writer lock that does not keep track of lock poisoning. +/// +/// For more information about reader-writer locks, check out the documentation for the poisoning +/// variant of this lock (which can be found at [`poison::RwLock`]). +/// +/// [`poison::RwLock`]: crate::sync::poison::RwLock +/// +/// # Examples +/// +/// ``` +/// #![feature(nonpoison_rwlock)] +/// +/// use std::sync::nonpoison::RwLock; +/// +/// let lock = RwLock::new(5); +/// +/// // many reader locks can be held at once +/// { +/// let r1 = lock.read(); +/// let r2 = lock.read(); +/// assert_eq!(*r1, 5); +/// assert_eq!(*r2, 5); +/// } // read locks are dropped at this point +/// +/// // only one write lock may be held, however +/// { +/// let mut w = lock.write(); +/// *w += 1; +/// assert_eq!(*w, 6); +/// } // write lock is dropped here +/// ``` +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonRwLock")] +pub struct RwLock<T: ?Sized> { + /// The inner [`sys::RwLock`] that synchronizes thread access to the protected data. + inner: sys::RwLock, + /// The lock-protected data. + data: UnsafeCell<T>, +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Send> Send for RwLock<T> {} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Guards +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// RAII structure used to release the shared read access of a lock when +/// dropped. +/// +/// This structure is created by the [`read`] and [`try_read`] methods on +/// [`RwLock`]. +/// +/// [`read`]: RwLock::read +/// [`try_read`]: RwLock::try_read +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a RwLockReadGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`"] +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonRwLockReadGuard")] +pub struct RwLockReadGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `RwLockReadGuard` instance only holds + /// immutability until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. `NonNull` is also + /// covariant over `T`, just like we would have with `&T`. + data: NonNull<T>, + /// A reference to the internal [`sys::RwLock`] that we have read-locked. + inner_lock: &'rwlock sys::RwLock, +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> !Send for RwLockReadGuard<'_, T> {} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {} + +/// RAII structure used to release the exclusive write access of a lock when +/// dropped. +/// +/// This structure is created by the [`write`] and [`try_write`] methods +/// on [`RwLock`]. +/// +/// [`write`]: RwLock::write +/// [`try_write`]: RwLock::try_write +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a RwLockWriteGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Future's to not implement `Send`"] +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonRwLockWriteGuard")] +pub struct RwLockWriteGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A reference to the [`RwLock`] that we have write-locked. + lock: &'rwlock RwLock<T>, +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {} + +/// RAII structure used to release the shared read access of a lock when +/// dropped, which can point to a subfield of the protected data. +/// +/// This structure is created by the [`map`] and [`filter_map`] methods +/// on [`RwLockReadGuard`]. +/// +/// [`map`]: RwLockReadGuard::map +/// [`filter_map`]: RwLockReadGuard::filter_map +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a MappedRwLockReadGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`"] +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[clippy::has_significant_drop] +pub struct MappedRwLockReadGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `MappedRwLockReadGuard` instance only + /// holds immutability until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. `NonNull` is also + /// covariant over `T`, just like we would have with `&T`. + data: NonNull<T>, + /// A reference to the internal [`sys::RwLock`] that we have read-locked. + inner_lock: &'rwlock sys::RwLock, +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> !Send for MappedRwLockReadGuard<'_, T> {} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockReadGuard<'_, T> {} + +/// RAII structure used to release the exclusive write access of a lock when +/// dropped, which can point to a subfield of the protected data. +/// +/// This structure is created by the [`map`] and [`filter_map`] methods +/// on [`RwLockWriteGuard`]. +/// +/// [`map`]: RwLockWriteGuard::map +/// [`filter_map`]: RwLockWriteGuard::filter_map +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a MappedRwLockWriteGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Future's to not implement `Send`"] +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[clippy::has_significant_drop] +pub struct MappedRwLockWriteGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `MappedRwLockWriteGuard` instance only + /// holds uniquneness until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. + data: NonNull<T>, + /// `NonNull` is covariant over `T`, so we add a `PhantomData<&'rwlock mut T>` field here to + /// enforce the correct invariance over `T`. + _variance: PhantomData<&'rwlock mut T>, + /// A reference to the internal [`sys::RwLock`] that we have write-locked. + inner_lock: &'rwlock sys::RwLock, +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> !Send for MappedRwLockWriteGuard<'_, T> {} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockWriteGuard<'_, T> {} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Implementations +//////////////////////////////////////////////////////////////////////////////////////////////////// + +impl<T> RwLock<T> { + /// Creates a new instance of an `RwLock<T>` which is unlocked. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(5); + /// ``` + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + #[inline] + pub const fn new(t: T) -> RwLock<T> { + RwLock { inner: sys::RwLock::new(), data: UnsafeCell::new(t) } + } + + /// Returns the contained value by cloning it. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.get_cloned(), 7); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn get_cloned(&self) -> T + where + T: Clone, + { + self.read().clone() + } + + /// Sets the contained value. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.get_cloned(), 7); + /// lock.set(11); + /// assert_eq!(lock.get_cloned(), 11); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn set(&self, value: T) { + if mem::needs_drop::<T>() { + // If the contained value has a non-trivial destructor, we + // call that destructor after the lock has been released. + drop(self.replace(value)) + } else { + *self.write() = value; + } + } + + /// Replaces the contained value with `value`, and returns the old contained value. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.replace(11), 7); + /// assert_eq!(lock.get_cloned(), 11); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn replace(&self, value: T) -> T { + let mut guard = self.write(); + mem::replace(&mut *guard, value) + } +} + +impl<T: ?Sized> RwLock<T> { + /// Locks this `RwLock` with shared read access, blocking the current thread + /// until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers which + /// hold the lock. There may be other readers currently inside the lock when + /// this method returns. This method does not provide any guarantees with + /// respect to the ordering of whether contentious readers or writers will + /// acquire the lock first. + /// + /// Returns an RAII guard which will release this thread's shared access + /// once it is dropped. + /// + /// # Panics + /// + /// This function might panic when called if the lock is already held by the current thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::Arc; + /// use std::sync::nonpoison::RwLock; + /// use std::thread; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// let c_lock = Arc::clone(&lock); + /// + /// let n = lock.read(); + /// assert_eq!(*n, 1); + /// + /// thread::spawn(move || { + /// let r = c_lock.read(); + /// }).join().unwrap(); + /// ``` + #[inline] + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn read(&self) -> RwLockReadGuard<'_, T> { + unsafe { + self.inner.read(); + RwLockReadGuard::new(self) + } + } + + /// Attempts to acquire this `RwLock` with shared read access. + /// + /// If the access could not be granted at this time, then `Err` is returned. + /// Otherwise, an RAII guard is returned which will release the shared access + /// when it is dropped. + /// + /// This function does not block. + /// + /// This function does not provide any guarantees with respect to the ordering + /// of whether contentious readers or writers will acquire the lock first. + /// + /// # Errors + /// + /// This function will return the [`WouldBlock`] error if the `RwLock` could + /// not be acquired because it was already locked exclusively. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(1); + /// + /// match lock.try_read() { + /// Ok(n) => assert_eq!(*n, 1), + /// Err(_) => unreachable!(), + /// }; + /// ``` + #[inline] + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> { + unsafe { + if self.inner.try_read() { Ok(RwLockReadGuard::new(self)) } else { Err(WouldBlock) } + } + } + + /// Locks this `RwLock` with exclusive write access, blocking the current + /// thread until it can be acquired. + /// + /// This function will not return while other writers or other readers + /// currently have access to the lock. + /// + /// Returns an RAII guard which will drop the write access of this `RwLock` + /// when dropped. + /// + /// # Panics + /// + /// This function might panic when called if the lock is already held by the current thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(1); + /// + /// let mut n = lock.write(); + /// *n = 2; + /// + /// assert!(lock.try_read().is_err()); + /// ``` + #[inline] + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn write(&self) -> RwLockWriteGuard<'_, T> { + unsafe { + self.inner.write(); + RwLockWriteGuard::new(self) + } + } + + /// Attempts to lock this `RwLock` with exclusive write access. + /// + /// If the lock could not be acquired at this time, then `Err` is returned. + /// Otherwise, an RAII guard is returned which will release the lock when + /// it is dropped. + /// + /// This function does not block. + /// + /// This function does not provide any guarantees with respect to the ordering + /// of whether contentious readers or writers will acquire the lock first. + /// + /// # Errors + /// + /// This function will return the [`WouldBlock`] error if the `RwLock` could + /// not be acquired because it was already locked. + /// + /// [`WouldBlock`]: WouldBlock + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(1); + /// + /// let n = lock.read(); + /// assert_eq!(*n, 1); + /// + /// assert!(lock.try_write().is_err()); + /// ``` + #[inline] + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> { + unsafe { + if self.inner.try_write() { Ok(RwLockWriteGuard::new(self)) } else { Err(WouldBlock) } + } + } + + /// Consumes this `RwLock`, returning the underlying data. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(String::new()); + /// { + /// let mut s = lock.write(); + /// *s = "modified".to_owned(); + /// } + /// assert_eq!(lock.into_inner(), "modified"); + /// ``` + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn into_inner(self) -> T + where + T: Sized, + { + self.data.into_inner() + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `RwLock` mutably, no actual locking needs to + /// take place -- the mutable borrow statically guarantees no new locks can be acquired + /// while this reference exists. Note that this method does not clear any previously abandoned + /// locks (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]). + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let mut lock = RwLock::new(0); + /// *lock.get_mut() = 10; + /// assert_eq!(*lock.read(), 10); + /// ``` + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn get_mut(&mut self) -> &mut T { + self.data.get_mut() + } + + /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads and writes through it + /// are properly synchronized to avoid data races, and that it is not read + /// or written through after the lock is dropped. + #[unstable(feature = "rwlock_data_ptr", issue = "140368")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = f.debug_struct("RwLock"); + match self.try_read() { + Ok(guard) => { + d.field("data", &&*guard); + } + Err(WouldBlock) => { + d.field("data", &format_args!("<locked>")); + } + } + d.finish_non_exhaustive() + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: Default> Default for RwLock<T> { + /// Creates a new `RwLock<T>`, with the `Default` value for T. + fn default() -> RwLock<T> { + RwLock::new(Default::default()) + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T> From<T> for RwLock<T> { + /// Creates a new instance of an `RwLock<T>` which is unlocked. + /// This is equivalent to [`RwLock::new`]. + fn from(t: T) -> Self { + RwLock::new(t) + } +} + +impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { + /// Creates a new instance of `RwLockReadGuard<T>` from a `RwLock<T>`. + /// + /// # Safety + /// + /// This function is safe if and only if the same thread has successfully and safely called + /// `lock.inner.read()`, `lock.inner.try_read()`, or `lock.inner.downgrade()` before + /// instantiating this object. + unsafe fn new(lock: &'rwlock RwLock<T>) -> RwLockReadGuard<'rwlock, T> { + RwLockReadGuard { + data: unsafe { NonNull::new_unchecked(lock.data.get()) }, + inner_lock: &lock.inner, + } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, e.g. + /// an enum variant. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockReadGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the `RwLockReadGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'rwlock, U> + where + F: FnOnce(&T) -> &U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_ref() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. The + /// original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockReadGuard::filter_map(...)`. A method would interfere with methods + /// of the same name on the contents of the `RwLockReadGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'rwlock, U>, Self> + where + F: FnOnce(&T) -> Option<&U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_ref() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) + } + None => Err(orig), + } + } +} + +impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { + /// Creates a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`. + /// + /// # Safety + /// + /// This function is safe if and only if the same thread has successfully and safely called + /// `lock.inner.write()`, `lock.inner.try_write()`, or `lock.inner.try_upgrade` before + /// instantiating this object. + unsafe fn new(lock: &'rwlock RwLock<T>) -> RwLockWriteGuard<'rwlock, T> { + RwLockWriteGuard { lock } + } + + /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. + /// + /// Since we have the `RwLockWriteGuard`, the [`RwLock`] must already be locked for writing, so + /// this method cannot fail. + /// + /// After downgrading, other readers will be allowed to read the protected data. + /// + /// # Examples + /// + /// `downgrade` takes ownership of the `RwLockWriteGuard` and returns a [`RwLockReadGuard`]. + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(rwlock_downgrade)] + /// + /// use std::sync::nonpoison::{RwLock, RwLockWriteGuard}; + /// + /// let rw = RwLock::new(0); + /// + /// let mut write_guard = rw.write(); + /// *write_guard = 42; + /// + /// let read_guard = RwLockWriteGuard::downgrade(write_guard); + /// assert_eq!(42, *read_guard); + /// ``` + /// + /// `downgrade` will _atomically_ change the state of the [`RwLock`] from exclusive mode into + /// shared mode. This means that it is impossible for another writing thread to get in between a + /// thread calling `downgrade` and any reads it performs after downgrading. + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(rwlock_downgrade)] + /// + /// use std::sync::Arc; + /// use std::sync::nonpoison::{RwLock, RwLockWriteGuard}; + /// + /// let rw = Arc::new(RwLock::new(1)); + /// + /// // Put the lock in write mode. + /// let mut main_write_guard = rw.write(); + /// + /// let rw_clone = rw.clone(); + /// let evil_handle = std::thread::spawn(move || { + /// // This will not return until the main thread drops the `main_read_guard`. + /// let mut evil_guard = rw_clone.write(); + /// + /// assert_eq!(*evil_guard, 2); + /// *evil_guard = 3; + /// }); + /// + /// *main_write_guard = 2; + /// + /// // Atomically downgrade the write guard into a read guard. + /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + /// + /// // Since `downgrade` is atomic, the writer thread cannot have changed the protected data. + /// assert_eq!(*main_read_guard, 2, "`downgrade` was not atomic"); + /// # + /// # drop(main_read_guard); + /// # evil_handle.join().unwrap(); + /// # + /// # let final_check = rw.read(); + /// # assert_eq!(*final_check, 3); + /// ``` + #[unstable(feature = "rwlock_downgrade", issue = "128203")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn downgrade(s: Self) -> RwLockReadGuard<'rwlock, T> { + let lock = s.lock; + + // We don't want to call the destructor since that calls `write_unlock`. + forget(s); + + // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write + // mode, satisfying the `downgrade` contract. + unsafe { lock.inner.downgrade() }; + + // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract. + unsafe { RwLockReadGuard::new(lock) } + } + + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, e.g. + /// an enum variant. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockWriteGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the `RwLockWriteGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'rwlock, U> + where + F: FnOnce(&mut T) -> &mut U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockWriteGuard { data, inner_lock: &orig.lock.inner, _variance: PhantomData } + } + + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. The + /// original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockWriteGuard::filter_map(...)`. A method would interfere with methods + /// of the same name on the contents of the `RwLockWriteGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'rwlock, U>, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { &mut *orig.lock.data.get() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockWriteGuard { + data, + inner_lock: &orig.lock.inner, + _variance: PhantomData, + }) + } + None => Err(orig), + } + } +} + +impl<'rwlock, T: ?Sized> MappedRwLockReadGuard<'rwlock, T> { + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, + /// e.g. an enum variant. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'rwlock, U> + where + F: FnOnce(&T) -> &U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_ref() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. + /// The original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::filter_map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'rwlock, U>, Self> + where + F: FnOnce(&T) -> Option<&U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_ref() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) + } + None => Err(orig), + } + } +} + +impl<'rwlock, T: ?Sized> MappedRwLockWriteGuard<'rwlock, T> { + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, + /// e.g. an enum variant. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockWriteGuard::map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockWriteGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'rwlock, U> + where + F: FnOnce(&mut T) -> &mut U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_mut() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockWriteGuard { data, inner_lock: orig.inner_lock, _variance: PhantomData } + } + + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. + /// The original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockWriteGuard::filter_map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockWriteGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn filter_map<U, F>( + mut orig: Self, + f: F, + ) -> Result<MappedRwLockWriteGuard<'rwlock, U>, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_mut() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockWriteGuard { + data, + inner_lock: orig.inner_lock, + _variance: PhantomData, + }) + } + None => Err(orig), + } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { + self.lock.inner.write_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { + self.inner_lock.write_unlock(); + } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { &*self.lock.data.get() } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { &mut *self.lock.data.get() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_mut() } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 6205c4fa4ca..720c212c65c 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -279,7 +279,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { poison: poison::Guard, } -/// A [`MutexGuard`] is not `Send` to maximize platform portablity. +/// A [`MutexGuard`] is not `Send` to maximize platform portability. /// /// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to /// release mutex locks on the same thread they were acquired. diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 2c92602bc87..0a463f3f9c7 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -80,16 +80,24 @@ use crate::sys::sync as sys; #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "RwLock")] pub struct RwLock<T: ?Sized> { + /// The inner [`sys::RwLock`] that synchronizes thread access to the protected data. inner: sys::RwLock, + /// A flag denoting if this `RwLock` has been poisoned. poison: poison::Flag, + /// The lock-protected data. data: UnsafeCell<T>, } #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Send> Send for RwLock<T> {} + #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Guards +//////////////////////////////////////////////////////////////////////////////////////////////////// + /// RAII structure used to release the shared read access of a lock when /// dropped. /// @@ -105,13 +113,15 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] #[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")] -pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { - // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a - // `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops. - // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull` - // is preferable over `const* T` to allow for niche optimization. +pub struct RwLockReadGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `RwLockReadGuard` instance only holds + /// immutability until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. `NonNull` is also + /// covariant over `T`, just like we would have with `&T`. data: NonNull<T>, - inner_lock: &'a sys::RwLock, + /// A reference to the internal [`sys::RwLock`] that we have read-locked. + inner_lock: &'rwlock sys::RwLock, } #[stable(feature = "rust1", since = "1.0.0")] @@ -135,8 +145,10 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] #[cfg_attr(not(test), rustc_diagnostic_item = "RwLockWriteGuard")] -pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { - lock: &'a RwLock<T>, +pub struct RwLockWriteGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A reference to the [`RwLock`] that we have write-locked. + lock: &'rwlock RwLock<T>, + /// The poison guard. See the [`poison`] module for more information. poison: poison::Guard, } @@ -160,13 +172,15 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {} and cause Futures to not implement `Send`"] #[unstable(feature = "mapped_lock_guards", issue = "117108")] #[clippy::has_significant_drop] -pub struct MappedRwLockReadGuard<'a, T: ?Sized + 'a> { - // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a - // `MappedRwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops. - // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull` - // is preferable over `const* T` to allow for niche optimization. +pub struct MappedRwLockReadGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `MappedRwLockReadGuard` instance only + /// holds immutability until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. `NonNull` is also + /// covariant over `T`, just like we would have with `&T`. data: NonNull<T>, - inner_lock: &'a sys::RwLock, + /// A reference to the internal [`sys::RwLock`] that we have read-locked. + inner_lock: &'rwlock sys::RwLock, } #[unstable(feature = "mapped_lock_guards", issue = "117108")] @@ -189,16 +203,21 @@ unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockReadGuard<'_, T> {} and cause Future's to not implement `Send`"] #[unstable(feature = "mapped_lock_guards", issue = "117108")] #[clippy::has_significant_drop] -pub struct MappedRwLockWriteGuard<'a, T: ?Sized + 'a> { - // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a - // `MappedRwLockWriteGuard` argument doesn't hold uniqueness for its whole scope, only until it drops. - // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field - // below for the correct variance over `T` (invariance). +pub struct MappedRwLockWriteGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `MappedRwLockWriteGuard` instance only + /// holds uniquneness until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. data: NonNull<T>, - inner_lock: &'a sys::RwLock, - poison_flag: &'a poison::Flag, - poison: poison::Guard, - _variance: PhantomData<&'a mut T>, + /// `NonNull` is covariant over `T`, so we add a `PhantomData<&'rwlock mut T>` field here to + /// enforce the correct invariance over `T`. + _variance: PhantomData<&'rwlock mut T>, + /// A reference to the internal [`sys::RwLock`] that we have write-locked. + inner_lock: &'rwlock sys::RwLock, + /// A reference to the original `RwLock`'s poison state. + poison_flag: &'rwlock poison::Flag, + /// The poison guard. See the [`poison`] module for more information. + poison_guard: poison::Guard, } #[unstable(feature = "mapped_lock_guards", issue = "117108")] @@ -207,6 +226,10 @@ impl<T: ?Sized> !Send for MappedRwLockWriteGuard<'_, T> {} #[unstable(feature = "mapped_lock_guards", issue = "117108")] unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockWriteGuard<'_, T> {} +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Implementations +//////////////////////////////////////////////////////////////////////////////////////////////////// + impl<T> RwLock<T> { /// Creates a new instance of an `RwLock<T>` which is unlocked. /// @@ -611,8 +634,8 @@ impl<T: ?Sized> RwLock<T> { /// /// Since this call borrows the `RwLock` mutably, no actual locking needs to /// take place -- the mutable borrow statically guarantees no new locks can be acquired - /// while this reference exists. Note that this method does not clear any previously abandoned locks - /// (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]). + /// while this reference exists. Note that this method does not clear any previously abandoned + /// locks (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]). /// /// # Errors /// @@ -700,177 +723,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { inner_lock: &lock.inner, }) } -} - -impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { - /// Creates a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`. - // SAFETY: if and only if `lock.inner.write()` (or `lock.inner.try_write()`) has been - // successfully called from the same thread before instantiating this object. - unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> { - poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard }) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "std_guard_impls", since = "1.20.0")] -impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "std_guard_impls", since = "1.20.0")] -impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. - unsafe { self.data.as_ref() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. - unsafe { &*self.lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { - fn deref_mut(&mut self) -> &mut T { - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. - unsafe { &mut *self.lock.data.get() } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { self.data.as_ref() } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { self.data.as_ref() } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> { - fn deref_mut(&mut self) -> &mut T { - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { self.data.as_mut() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { - fn drop(&mut self) { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. - unsafe { - self.inner_lock.read_unlock(); - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { - fn drop(&mut self) { - self.lock.poison.done(&self.poison); - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. - unsafe { - self.lock.inner.write_unlock(); - } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> { - fn drop(&mut self) { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { - self.inner_lock.read_unlock(); - } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> { - fn drop(&mut self) { - self.poison_flag.done(&self.poison); - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { - self.inner_lock.write_unlock(); - } - } -} -impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, e.g. /// an enum variant. /// @@ -883,17 +736,18 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { /// /// # Panics /// - /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be + /// poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U> + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'rwlock, U> where F: FnOnce(&T) -> &U, U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { orig.data.as_ref() })); let orig = ManuallyDrop::new(orig); MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } @@ -912,17 +766,18 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { /// /// # Panics /// - /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be + /// poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self> + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'rwlock, U>, Self> where F: FnOnce(&T) -> Option<&U>, U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. match f(unsafe { orig.data.as_ref() }) { Some(data) => { let data = NonNull::from(data); @@ -934,71 +789,95 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { } } -impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> { - /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, - /// e.g. an enum variant. - /// - /// The `RwLock` is already locked for reading, so this cannot fail. - /// - /// This is an associated function that needs to be used as - /// `MappedRwLockReadGuard::map(...)`. A method would interfere with - /// methods of the same name on the contents of the `MappedRwLockReadGuard` - /// used through `Deref`. +impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { + /// Creates a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`. /// - /// # Panics + /// # Safety /// - /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. - #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U> - where - F: FnOnce(&T) -> &U, - U: ?Sized, - { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. - let data = NonNull::from(f(unsafe { orig.data.as_ref() })); - let orig = ManuallyDrop::new(orig); - MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + /// This function is safe if and only if the same thread has successfully and safely called + /// `lock.inner.write()`, `lock.inner.try_write()`, or `lock.inner.try_upgrade` before + /// instantiating this object. + unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> { + poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard }) } - /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. - /// The original guard is returned as an `Err(...)` if the closure returns - /// `None`. + /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. /// - /// The `RwLock` is already locked for reading, so this cannot fail. + /// Since we have the `RwLockWriteGuard`, the [`RwLock`] must already be locked for writing, so + /// this method cannot fail. /// - /// This is an associated function that needs to be used as - /// `MappedRwLockReadGuard::filter_map(...)`. A method would interfere with - /// methods of the same name on the contents of the `MappedRwLockReadGuard` - /// used through `Deref`. + /// After downgrading, other readers will be allowed to read the protected data. /// - /// # Panics + /// # Examples /// - /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. - #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self> - where - F: FnOnce(&T) -> Option<&U>, - U: ?Sized, - { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. - match f(unsafe { orig.data.as_ref() }) { - Some(data) => { - let data = NonNull::from(data); - let orig = ManuallyDrop::new(orig); - Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) - } - None => Err(orig), - } + /// `downgrade` takes ownership of the `RwLockWriteGuard` and returns a [`RwLockReadGuard`]. + /// + /// ``` + /// #![feature(rwlock_downgrade)] + /// + /// use std::sync::{RwLock, RwLockWriteGuard}; + /// + /// let rw = RwLock::new(0); + /// + /// let mut write_guard = rw.write().unwrap(); + /// *write_guard = 42; + /// + /// let read_guard = RwLockWriteGuard::downgrade(write_guard); + /// assert_eq!(42, *read_guard); + /// ``` + /// + /// `downgrade` will _atomically_ change the state of the [`RwLock`] from exclusive mode into + /// shared mode. This means that it is impossible for another writing thread to get in between a + /// thread calling `downgrade` and any reads it performs after downgrading. + /// + /// ``` + /// #![feature(rwlock_downgrade)] + /// + /// use std::sync::{Arc, RwLock, RwLockWriteGuard}; + /// + /// let rw = Arc::new(RwLock::new(1)); + /// + /// // Put the lock in write mode. + /// let mut main_write_guard = rw.write().unwrap(); + /// + /// let rw_clone = rw.clone(); + /// let evil_handle = std::thread::spawn(move || { + /// // This will not return until the main thread drops the `main_read_guard`. + /// let mut evil_guard = rw_clone.write().unwrap(); + /// + /// assert_eq!(*evil_guard, 2); + /// *evil_guard = 3; + /// }); + /// + /// *main_write_guard = 2; + /// + /// // Atomically downgrade the write guard into a read guard. + /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + /// + /// // Since `downgrade` is atomic, the writer thread cannot have changed the protected data. + /// assert_eq!(*main_read_guard, 2, "`downgrade` was not atomic"); + /// # + /// # drop(main_read_guard); + /// # evil_handle.join().unwrap(); + /// # + /// # let final_check = rw.read().unwrap(); + /// # assert_eq!(*final_check, 3); + /// ``` + #[unstable(feature = "rwlock_downgrade", issue = "128203")] + pub fn downgrade(s: Self) -> RwLockReadGuard<'rwlock, T> { + let lock = s.lock; + + // We don't want to call the destructor since that calls `write_unlock`. + forget(s); + + // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write + // mode, satisfying the `downgrade` contract. + unsafe { lock.inner.downgrade() }; + + // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract. + unsafe { RwLockReadGuard::new(lock).unwrap_or_else(PoisonError::into_inner) } } -} -impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, e.g. /// an enum variant. /// @@ -1013,22 +892,22 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U> + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'rwlock, U> where F: FnOnce(&mut T) -> &mut U, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() })); let orig = ManuallyDrop::new(orig); MappedRwLockWriteGuard { data, inner_lock: &orig.lock.inner, poison_flag: &orig.lock.poison, - poison: orig.poison.clone(), + poison_guard: orig.poison.clone(), _variance: PhantomData, } } @@ -1048,15 +927,15 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self> + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'rwlock, U>, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. match f(unsafe { &mut *orig.lock.data.get() }) { Some(data) => { let data = NonNull::from(data); @@ -1065,78 +944,82 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { data, inner_lock: &orig.lock.inner, poison_flag: &orig.lock.poison, - poison: orig.poison.clone(), + poison_guard: orig.poison.clone(), _variance: PhantomData, }) } None => Err(orig), } } +} - /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. - /// - /// This method will atomically change the state of the [`RwLock`] from exclusive mode into - /// shared mode. This means that it is impossible for a writing thread to get in between a - /// thread calling `downgrade` and the same thread reading whatever it wrote while it had the - /// [`RwLock`] in write mode. - /// - /// Note that since we have the `RwLockWriteGuard`, we know that the [`RwLock`] is already - /// locked for writing, so this method cannot fail. - /// - /// # Example - /// - /// ``` - /// #![feature(rwlock_downgrade)] - /// use std::sync::{Arc, RwLock, RwLockWriteGuard}; - /// - /// // The inner value starts as 0. - /// let rw = Arc::new(RwLock::new(0)); +impl<'rwlock, T: ?Sized> MappedRwLockReadGuard<'rwlock, T> { + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, + /// e.g. an enum variant. /// - /// // Put the lock in write mode. - /// let mut main_write_guard = rw.write().unwrap(); + /// The `RwLock` is already locked for reading, so this cannot fail. /// - /// let evil = rw.clone(); - /// let handle = std::thread::spawn(move || { - /// // This will not return until the main thread drops the `main_read_guard`. - /// let mut evil_guard = evil.write().unwrap(); + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. /// - /// assert_eq!(*evil_guard, 1); - /// *evil_guard = 2; - /// }); + /// # Panics /// - /// // After spawning the writer thread, set the inner value to 1. - /// *main_write_guard = 1; + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be + /// poisoned. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'rwlock, U> + where + F: FnOnce(&T) -> &U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_ref() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. + /// The original guard is returned as an `Err(...)` if the closure returns + /// `None`. /// - /// // Atomically downgrade the write guard into a read guard. - /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + /// The `RwLock` is already locked for reading, so this cannot fail. /// - /// // Since `downgrade` is atomic, the writer thread cannot have set the inner value to 2. - /// assert_eq!(*main_read_guard, 1, "`downgrade` was not atomic"); + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::filter_map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. /// - /// // Clean up everything now - /// drop(main_read_guard); - /// handle.join().unwrap(); + /// # Panics /// - /// let final_check = rw.read().unwrap(); - /// assert_eq!(*final_check, 2); - /// ``` - #[unstable(feature = "rwlock_downgrade", issue = "128203")] - pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> { - let lock = s.lock; - - // We don't want to call the destructor since that calls `write_unlock`. - forget(s); - - // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write - // mode, satisfying the `downgrade` contract. - unsafe { lock.inner.downgrade() }; - - // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract. - unsafe { RwLockReadGuard::new(lock).unwrap_or_else(PoisonError::into_inner) } + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be + /// poisoned. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'rwlock, U>, Self> + where + F: FnOnce(&T) -> Option<&U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_ref() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) + } + None => Err(orig), + } } } -impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { +impl<'rwlock, T: ?Sized> MappedRwLockWriteGuard<'rwlock, T> { /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, /// e.g. an enum variant. /// @@ -1151,22 +1034,22 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U> + pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'rwlock, U> where F: FnOnce(&mut T) -> &mut U, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { orig.data.as_mut() })); let orig = ManuallyDrop::new(orig); MappedRwLockWriteGuard { data, inner_lock: orig.inner_lock, poison_flag: orig.poison_flag, - poison: orig.poison.clone(), + poison_guard: orig.poison_guard.clone(), _variance: PhantomData, } } @@ -1186,15 +1069,18 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn filter_map<U, F>(mut orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self> + pub fn filter_map<U, F>( + mut orig: Self, + f: F, + ) -> Result<MappedRwLockWriteGuard<'rwlock, U>, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. match f(unsafe { orig.data.as_mut() }) { Some(data) => { let data = NonNull::from(data); @@ -1203,7 +1089,7 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { data, inner_lock: orig.inner_lock, poison_flag: orig.poison_flag, - poison: orig.poison.clone(), + poison_guard: orig.poison_guard.clone(), _variance: PhantomData, }) } @@ -1211,3 +1097,162 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { } } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { + fn drop(&mut self) { + self.lock.poison.done(&self.poison); + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { + self.lock.inner.write_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> { + fn drop(&mut self) { + self.poison_flag.done(&self.poison_guard); + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { + self.inner_lock.write_unlock(); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. + unsafe { self.data.as_ref() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { &*self.lock.data.get() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { &mut *self.lock.data.get() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_mut() } + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[stable(feature = "std_guard_impls", since = "1.20.0")] +impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[stable(feature = "std_guard_impls", since = "1.20.0")] +impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index cdca73cdca1..a12f692e754 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -37,10 +37,10 @@ pub struct FileDesc(OwnedFd); // // On Apple targets however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size -// larger than or equal to INT_MAX. To handle both of these the read -// size is capped on both platforms. +// larger than INT_MAX. To handle both of these the read size is capped on +// both platforms. const READ_LIMIT: usize = if cfg!(target_vendor = "apple") { - libc::c_int::MAX as usize - 1 + libc::c_int::MAX as usize } else { libc::ssize_t::MAX as usize }; diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index d9740e15789..dbd782f5018 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -114,6 +114,21 @@ pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { with_native_path(path, &|path| imp::set_perm(path, perm.clone())) } +#[cfg(unix)] +pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> { + use crate::fs::OpenOptions; + use crate::os::unix::fs::OpenOptionsExt; + + OpenOptions::new().custom_flags(libc::O_NOFOLLOW).open(path)?.set_permissions(perm) +} + +#[cfg(not(unix))] +pub fn set_permissions_nofollow(_path: &Path, _perm: crate::fs::Permissions) -> io::Result<()> { + crate::unimplemented!( + "`set_permissions_nofollow` is currently only implemented on Unix platforms" + ) +} + pub fn canonicalize(path: &Path) -> io::Result<PathBuf> { with_native_path(path, &imp::canonicalize) } diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 1e2fe6b01f7..0d710a4b2a6 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1264,6 +1264,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", ))] pub fn lock(&self) -> io::Result<()> { @@ -1276,6 +1278,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", )))] pub fn lock(&self) -> io::Result<()> { @@ -1287,6 +1291,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", ))] pub fn lock_shared(&self) -> io::Result<()> { @@ -1299,6 +1305,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", )))] pub fn lock_shared(&self) -> io::Result<()> { @@ -1310,6 +1318,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", ))] pub fn try_lock(&self) -> Result<(), TryLockError> { @@ -1330,6 +1340,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", )))] pub fn try_lock(&self) -> Result<(), TryLockError> { @@ -1344,6 +1356,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", ))] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { @@ -1364,6 +1378,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", )))] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { @@ -1378,6 +1394,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", ))] pub fn unlock(&self) -> io::Result<()> { @@ -1390,6 +1408,8 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", target_vendor = "apple", )))] pub fn unlock(&self) -> io::Result<()> { diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 8ec0a0e3302..6324c1a232a 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -1,7 +1,7 @@ #![allow(unsafe_op_in_unsafe_fn)] /// The configure builtins provides runtime support compiler-builtin features -/// which require dynamic intialization to work as expected, e.g. aarch64 +/// which require dynamic initialization to work as expected, e.g. aarch64 /// outline-atomics. mod configure_builtins; diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index b7c71b76ee8..36ce3f7ef96 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -188,7 +188,7 @@ pub(crate) mod system_time_internal { Duration::new(epoch, t.nanosecond) } - /// This algorithm is a modifed version of the one described in the post: + /// This algorithm is a modified version of the one described in the post: /// https://howardhinnant.github.io/date_algorithms.html#clive_from_days /// /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX @@ -197,7 +197,7 @@ pub(crate) mod system_time_internal { // Check timzone validity assert!(timezone <= 1440 && timezone >= -1440); - // FIXME(#126043): use checked_sub_signed once stablized + // FIXME(#126043): use checked_sub_signed once stabilized let secs = dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap(); diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index fede3673eb6..aef7ab55088 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -59,6 +59,30 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { } unsafe fn sanitize_standard_fds() { + #[allow(dead_code, unused_variables, unused_mut)] + let mut opened_devnull = -1; + #[allow(dead_code, unused_variables, unused_mut)] + let mut open_devnull = || { + #[cfg(not(all(target_os = "linux", target_env = "gnu")))] + use libc::open; + #[cfg(all(target_os = "linux", target_env = "gnu"))] + use libc::open64 as open; + + if opened_devnull != -1 { + if libc::dup(opened_devnull) != -1 { + return; + } + } + opened_devnull = open(c"/dev/null".as_ptr(), libc::O_RDWR, 0); + if opened_devnull == -1 { + // If the stream is closed but we failed to reopen it, abort the + // process. Otherwise we wouldn't preserve the safety of + // operations on the corresponding Rust object Stdin, Stdout, or + // Stderr. + libc::abort(); + } + }; + // fast path with a single syscall for systems with poll() #[cfg(not(any( miri, @@ -74,11 +98,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_vendor = "apple", )))] 'poll: { - #[cfg(not(all(target_os = "linux", target_env = "gnu")))] - use libc::open as open64; - #[cfg(all(target_os = "linux", target_env = "gnu"))] - use libc::open64; - use crate::sys::os::errno; let pfds: &mut [_] = &mut [ libc::pollfd { fd: 0, events: 0, revents: 0 }, @@ -106,13 +125,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { if pfd.revents & libc::POLLNVAL == 0 { continue; } - if open64(c"/dev/null".as_ptr(), libc::O_RDWR, 0) == -1 { - // If the stream is closed but we failed to reopen it, abort the - // process. Otherwise we wouldn't preserve the safety of - // operations on the corresponding Rust object Stdin, Stdout, or - // Stderr. - libc::abort(); - } + open_devnull(); } return; } @@ -129,21 +142,10 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "vita", )))] { - #[cfg(not(all(target_os = "linux", target_env = "gnu")))] - use libc::open as open64; - #[cfg(all(target_os = "linux", target_env = "gnu"))] - use libc::open64; - use crate::sys::os::errno; for fd in 0..3 { if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { - if open64(c"/dev/null".as_ptr(), libc::O_RDWR, 0) == -1 { - // If the stream is closed but we failed to reopen it, abort the - // process. Otherwise we wouldn't preserve the safety of - // operations on the corresponding Rust object Stdin, Stdout, or - // Stderr. - libc::abort(); - } + open_devnull(); } } } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 0ad014ccd3e..797feeb2bbb 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -8,8 +8,8 @@ use crate::fmt; /// A thread local storage (TLS) key which owns its contents. /// -/// This key uses the fastest possible implementation available to it for the -/// target platform. It is instantiated with the [`thread_local!`] macro and the +/// This key uses the fastest implementation available on the target platform. +/// It is instantiated with the [`thread_local!`] macro and the /// primary method is the [`with`] method, though there are helpers to make /// working with [`Cell`] types easier. /// @@ -24,10 +24,10 @@ use crate::fmt; /// [`with`]) within a thread, and values that implement [`Drop`] get /// destructed when a thread exits. Some platform-specific caveats apply, which /// are explained below. -/// Note that, should the destructor panics, the whole process will be [aborted]. +/// Note that if the destructor panics, the whole process will be [aborted]. /// /// A `LocalKey`'s initializer cannot recursively depend on itself. Using a -/// `LocalKey` in this way may cause panics, aborts or infinite recursion on +/// `LocalKey` in this way may cause panics, aborts, or infinite recursion on /// the first call to `with`. /// /// [aborted]: crate::process::abort |
