tid handling: cleanup and unification

This commit is contained in:
Ralf Jung
2026-05-03 19:36:04 +02:00
parent 85298e9992
commit 64ab20128c
8 changed files with 38 additions and 31 deletions
@@ -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);
+9 -18
View File
@@ -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
}
}
}
+3 -2
View File
@@ -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
+2 -1
View File
@@ -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);