mirror of
https://github.com/rust-lang/rust.git
synced 2026-06-02 06:28:20 +03:00
Support running no_core Linux programs
Co-authored-by: Ralf Jung <post@ralfj.de>
This commit is contained in:
@@ -962,8 +962,11 @@ fn start_regular_thread(
|
||||
let old_thread_id = this.machine.threads.set_active_thread_id(new_thread_id);
|
||||
|
||||
// The child inherits its parent's cpu affinity.
|
||||
if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&old_thread_id).cloned() {
|
||||
this.machine.thread_cpu_affinity.insert(new_thread_id, cpuset);
|
||||
// Skips this if `machine.thread_cpu_affinity` is not initialized.
|
||||
if let Some(thread_cpu_affinity) = &mut this.machine.thread_cpu_affinity
|
||||
&& let Some(cpuset) = thread_cpu_affinity.get(&old_thread_id).cloned()
|
||||
{
|
||||
thread_cpu_affinity.insert(new_thread_id, cpuset);
|
||||
}
|
||||
|
||||
// Perform the function pointer load in the new thread frame.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
use crate::concurrency::GenmcCtx;
|
||||
use crate::concurrency::thread::TlsAllocAction;
|
||||
use crate::diagnostics::report_leaks;
|
||||
use crate::helpers::is_no_core;
|
||||
use crate::shims::{global_ctor, tls};
|
||||
use crate::*;
|
||||
|
||||
@@ -289,14 +290,20 @@ pub fn create_ecx<'tcx>(
|
||||
MiriMachine::new(config, layout_cx, genmc_ctx),
|
||||
);
|
||||
|
||||
// Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
|
||||
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.\n\
|
||||
Note that directly invoking the `miri` binary is not supported; please use `cargo miri` instead."
|
||||
// Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. However,
|
||||
// if the current crate is #![no_core] it's fine to be missing the usual items from libcore.
|
||||
if !is_no_core(tcx) {
|
||||
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.\n\
|
||||
Note that directly invoking the `miri` binary is not supported; please use `cargo miri` instead."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute argc and argv from `config.args`.
|
||||
|
||||
@@ -1085,6 +1085,11 @@ pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the local crate has the `#![no_core]` attribute.
|
||||
pub fn is_no_core(tcx: TyCtxt<'_>) -> bool {
|
||||
rustc_hir::find_attr!(tcx, crate, NoCore)
|
||||
}
|
||||
|
||||
/// We don't support 16-bit systems, so let's have ergonomic conversion from `u32` to `usize`.
|
||||
pub trait ToUsize {
|
||||
fn to_usize(self) -> usize;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
use crate::concurrency::{
|
||||
AllocDataRaceHandler, GenmcCtx, GenmcEvalContextExt as _, GlobalDataRaceHandler, weak_memory,
|
||||
};
|
||||
use crate::helpers::is_no_core;
|
||||
use crate::*;
|
||||
|
||||
/// First real-time signal.
|
||||
@@ -546,7 +547,8 @@ pub struct MiriMachine<'tcx> {
|
||||
/// Stores which thread is eligible to run on which CPUs.
|
||||
/// This has no effect at all, it is just tracked to produce the correct result
|
||||
/// in `sched_getaffinity`
|
||||
pub(crate) thread_cpu_affinity: FxHashMap<ThreadId, CpuAffinityMask>,
|
||||
/// This will be `None` when running `#![no_core]` crates.
|
||||
pub(crate) thread_cpu_affinity: Option<FxHashMap<ThreadId, CpuAffinityMask>>,
|
||||
|
||||
/// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri.
|
||||
pub(crate) layouts: PrimitiveLayouts<'tcx>,
|
||||
@@ -735,11 +737,19 @@ pub(crate) fn new(
|
||||
config.num_cpus
|
||||
);
|
||||
let threads = ThreadManager::new(config);
|
||||
let mut thread_cpu_affinity = FxHashMap::default();
|
||||
if matches!(&tcx.sess.target.os, Os::Linux | Os::FreeBsd | Os::Android) {
|
||||
thread_cpu_affinity
|
||||
.insert(threads.active_thread(), CpuAffinityMask::new(&layout_cx, config.num_cpus));
|
||||
}
|
||||
let thread_cpu_affinity =
|
||||
if matches!(&tcx.sess.target.os, Os::Linux | Os::FreeBsd | Os::Android)
|
||||
&& !is_no_core(tcx)
|
||||
{
|
||||
let mut affinity = FxHashMap::default();
|
||||
affinity.insert(
|
||||
threads.active_thread(),
|
||||
CpuAffinityMask::new(&layout_cx, config.num_cpus),
|
||||
);
|
||||
Some(affinity)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let blocking_io = BlockingIoManager::new(config.isolated_op == IsolatedOp::Allow)
|
||||
.expect("Couldn't create poll instance");
|
||||
let alloc_addresses =
|
||||
|
||||
@@ -1126,6 +1126,12 @@ fn emulate_foreign_item_inner(
|
||||
let cpusetsize = this.read_target_usize(cpusetsize)?;
|
||||
let mask = this.read_pointer(mask)?;
|
||||
|
||||
if this.machine.thread_cpu_affinity.is_none() {
|
||||
throw_unsup_format!(
|
||||
"`sched_getaffinity` is not supported on #![no_core] programs"
|
||||
)
|
||||
}
|
||||
|
||||
let thread_id = if pid == 0 {
|
||||
this.active_thread()
|
||||
} else if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android) {
|
||||
@@ -1149,7 +1155,9 @@ fn emulate_foreign_item_inner(
|
||||
} else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
|
||||
// we only copy whole chunks of size_of::<c_ulong>()
|
||||
this.set_errno_and_return_neg1(LibcError("EINVAL"), dest)?;
|
||||
} else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
|
||||
} else if let Some(cpuset) =
|
||||
this.machine.thread_cpu_affinity.as_ref().unwrap().get(&thread_id)
|
||||
{
|
||||
let cpuset = cpuset.clone();
|
||||
// we only copy whole chunks of size_of::<c_ulong>()
|
||||
let byte_count =
|
||||
@@ -1171,6 +1179,12 @@ fn emulate_foreign_item_inner(
|
||||
let cpusetsize = this.read_target_usize(cpusetsize)?;
|
||||
let mask = this.read_pointer(mask)?;
|
||||
|
||||
if this.machine.thread_cpu_affinity.is_none() {
|
||||
throw_unsup_format!(
|
||||
"`sched_setaffinity` is not supported on #![no_core] programs"
|
||||
)
|
||||
}
|
||||
|
||||
let thread_id = if pid == 0 {
|
||||
this.active_thread()
|
||||
} else if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android) {
|
||||
@@ -1199,7 +1213,11 @@ fn emulate_foreign_item_inner(
|
||||
std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
|
||||
match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
|
||||
Some(cpuset) => {
|
||||
this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
|
||||
this.machine
|
||||
.thread_cpu_affinity
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.insert(thread_id, cpuset);
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
None => {
|
||||
|
||||
@@ -75,6 +75,12 @@ fn emulate_foreign_item_inner(
|
||||
let set_size = this.read_target_usize(set_size)?; // measured in bytes
|
||||
let mask = this.read_pointer(mask)?;
|
||||
|
||||
if this.machine.thread_cpu_affinity.is_none() {
|
||||
throw_unsup_format!(
|
||||
"`cpuset_getaffinity` is not supported on #![no_core] programs"
|
||||
)
|
||||
}
|
||||
|
||||
let _level_root = this.eval_libc_i32("CPU_LEVEL_ROOT");
|
||||
let _level_cpuset = this.eval_libc_i32("CPU_LEVEL_CPUSET");
|
||||
let level_which = this.eval_libc_i32("CPU_LEVEL_WHICH");
|
||||
@@ -104,7 +110,9 @@ fn emulate_foreign_item_inner(
|
||||
throw_unsup_format!(
|
||||
"`cpuset_getaffinity` is only supported with `level` set to CPU_LEVEL_WHICH and `which` set to CPU_WHICH_PID."
|
||||
);
|
||||
} else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&id) {
|
||||
} else if let Some(cpuset) =
|
||||
this.machine.thread_cpu_affinity.as_ref().unwrap().get(&id)
|
||||
{
|
||||
// `cpusetsize` must be large enough to contain the entire CPU mask.
|
||||
// FreeBSD only uses `cpusetsize` to verify that it's sufficient for the kernel's CPU mask.
|
||||
// If it's too small, the syscall returns ERANGE.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//! Test that Miri is able to run no_core programs.
|
||||
//! This ensures that we don't depend on any paths from core when no_core is set.
|
||||
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
#![no_main]
|
||||
#![feature(rustc_attrs, no_core, lang_items, intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[lang = "pointee_sized"]
|
||||
pub trait PointeeSized {}
|
||||
|
||||
#[lang = "meta_sized"]
|
||||
pub trait MetaSized: PointeeSized {}
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized: MetaSized {}
|
||||
|
||||
#[no_mangle]
|
||||
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
0
|
||||
}
|
||||
Reference in New Issue
Block a user