mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-06 08:36:52 -04:00
tid handling: cleanup and unification
This commit is contained in:
@@ -219,7 +219,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
this.machine.blocking_io.register(
|
||||
source_fd,
|
||||
InterestReceiver::UnblockThread(this.machine.threads.active_thread()),
|
||||
InterestReceiver::UnblockThread(this.active_thread()),
|
||||
interests,
|
||||
);
|
||||
this.block_thread(BlockReason::IO, timeout, callback);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::assert_matches;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@@ -108,32 +109,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
if this.machine.communicate() { std::process::id() } else { 1000 }
|
||||
}
|
||||
|
||||
/// Get an "OS" thread ID for the current thread.
|
||||
fn get_current_tid(&self) -> u32 {
|
||||
/// Get an "OS" thread ID for any thread.
|
||||
fn get_tid(&self, thread: ThreadId) -> u32 {
|
||||
let this = self.eval_context_ref();
|
||||
self.get_tid(this.machine.threads.active_thread())
|
||||
assert!(this.target_os_is_unix());
|
||||
// On Linux, the main thread has PID == TID so we uphold this. For simplicity we do it
|
||||
// everywhere. That also ensures this ID is different from what is returned by
|
||||
// `pthread_self`.
|
||||
this.get_pid().strict_add(thread.to_u32())
|
||||
}
|
||||
|
||||
/// Convert TID back to a `ThreadId`, or `None` if it is invalid or the thread has terminated.
|
||||
fn get_thread_id_from_linux_tid(&self, tid: u32) -> Option<ThreadId> {
|
||||
let this = self.eval_context_ref();
|
||||
debug_assert!(matches!(this.tcx.sess.target.os, Os::Linux | Os::Android));
|
||||
assert_matches!(this.tcx.sess.target.os, Os::Linux | Os::Android);
|
||||
// TID = PID + thread_index => index = TID - PID.
|
||||
let id = tid.checked_sub(this.get_pid())?;
|
||||
this.machine.threads.thread_id_try_from(id).ok()
|
||||
}
|
||||
|
||||
/// Get an "OS" thread ID for any thread.
|
||||
fn get_tid(&self, thread: ThreadId) -> u32 {
|
||||
let this = self.eval_context_ref();
|
||||
let index = thread.to_u32();
|
||||
let target_os = &this.tcx.sess.target.os;
|
||||
if matches!(target_os, Os::Linux | Os::Android) {
|
||||
// On Linux, the main thread has PID == TID so we uphold this.
|
||||
this.get_pid().strict_add(index)
|
||||
} else {
|
||||
// Other platforms do not display any relationship between PID and TID.
|
||||
index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
|
||||
// For most platforms the return type is an `i32`, but some are unsigned. The TID
|
||||
// will always be positive so we don't need to differentiate.
|
||||
interp_ok(Scalar::from_u32(this.get_current_tid()))
|
||||
interp_ok(Scalar::from_u32(this.get_tid(this.active_thread())))
|
||||
}
|
||||
|
||||
/// `fields_size`, if present, says how large each field of the struct is.
|
||||
@@ -323,7 +323,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
/// allows querying the ID for arbitrary threads, identified by their pthread_t.
|
||||
///
|
||||
/// API documentation: <https://www.manpagez.com/man/3/pthread_threadid_np/>.
|
||||
fn apple_pthread_threadip_np(
|
||||
fn apple_pthread_threadid_np(
|
||||
&mut self,
|
||||
thread_op: &OpTy<'tcx>,
|
||||
tid_op: &OpTy<'tcx>,
|
||||
@@ -349,6 +349,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
thread
|
||||
};
|
||||
|
||||
// This returns an `int`, not a `pthread_t`, so we treat it like we treat `gettid` on Linux.
|
||||
let tid = this.get_tid(thread);
|
||||
let tid_dest = this.deref_pointer_as(tid_op, this.machine.layouts.u64)?;
|
||||
this.write_int(tid, &tid_dest)?;
|
||||
|
||||
@@ -180,6 +180,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
&[Os::Linux, Os::Android, Os::MacOs, Os::Solaris, Os::Illumos],
|
||||
link_name,
|
||||
)?;
|
||||
|
||||
let [uname] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*mut _) -> i32),
|
||||
link_name,
|
||||
@@ -296,6 +297,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
"flock" => {
|
||||
// Currently this function does not exist on all Unixes, e.g. on Solaris.
|
||||
this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::MacOs, Os::Illumos], link_name)?;
|
||||
|
||||
let [fd, op] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, i32) -> i32),
|
||||
link_name,
|
||||
@@ -495,6 +497,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
&[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android],
|
||||
link_name,
|
||||
)?;
|
||||
|
||||
let [fd, offset, len] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32),
|
||||
link_name,
|
||||
@@ -560,6 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
&[Os::Linux, Os::Android, Os::FreeBsd, Os::Solaris, Os::Illumos],
|
||||
link_name,
|
||||
)?;
|
||||
|
||||
let [pipefd, flags] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*mut _, i32) -> i32),
|
||||
link_name,
|
||||
@@ -743,6 +747,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
"reallocarray" => {
|
||||
// Currently this function does not exist on all Unixes, e.g. on macOS.
|
||||
this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
|
||||
|
||||
let [ptr, nmemb, size] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let ptr = this.read_pointer(ptr)?;
|
||||
@@ -1020,6 +1025,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
&[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos],
|
||||
link_name,
|
||||
)?;
|
||||
|
||||
let [clock_id, flags, req, rem] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
|
||||
@@ -1028,6 +1034,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
"sched_getaffinity" => {
|
||||
// Currently this function does not exist on all Unixes, e.g. on macOS.
|
||||
this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
|
||||
|
||||
let [pid, cpusetsize, mask] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let pid = this.read_scalar(pid)?.to_u32()?;
|
||||
@@ -1072,6 +1079,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
"sched_setaffinity" => {
|
||||
// Currently this function does not exist on all Unixes, e.g. on macOS.
|
||||
this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?;
|
||||
|
||||
let [pid, cpusetsize, mask] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let pid = this.read_scalar(pid)?.to_u32()?;
|
||||
@@ -1140,6 +1148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
&[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
|
||||
link_name,
|
||||
)?;
|
||||
|
||||
let [buf, bufsize] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let buf = this.read_pointer(buf)?;
|
||||
@@ -1172,6 +1181,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
&[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android],
|
||||
link_name,
|
||||
)?;
|
||||
|
||||
let [ptr, len, flags] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let ptr = this.read_pointer(ptr)?;
|
||||
@@ -1185,6 +1195,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
// This function is non-standard but exists with the same signature and
|
||||
// same behavior (eg never fails) on FreeBSD and Solaris/Illumos.
|
||||
this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?;
|
||||
|
||||
let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let ptr = this.read_pointer(ptr)?;
|
||||
let len = this.read_target_usize(len)?;
|
||||
@@ -1208,6 +1219,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
&[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs],
|
||||
link_name,
|
||||
)?;
|
||||
|
||||
// This function looks and behaves exactly like miri_start_unwind.
|
||||
let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
this.handle_miri_start_unwind(payload)?;
|
||||
|
||||
@@ -244,7 +244,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
"pthread_threadid_np" => {
|
||||
let [thread, tid_ptr] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let res = this.apple_pthread_threadip_np(thread, tid_ptr)?;
|
||||
let res = this.apple_pthread_threadid_np(thread, tid_ptr)?;
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -953,8 +953,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
|
||||
_ => this.invalid_handle("GetThreadDescription")?,
|
||||
};
|
||||
let tid = this.get_tid(thread);
|
||||
this.write_scalar(Scalar::from_u32(tid), dest)?;
|
||||
this.write_scalar(Scalar::from_u32(thread.to_u32()), dest)?;
|
||||
}
|
||||
"GetCurrentThreadId" => {
|
||||
let [] = this.check_shim_sig(
|
||||
@@ -963,9 +962,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
abi,
|
||||
args,
|
||||
)?;
|
||||
let thread = this.active_thread();
|
||||
let tid = this.get_tid(thread);
|
||||
this.write_scalar(Scalar::from_u32(tid), dest)?;
|
||||
this.write_scalar(Scalar::from_u32(this.active_thread().to_u32()), dest)?;
|
||||
}
|
||||
|
||||
// Miscellaneous
|
||||
|
||||
@@ -184,7 +184,8 @@ impl Handle {
|
||||
|
||||
match Self::from_packed(handle) {
|
||||
Some(Self::Thread(thread)) => {
|
||||
// Validate the thread id. Windows handles remain valid even after thread termination
|
||||
// Validate the thread id. Windows handles remain valid even after thread
|
||||
// termination.
|
||||
use crate::concurrency::thread::ThreadLookupError;
|
||||
match cx.machine.threads.thread_id_try_from(thread.to_u32()) {
|
||||
Ok(id) | Err(ThreadLookupError::Terminated(id)) =>
|
||||
|
||||
@@ -165,8 +165,13 @@ fn main() {
|
||||
// The value is not important, we only care that whatever the value is,
|
||||
// won't change from execution to execution.
|
||||
if cfg!(with_isolation) {
|
||||
if cfg!(any(target_os = "linux", target_os = "android")) {
|
||||
// Linux starts the TID at the PID, which is 1000.
|
||||
if cfg!(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "macos"
|
||||
)) {
|
||||
// On these OSes we start the TID at the PID, which is 1000.
|
||||
assert_eq!(tid, 1000);
|
||||
} else {
|
||||
// Other platforms start counting from 0.
|
||||
@@ -174,7 +179,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
// On Linux, the first TID is the PID.
|
||||
// On Linux, the main thread TID is the PID.
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
assert_eq!(tid, unsafe { libc::getpid() } as u64);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user