diff options
Diffstat (limited to 'library/std/src/sys/unix')
| -rw-r--r-- | library/std/src/sys/unix/locks/fuchsia_mutex.rs | 5 | ||||
| -rw-r--r-- | library/std/src/sys/unix/locks/futex_mutex.rs | 5 | ||||
| -rw-r--r-- | library/std/src/sys/unix/locks/futex_rwlock.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sys/unix/locks/mod.rs | 6 | ||||
| -rw-r--r-- | library/std/src/sys/unix/locks/pthread_mutex.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sys/unix/mod.rs | 36 | ||||
| -rw-r--r-- | library/std/src/sys/unix/os.rs | 12 | ||||
| -rw-r--r-- | library/std/src/sys/unix/process/process_unix.rs | 4 | ||||
| -rw-r--r-- | library/std/src/sys/unix/thread.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sys/unix/thread_parker/mod.rs | 21 | ||||
| -rw-r--r-- | library/std/src/sys/unix/thread_parker/netbsd.rs | 113 | ||||
| -rw-r--r-- | library/std/src/sys/unix/thread_parker/pthread.rs (renamed from library/std/src/sys/unix/thread_parker.rs) | 14 |
12 files changed, 183 insertions, 39 deletions
diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs index ce427599c3b..117611ce43f 100644 --- a/library/std/src/sys/unix/locks/fuchsia_mutex.rs +++ b/library/std/src/sys/unix/locks/fuchsia_mutex.rs @@ -86,9 +86,6 @@ impl Mutex { } #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] pub unsafe fn try_lock(&self) -> bool { let thread_self = zx_thread_self(); self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed).is_ok() @@ -138,7 +135,7 @@ impl Mutex { } } - // The state has changed or a wakeup occured, try to lock the mutex. + // The state has changed or a wakeup occurred, try to lock the mutex. match self.futex.compare_exchange(UNLOCKED, owned_state, Acquire, Relaxed) { Ok(_) => return, Err(updated) => state = updated, diff --git a/library/std/src/sys/unix/locks/futex_mutex.rs b/library/std/src/sys/unix/locks/futex_mutex.rs index 99ba86e5f99..33b13dad4d6 100644 --- a/library/std/src/sys/unix/locks/futex_mutex.rs +++ b/library/std/src/sys/unix/locks/futex_mutex.rs @@ -20,9 +20,6 @@ impl Mutex { } #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] pub unsafe fn try_lock(&self) -> bool { self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok() } @@ -53,7 +50,7 @@ impl Mutex { // We avoid an unnecessary write if it as already set to 2, // to be friendlier for the caches. if state != 2 && self.futex.swap(2, Acquire) == 0 { - // We changed it from 0 to 2, so we just succesfully locked it. + // We changed it from 0 to 2, so we just successfully locked it. return; } diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index b3bbbf743f8..0cc92244eca 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -54,7 +54,7 @@ fn is_read_lockable(state: u32) -> bool { // We don't allow read-locking if there's readers waiting, even if the lock is unlocked // and there's no writers waiting. The only situation when this happens is after unlocking, // at which point the unlocking thread might be waking up writers, which have priority over readers. - // The unlocking thread will clear the readers waiting bit and wake up readers, if necssary. + // The unlocking thread will clear the readers waiting bit and wake up readers, if necessary. state & MASK < MAX_READERS && !has_readers_waiting(state) && !has_writers_waiting(state) } diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs index f5f92f69358..9bb314b7010 100644 --- a/library/std/src/sys/unix/locks/mod.rs +++ b/library/std/src/sys/unix/locks/mod.rs @@ -11,21 +11,21 @@ cfg_if::cfg_if! { mod futex_rwlock; mod futex_condvar; pub(crate) use futex_mutex::{Mutex, MovableMutex}; - pub(crate) use futex_rwlock::{RwLock, MovableRwLock}; + pub(crate) use futex_rwlock::MovableRwLock; pub(crate) use futex_condvar::MovableCondvar; } else if #[cfg(target_os = "fuchsia")] { mod fuchsia_mutex; mod futex_rwlock; mod futex_condvar; pub(crate) use fuchsia_mutex::{Mutex, MovableMutex}; - pub(crate) use futex_rwlock::{RwLock, MovableRwLock}; + pub(crate) use futex_rwlock::MovableRwLock; pub(crate) use futex_condvar::MovableCondvar; } else { mod pthread_mutex; mod pthread_rwlock; mod pthread_condvar; pub(crate) use pthread_mutex::{Mutex, MovableMutex}; - pub(crate) use pthread_rwlock::{RwLock, MovableRwLock}; + pub(crate) use pthread_rwlock::MovableRwLock; pub(crate) use pthread_condvar::MovableCondvar; } } diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs index 98afee69ba6..5964935ddb5 100644 --- a/library/std/src/sys/unix/locks/pthread_mutex.rs +++ b/library/std/src/sys/unix/locks/pthread_mutex.rs @@ -52,7 +52,7 @@ impl Mutex { Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } #[inline] - pub unsafe fn init(&mut self) { + unsafe fn init(&mut self) { // Issue #33770 // // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 3a375093099..c84e292eac1 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -44,12 +44,13 @@ pub mod thread_parker; pub mod time; #[cfg(target_os = "espidf")] -pub fn init(argc: isize, argv: *const *const u8) {} +pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {} #[cfg(not(target_os = "espidf"))] // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -pub unsafe fn init(argc: isize, argv: *const *const u8) { +// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`. +pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // The standard streams might be closed on application startup. To prevent // std::io::{stdin, stdout,stderr} objects from using other unrelated file // resources opened later, we reopen standards streams when they are closed. @@ -61,8 +62,9 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { // want! // // Hence, we set SIGPIPE to ignore when the program starts up in order - // to prevent this problem. - reset_sigpipe(); + // to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to + // alter this behavior. + reset_sigpipe(sigpipe); stack_overflow::init(); args::init(argc, argv); @@ -151,9 +153,31 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { } } - unsafe fn reset_sigpipe() { + unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) { #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))] - rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); + { + // We don't want to add this as a public type to libstd, nor do we + // want to `include!` a file from the compiler (which would break + // Miri and xargo for example), so we choose to duplicate these + // constants from `compiler/rustc_session/src/config/sigpipe.rs`. + // See the other file for docs. NOTE: Make sure to keep them in + // sync! + mod sigpipe { + pub const INHERIT: u8 = 1; + pub const SIG_IGN: u8 = 2; + pub const SIG_DFL: u8 = 3; + } + + let handler = match sigpipe { + sigpipe::INHERIT => None, + sigpipe::SIG_IGN => Some(libc::SIG_IGN), + sigpipe::SIG_DFL => Some(libc::SIG_DFL), + _ => unreachable!(), + }; + if let Some(handler) = handler { + rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR); + } + } } } diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 46545a0839f..7c70ddbd9b9 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -17,10 +17,10 @@ use crate::path::{self, PathBuf}; use crate::ptr; use crate::slice; use crate::str; +use crate::sync::{PoisonError, RwLock}; use crate::sys::cvt; use crate::sys::fd; use crate::sys::memchr; -use crate::sys_common::rwlock::{StaticRwLock, StaticRwLockReadGuard}; use crate::vec; #[cfg(all(target_env = "gnu", not(target_os = "vxworks")))] @@ -125,7 +125,9 @@ pub fn error_string(errno: i32) -> String { } let p = p as *const _; - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() + // We can't always expect a UTF-8 environment. When we don't get that luxury, + // it's better to give a low-quality error message than none at all. + String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into() } } @@ -501,10 +503,10 @@ pub unsafe fn environ() -> *mut *const *const c_char { ptr::addr_of_mut!(environ) } -static ENV_LOCK: StaticRwLock = StaticRwLock::new(); +static ENV_LOCK: RwLock<()> = RwLock::new(()); -pub fn env_read_lock() -> StaticRwLockReadGuard { - ENV_LOCK.read() +pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) } /// Returns a vector of (variable, value) byte-vector pairs for all the diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 26ae6281771..2ff8e600f7c 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -822,14 +822,14 @@ impl crate::os::linux::process::ChildExt for crate::process::Child { self.handle .pidfd .as_ref() - .ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created.")) + .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created.")) } fn take_pidfd(&mut self) -> io::Result<PidFd> { self.handle .pidfd .take() - .ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created.")) + .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created.")) } } diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 7db3065dee0..56bb71b5dcb 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -429,7 +429,7 @@ mod cgroups { Some(b"") => Cgroup::V2, Some(controllers) if from_utf8(controllers) - .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) => + .is_ok_and(|c| c.split(',').any(|c| c == "cpu")) => { Cgroup::V1 } diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parker/mod.rs new file mode 100644 index 00000000000..e2453580dc7 --- /dev/null +++ b/library/std/src/sys/unix/thread_parker/mod.rs @@ -0,0 +1,21 @@ +//! Thread parking on systems without futex support. + +#![cfg(not(any( + target_os = "linux", + target_os = "android", + all(target_os = "emscripten", target_feature = "atomics"), + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "fuchsia", +)))] + +cfg_if::cfg_if! { + if #[cfg(target_os = "netbsd")] { + mod netbsd; + pub use netbsd::Parker; + } else { + mod pthread; + pub use pthread::Parker; + } +} diff --git a/library/std/src/sys/unix/thread_parker/netbsd.rs b/library/std/src/sys/unix/thread_parker/netbsd.rs new file mode 100644 index 00000000000..7657605b52f --- /dev/null +++ b/library/std/src/sys/unix/thread_parker/netbsd.rs @@ -0,0 +1,113 @@ +use crate::ffi::{c_int, c_void}; +use crate::pin::Pin; +use crate::ptr::{null, null_mut}; +use crate::sync::atomic::{ + AtomicU64, + Ordering::{Acquire, Relaxed, Release}, +}; +use crate::time::Duration; +use libc::{_lwp_self, clockid_t, lwpid_t, time_t, timespec, CLOCK_MONOTONIC}; + +extern "C" { + fn ___lwp_park60( + clock_id: clockid_t, + flags: c_int, + ts: *mut timespec, + unpark: lwpid_t, + hint: *const c_void, + unparkhint: *const c_void, + ) -> c_int; + fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int; +} + +/// The thread is not parked and the token is not available. +/// +/// Zero cannot be a valid LWP id, since it is used as empty value for the unpark +/// argument in _lwp_park. +const EMPTY: u64 = 0; +/// The token is available. Do not park anymore. +const NOTIFIED: u64 = u64::MAX; + +pub struct Parker { + /// The parker state. Contains either one of the two state values above or the LWP + /// id of the parked thread. + state: AtomicU64, +} + +impl Parker { + pub unsafe fn new(parker: *mut Parker) { + parker.write(Parker { state: AtomicU64::new(EMPTY) }) + } + + // Does not actually need `unsafe` or `Pin`, but the pthread implementation does. + pub unsafe fn park(self: Pin<&Self>) { + // If the token has already been made available, we can skip + // a bit of work, so check for it here. + if self.state.load(Acquire) != NOTIFIED { + let parked = _lwp_self() as u64; + let hint = self.state.as_mut_ptr().cast(); + if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() { + // Loop to guard against spurious wakeups. + loop { + ___lwp_park60(0, 0, null_mut(), 0, hint, null()); + if self.state.load(Acquire) == NOTIFIED { + break; + } + } + } + } + + // At this point, the change to NOTIFIED has always been observed with acquire + // ordering, so we can just use a relaxed store here (instead of a swap). + self.state.store(EMPTY, Relaxed); + } + + // Does not actually need `unsafe` or `Pin`, but the pthread implementation does. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + if self.state.load(Acquire) != NOTIFIED { + let parked = _lwp_self() as u64; + let hint = self.state.as_mut_ptr().cast(); + let mut timeout = timespec { + // Saturate so that the operation will definitely time out + // (even if it is after the heat death of the universe). + tv_sec: dur.as_secs().try_into().ok().unwrap_or(time_t::MAX), + tv_nsec: dur.subsec_nanos().into(), + }; + + if self.state.compare_exchange(EMPTY, parked, Relaxed, Acquire).is_ok() { + // Timeout needs to be mutable since it is modified on NetBSD 9.0 and + // above. + ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, hint, null()); + // Use a swap to get acquire ordering even if the token was set after + // the timeout occurred. + self.state.swap(EMPTY, Acquire); + return; + } + } + + self.state.store(EMPTY, Relaxed); + } + + // Does not actually need `Pin`, but the pthread implementation does. + pub fn unpark(self: Pin<&Self>) { + let state = self.state.swap(NOTIFIED, Release); + if !matches!(state, EMPTY | NOTIFIED) { + let lwp = state as lwpid_t; + let hint = self.state.as_mut_ptr().cast(); + + // If the parking thread terminated and did not actually park, this will + // probably return an error, which is OK. In the worst case, another + // thread has received the same LWP id. It will then receive a spurious + // wakeup, but those are allowable per the API contract. The same reasoning + // applies if a timeout occurred before this call, but the state was not + // yet reset. + + // SAFETY: + // The syscall has no invariants to hold. Only unsafe because it is an + // extern function. + unsafe { + _lwp_unpark(lwp, hint); + } + } + } +} diff --git a/library/std/src/sys/unix/thread_parker.rs b/library/std/src/sys/unix/thread_parker/pthread.rs index ca1a7138fde..3dfc0026ed1 100644 --- a/library/std/src/sys/unix/thread_parker.rs +++ b/library/std/src/sys/unix/thread_parker/pthread.rs @@ -1,15 +1,5 @@ //! Thread parking without `futex` using the `pthread` synchronization primitives. -#![cfg(not(any( - target_os = "linux", - target_os = "android", - all(target_os = "emscripten", target_feature = "atomics"), - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - target_os = "fuchsia", -)))] - use crate::cell::UnsafeCell; use crate::marker::PhantomPinned; use crate::pin::Pin; @@ -59,8 +49,8 @@ unsafe fn wait_timeout( target_os = "espidf" ))] let (now, dur) = { - use super::time::SystemTime; use crate::cmp::min; + use crate::sys::time::SystemTime; // OSX implementation of `pthread_cond_timedwait` is buggy // with super long durations. When duration is greater than @@ -85,7 +75,7 @@ unsafe fn wait_timeout( target_os = "espidf" )))] let (now, dur) = { - use super::time::Timespec; + use crate::sys::time::Timespec; (Timespec::now(libc::CLOCK_MONOTONIC), dur) }; |
