about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/fs.rs7
-rw-r--r--library/std/src/panic.rs4
-rw-r--r--library/std/src/panicking.rs3
-rw-r--r--library/std/src/path.rs2
-rw-r--r--library/std/src/sys/args/common.rs2
-rw-r--r--library/std/src/sys/pal/hermit/thread.rs4
-rw-r--r--library/std/src/sys/pal/itron/thread.rs4
-rw-r--r--library/std/src/sys/pal/sgx/thread.rs6
-rw-r--r--library/std/src/sys/pal/teeos/thread.rs4
-rw-r--r--library/std/src/sys/pal/uefi/thread.rs4
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs6
-rw-r--r--library/std/src/sys/pal/unix/thread.rs56
-rw-r--r--library/std/src/sys/pal/unsupported/thread.rs4
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs4
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt1
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs1
-rw-r--r--library/std/src/sys/pal/windows/stack_overflow.rs3
-rw-r--r--library/std/src/sys/pal/windows/thread.rs8
-rw-r--r--library/std/src/sys/pal/xous/thread.rs4
-rw-r--r--library/std/src/thread/current.rs13
-rw-r--r--library/std/src/thread/mod.rs2
-rw-r--r--library/std/src/thread/tests.rs7
22 files changed, 137 insertions, 12 deletions
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 72ad7c244ee..b3ca118a452 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1111,6 +1111,11 @@ impl File {
     /// `futimes` on macOS before 10.13) and the `SetFileTime` function on Windows. Note that this
     /// [may change in the future][changes].
     ///
+    /// On most platforms, including UNIX and Windows platforms, this function can also change the
+    /// timestamps of a directory. To get a `File` representing a directory in order to call
+    /// `set_times`, open the directory with `File::open` without attempting to obtain write
+    /// permission.
+    ///
     /// [changes]: io#platform-specific-behavior
     ///
     /// # Errors
@@ -1128,7 +1133,7 @@ impl File {
     ///     use std::fs::{self, File, FileTimes};
     ///
     ///     let src = fs::metadata("src")?;
-    ///     let dest = File::options().write(true).open("dest")?;
+    ///     let dest = File::open("dest")?;
     ///     let times = FileTimes::new()
     ///         .set_accessed(src.accessed()?)
     ///         .set_modified(src.modified()?);
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 913ef72f674..cff4f20b5a8 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -108,8 +108,6 @@ impl<'a> PanicHookInfo<'a> {
     /// # Example
     ///
     /// ```should_panic
-    /// #![feature(panic_payload_as_str)]
-    ///
     /// std::panic::set_hook(Box::new(|panic_info| {
     ///     if let Some(s) = panic_info.payload_as_str() {
     ///         println!("panic occurred: {s:?}");
@@ -122,7 +120,7 @@ impl<'a> PanicHookInfo<'a> {
     /// ```
     #[must_use]
     #[inline]
-    #[unstable(feature = "panic_payload_as_str", issue = "125175")]
+    #[stable(feature = "panic_payload_as_str", since = "CURRENT_RUSTC_VERSION")]
     pub fn payload_as_str(&self) -> Option<&str> {
         if let Some(s) = self.payload.downcast_ref::<&str>() {
             Some(s)
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 224cd39855a..547906ca7dc 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -269,6 +269,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
 
         thread::with_current_name(|name| {
             let name = name.unwrap_or("<unnamed>");
+            let tid = thread::current_os_id();
 
             // Try to write the panic message to a buffer first to prevent other concurrent outputs
             // interleaving with it.
@@ -277,7 +278,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
 
             let write_msg = |dst: &mut dyn crate::io::Write| {
                 // We add a newline to ensure the panic message appears at the start of a line.
-                writeln!(dst, "\nthread '{name}' panicked at {location}:\n{msg}")
+                writeln!(dst, "\nthread '{name}' ({tid}) panicked at {location}:\n{msg}")
             };
 
             if write_msg(&mut cursor).is_ok() {
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 055e7f81480..e7ba6936435 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2683,6 +2683,8 @@ impl Path {
     ///
     /// assert_eq!("foo", Path::new("foo.rs").file_prefix().unwrap());
     /// assert_eq!("foo", Path::new("foo.tar.gz").file_prefix().unwrap());
+    /// assert_eq!(".config", Path::new(".config").file_prefix().unwrap());
+    /// assert_eq!(".config", Path::new(".config.toml").file_prefix().unwrap());
     /// ```
     ///
     /// # See Also
diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs
index e787105a05a..33f3794ee63 100644
--- a/library/std/src/sys/args/common.rs
+++ b/library/std/src/sys/args/common.rs
@@ -12,7 +12,7 @@ impl !Sync for Args {}
 
 impl Args {
     #[inline]
-    pub(super) fn new(args: Vec<OsString>) -> Self {
+    pub fn new(args: Vec<OsString>) -> Self {
         Args { iter: args.into_iter() }
     }
 }
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 95fe4f902d3..cc4734b6819 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -115,6 +115,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
 }
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index 0d28051fcc4..4e14cb3cbca 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -361,6 +361,10 @@ unsafe fn terminate_and_delete_current_task() -> ! {
     unsafe { crate::hint::unreachable_unchecked() };
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     super::unsupported()
 }
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index a236c362706..1f613badcd7 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -1,6 +1,6 @@
 #![cfg_attr(test, allow(dead_code))] // why is this necessary?
 
-use super::abi::usercalls;
+use super::abi::{thread, usercalls};
 use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
@@ -149,6 +149,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    Some(thread::current().addr().get() as u64)
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index a91d95626e7..1812d11e692 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -144,6 +144,10 @@ impl Drop for Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 // Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
 // teeos, so this function always returns an Error!
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
index 75c364362b2..47a48008c76 100644
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ b/library/std/src/sys/pal/uefi/thread.rs
@@ -56,6 +56,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // UEFI is single threaded
     Ok(NonZero::new(1).unwrap())
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index d89100e6919..0d2100d66bc 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -119,7 +119,8 @@ mod imp {
                     && thread_info.guard_page_range.contains(&fault_addr)
                 {
                     let name = thread_info.thread_name.as_deref().unwrap_or("<unknown>");
-                    rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
+                    let tid = crate::thread::current_os_id();
+                    rtprintpanic!("\nthread '{name}' ({tid}) has overflowed its stack\n");
                     rtabort!("stack overflow");
                 }
             })
@@ -696,7 +697,8 @@ mod imp {
             if code == c::EXCEPTION_STACK_OVERFLOW {
                 crate::thread::with_current_name(|name| {
                     let name = name.unwrap_or("<unknown>");
-                    rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
+                    let tid = crate::thread::current_os_id();
+                    rtprintpanic!("\nthread '{name}' ({tid}) has overflowed its stack\n");
                 });
             }
             c::EXCEPTION_CONTINUE_SEARCH
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 7f6440152d4..36e53e7cadc 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -398,6 +398,62 @@ impl Drop for Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    // Most Unix platforms have a way to query an integer ID of the current thread, all with
+    // slightly different spellings.
+    //
+    // The OS thread ID is used rather than `pthread_self` so as to match what will be displayed
+    // for process inspection (debuggers, trace, `top`, etc.).
+    cfg_if::cfg_if! {
+        // Most platforms have a function returning a `pid_t` or int, which is an `i32`.
+        if #[cfg(any(target_os = "android", target_os = "linux"))] {
+            use crate::sys::weak::syscall;
+
+            // `libc::gettid` is only available on glibc 2.30+, but the syscall is available
+            // since Linux 2.4.11.
+            syscall!(fn gettid() -> libc::pid_t;);
+
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { gettid() };
+            Some(id as u64)
+        } else if #[cfg(target_os = "nto")] {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { libc::gettid() };
+            Some(id as u64)
+        } else if #[cfg(target_os = "openbsd")] {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { libc::getthrid() };
+            Some(id as u64)
+        } else if #[cfg(target_os = "freebsd")] {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
+            Some(id as u64)
+        } else if #[cfg(target_os = "netbsd")] {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
+            Some(id as u64)
+        } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
+            // On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID.
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pthread_t = unsafe { libc::pthread_self() };
+            Some(id as u64)
+        } else if #[cfg(target_vendor = "apple")] {
+            // Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
+            let mut id = 0u64;
+            // SAFETY: `thread_id` is a valid pointer, no other preconditions.
+            let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
+            if status == 0 {
+                Some(id)
+            } else {
+                None
+            }
+        } else {
+            // Other platforms don't have an OS thread ID or don't have a way to access it.
+            None
+        }
+    }
+}
+
 #[cfg(any(
     target_os = "linux",
     target_os = "nto",
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs
index 5a1e3fde986..34d9b5ec70c 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/pal/unsupported/thread.rs
@@ -39,6 +39,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index a46c74630c9..4755e2ef5da 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -194,6 +194,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     cfg_if::cfg_if! {
         if #[cfg(target_feature = "atomics")] {
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index 827d96e73db..c8e4dca4781 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2185,6 +2185,7 @@ GetSystemInfo
 GetSystemTimeAsFileTime
 GetSystemTimePreciseAsFileTime
 GetTempPathW
+GetThreadId
 GetUserProfileDirectoryW
 GetWindowsDirectoryW
 HANDLE
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index b2e3aabc633..45a273d241a 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -61,6 +61,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *
 windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
 windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
 windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetThreadId(thread : HANDLE) -> u32);
 windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
 windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL);
diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs
index 734cd30bed0..9a40551b985 100644
--- a/library/std/src/sys/pal/windows/stack_overflow.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow.rs
@@ -20,7 +20,8 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN
         if code == c::EXCEPTION_STACK_OVERFLOW {
             thread::with_current_name(|name| {
                 let name = name.unwrap_or("<unknown>");
-                rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
+                let tid = thread::current_os_id();
+                rtprintpanic!("\nthread '{name}' ({tid}) has overflowed its stack\n");
             });
         }
         c::EXCEPTION_CONTINUE_SEARCH
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index b45f76fb546..c708da5af12 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -127,6 +127,14 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    // SAFETY: FFI call with no preconditions.
+    let id: u32 = unsafe { c::GetThreadId(c::GetCurrentThread()) };
+
+    // A return value of 0 indicates failed lookup.
+    if id == 0 { None } else { Some(id.into()) }
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     let res = unsafe {
         let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed();
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index f2404a62abf..92803c94c6e 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -145,6 +145,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // We're unicore right now.
     Ok(unsafe { NonZero::new_unchecked(1) })
diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs
index 414711298f0..5c879903526 100644
--- a/library/std/src/thread/current.rs
+++ b/library/std/src/thread/current.rs
@@ -1,4 +1,4 @@
-use super::{Thread, ThreadId};
+use super::{Thread, ThreadId, imp};
 use crate::mem::ManuallyDrop;
 use crate::ptr;
 use crate::sys::thread_local::local_pointer;
@@ -148,6 +148,17 @@ pub(crate) fn current_id() -> ThreadId {
     id::get_or_init()
 }
 
+/// Gets the OS thread ID of the thread that invokes it, if available. If not, return the Rust
+/// thread ID.
+///
+/// We use a `u64` to all possible platform IDs without excess `cfg`; most use `int`, some use a
+/// pointer, and Apple uses `uint64_t`. This is a "best effort" approach for diagnostics and is
+/// allowed to fall back to a non-OS ID (such as the Rust thread ID) or a non-unique ID (such as a
+/// PID) if the thread ID cannot be retrieved.
+pub(crate) fn current_os_id() -> u64 {
+    imp::current_os_id().unwrap_or_else(|| current_id().as_u64().get())
+}
+
 /// Gets a reference to the handle of the thread that invokes it, if the handle
 /// has been initialized.
 pub(super) fn try_with_current<F, R>(f: F) -> R
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 8d3ab82ace1..292323d0118 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -183,7 +183,7 @@ mod current;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use current::current;
-pub(crate) use current::{current_id, current_or_unnamed, drop_current};
+pub(crate) use current::{current_id, current_or_unnamed, current_os_id, drop_current};
 use current::{set_current, try_with_current};
 
 mod spawnhook;
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index 59ec48a57d1..ae889f1e778 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -347,6 +347,13 @@ fn test_thread_id_not_equal() {
 }
 
 #[test]
+fn test_thread_os_id_not_equal() {
+    let spawned_id = thread::spawn(|| thread::current_os_id()).join().unwrap();
+    let current_id = thread::current_os_id();
+    assert!(current_id != spawned_id);
+}
+
+#[test]
 fn test_scoped_threads_drop_result_before_join() {
     let actually_finished = &AtomicBool::new(false);
     struct X<'scope, 'env>(&'scope Scope<'scope, 'env>, &'env AtomicBool);