lookup c_ulong instead of hard-coding the chunk size
This commit is contained in:
parent
c77a2c6c0c
commit
9a0e671cc2
5 changed files with 58 additions and 57 deletions
|
|
@ -1,6 +1,8 @@
|
|||
use crate::bug;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_target::abi::Endian;
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// The maximum number of CPUs supported by miri.
|
||||
///
|
||||
/// This value is compatible with the libc `CPU_SETSIZE` constant and corresponds to the number
|
||||
|
|
@ -19,41 +21,34 @@ pub(crate) struct CpuAffinityMask([u8; Self::CPU_MASK_BYTES]);
|
|||
impl CpuAffinityMask {
|
||||
pub(crate) const CPU_MASK_BYTES: usize = MAX_CPUS / 8;
|
||||
|
||||
pub fn new(target: &rustc_target::spec::Target, cpu_count: u32) -> Self {
|
||||
pub fn new<'tcx>(cx: &impl LayoutOf<'tcx>, cpu_count: u32) -> Self {
|
||||
let mut this = Self([0; Self::CPU_MASK_BYTES]);
|
||||
|
||||
// the default affinity mask includes only the available CPUs
|
||||
for i in 0..cpu_count as usize {
|
||||
this.set(target, i);
|
||||
this.set(cx, i);
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
pub fn chunk_size(target: &rustc_target::spec::Target) -> u64 {
|
||||
// The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
|
||||
//
|
||||
// - [u32; 32] on 32-bit platforms
|
||||
// - [u64; 16] everywhere else
|
||||
|
||||
// FIXME: this should be `size_of::<core::ffi::c_ulong>()`
|
||||
u64::from(target.pointer_width / 8)
|
||||
pub fn chunk_size<'tcx>(cx: &impl LayoutOf<'tcx>) -> u64 {
|
||||
// The actual representation of the CpuAffinityMask is [c_ulong; _].
|
||||
let ulong = helpers::path_ty_layout(cx, &["core", "ffi", "c_ulong"]);
|
||||
ulong.size.bytes()
|
||||
}
|
||||
|
||||
fn set(&mut self, target: &rustc_target::spec::Target, cpu: usize) {
|
||||
fn set<'tcx>(&mut self, cx: &impl LayoutOf<'tcx>, cpu: usize) {
|
||||
// we silently ignore CPUs that are out of bounds. This matches the behavior of
|
||||
// `sched_setaffinity` with a mask that specifies more than `CPU_SETSIZE` CPUs.
|
||||
if cpu >= MAX_CPUS {
|
||||
return;
|
||||
}
|
||||
|
||||
// The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
|
||||
//
|
||||
// - [u32; 32] on 32-bit platforms
|
||||
// - [u64; 16] everywhere else
|
||||
//
|
||||
// The actual representation of the CpuAffinityMask is [c_ulong; _].
|
||||
// Within the array elements, we need to use the endianness of the target.
|
||||
match Self::chunk_size(target) {
|
||||
let target = &cx.tcx().sess.target;
|
||||
match Self::chunk_size(cx) {
|
||||
4 => {
|
||||
let start = cpu / 32 * 4; // first byte of the correct u32
|
||||
let chunk = self.0[start..].first_chunk_mut::<4>().unwrap();
|
||||
|
|
@ -72,7 +67,7 @@ impl CpuAffinityMask {
|
|||
Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
|
||||
};
|
||||
}
|
||||
other => bug!("other chunk sizes are not supported: {other}"),
|
||||
other => bug!("chunk size not supported: {other}"),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -80,13 +75,13 @@ impl CpuAffinityMask {
|
|||
self.0.as_slice()
|
||||
}
|
||||
|
||||
pub fn from_array(
|
||||
target: &rustc_target::spec::Target,
|
||||
pub fn from_array<'tcx>(
|
||||
cx: &impl LayoutOf<'tcx>,
|
||||
cpu_count: u32,
|
||||
bytes: [u8; Self::CPU_MASK_BYTES],
|
||||
) -> Option<Self> {
|
||||
// mask by what CPUs are actually available
|
||||
let default = Self::new(target, cpu_count);
|
||||
let default = Self::new(cx, cpu_count);
|
||||
let masked = std::array::from_fn(|i| bytes[i] & default.0[i]);
|
||||
|
||||
// at least one thread must be set for the input to be valid
|
||||
|
|
|
|||
|
|
@ -282,7 +282,8 @@ pub fn create_ecx<'tcx>(
|
|||
})?;
|
||||
|
||||
// Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
|
||||
let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
|
||||
let sentinel =
|
||||
helpers::try_resolve_path(tcx, &["core", "ascii", "escape_default"], Namespace::ValueNS);
|
||||
if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
|
||||
tcx.dcx().fatal(
|
||||
"the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
|||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols::ExportedSymbol;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::layout::MaybeResult;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
layout::{LayoutOf, TyAndLayout},
|
||||
|
|
@ -159,6 +160,35 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>)
|
|||
None
|
||||
}
|
||||
|
||||
/// Gets an instance for a path; fails gracefully if the path does not exist.
|
||||
pub fn try_resolve_path<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
path: &[&str],
|
||||
namespace: Namespace,
|
||||
) -> Option<ty::Instance<'tcx>> {
|
||||
let did = try_resolve_did(tcx, path, Some(namespace))?;
|
||||
Some(ty::Instance::mono(tcx, did))
|
||||
}
|
||||
|
||||
/// Gets an instance for a path.
|
||||
#[track_caller]
|
||||
pub fn resolve_path<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
path: &[&str],
|
||||
namespace: Namespace,
|
||||
) -> ty::Instance<'tcx> {
|
||||
try_resolve_path(tcx, path, namespace)
|
||||
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
|
||||
}
|
||||
|
||||
/// Gets the layout of a type at a path.
|
||||
#[track_caller]
|
||||
pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> {
|
||||
let ty =
|
||||
resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), ty::ParamEnv::reveal_all());
|
||||
cx.layout_of(ty).to_result().ok().unwrap()
|
||||
}
|
||||
|
||||
/// Call `f` for each exported symbol.
|
||||
pub fn iter_exported_symbols<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
@ -259,23 +289,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
|
||||
}
|
||||
|
||||
/// Gets an instance for a path; fails gracefully if the path does not exist.
|
||||
fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
|
||||
let tcx = self.eval_context_ref().tcx.tcx;
|
||||
let did = try_resolve_did(tcx, path, Some(namespace))?;
|
||||
Some(ty::Instance::mono(tcx, did))
|
||||
}
|
||||
|
||||
/// Gets an instance for a path.
|
||||
fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> {
|
||||
self.try_resolve_path(path, namespace)
|
||||
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
|
||||
}
|
||||
|
||||
/// Evaluates the scalar at the specified path.
|
||||
fn eval_path(&self, path: &[&str]) -> OpTy<'tcx> {
|
||||
let this = self.eval_context_ref();
|
||||
let instance = this.resolve_path(path, Namespace::ValueNS);
|
||||
let instance = resolve_path(*this.tcx, path, Namespace::ValueNS);
|
||||
// We don't give a span -- this isn't actually used directly by the program anyway.
|
||||
let const_val = this.eval_global(instance).unwrap_or_else(|err| {
|
||||
panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
|
||||
|
|
@ -344,19 +361,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
"`libc` crate is not reliably available on Windows targets; Miri should not use it there"
|
||||
);
|
||||
}
|
||||
let ty = this
|
||||
.resolve_path(&["libc", name], Namespace::TypeNS)
|
||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||
this.layout_of(ty).unwrap()
|
||||
path_ty_layout(this, &["libc", name])
|
||||
}
|
||||
|
||||
/// Helper function to get the `TyAndLayout` of a `windows` type
|
||||
fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
|
||||
let this = self.eval_context_ref();
|
||||
let ty = this
|
||||
.resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS)
|
||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||
this.layout_of(ty).unwrap()
|
||||
path_ty_layout(this, &["std", "sys", "pal", "windows", "c", name])
|
||||
}
|
||||
|
||||
/// Project to the given *named* field (which must be a struct or union type).
|
||||
|
|
|
|||
|
|
@ -643,10 +643,8 @@ impl<'tcx> MiriMachine<'tcx> {
|
|||
let threads = ThreadManager::default();
|
||||
let mut thread_cpu_affinity = FxHashMap::default();
|
||||
if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") {
|
||||
thread_cpu_affinity.insert(
|
||||
threads.active_thread(),
|
||||
CpuAffinityMask::new(&tcx.sess.target, config.num_cpus),
|
||||
);
|
||||
thread_cpu_affinity
|
||||
.insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus));
|
||||
}
|
||||
MiriMachine {
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -594,11 +594,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
_ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"),
|
||||
};
|
||||
|
||||
// The actual representation of the CpuAffinityMask is [c_ulong; _], in practice either
|
||||
//
|
||||
// - [u32; 32] on 32-bit platforms
|
||||
// - [u64; 16] everywhere else
|
||||
let chunk_size = CpuAffinityMask::chunk_size(&this.tcx.sess.target);
|
||||
// The mask is stored in chunks, and the size must be a whole number of chunks.
|
||||
let chunk_size = CpuAffinityMask::chunk_size(this);
|
||||
|
||||
if this.ptr_is_null(mask)? {
|
||||
let einval = this.eval_libc("EFAULT");
|
||||
|
|
@ -643,7 +640,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
_ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"),
|
||||
};
|
||||
|
||||
#[allow(clippy::map_entry)]
|
||||
if this.ptr_is_null(mask)? {
|
||||
let einval = this.eval_libc("EFAULT");
|
||||
this.set_last_error(einval)?;
|
||||
|
|
@ -652,9 +648,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
// NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`
|
||||
let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
|
||||
// This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
|
||||
let bits_array: [u8;CpuAffinityMask::CPU_MASK_BYTES] =
|
||||
let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
|
||||
std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
|
||||
match CpuAffinityMask::from_array(&this.tcx.sess.target, this.machine.num_cpus, bits_array) {
|
||||
match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
|
||||
Some(cpuset) => {
|
||||
this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
|
||||
this.write_scalar(Scalar::from_i32(0), dest)?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue