about summary refs log tree commit diff
path: root/library/std/src/sys/unix
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/unix')
-rw-r--r--library/std/src/sys/unix/locks/fuchsia_mutex.rs5
-rw-r--r--library/std/src/sys/unix/locks/futex_mutex.rs5
-rw-r--r--library/std/src/sys/unix/locks/futex_rwlock.rs2
-rw-r--r--library/std/src/sys/unix/locks/mod.rs6
-rw-r--r--library/std/src/sys/unix/locks/pthread_mutex.rs2
-rw-r--r--library/std/src/sys/unix/mod.rs36
-rw-r--r--library/std/src/sys/unix/os.rs12
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs2
-rw-r--r--library/std/src/sys/unix/thread_parker/mod.rs21
-rw-r--r--library/std/src/sys/unix/thread_parker/netbsd.rs113
-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)
     };