Implement FreeBSD syscall cpuset_getaffinity.
This commit is contained in:
parent
febe98807f
commit
5dfcb12a20
3 changed files with 117 additions and 2 deletions
|
|
@ -165,8 +165,8 @@ case $HOST_TARGET in
|
|||
# Partially supported targets (tier 2)
|
||||
BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
|
||||
UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
|
||||
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
|
||||
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
|
||||
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe affinity
|
||||
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe affinity
|
||||
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd
|
||||
TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm
|
||||
TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
|
||||
|
|
|
|||
|
|
@ -56,6 +56,70 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
|
||||
"cpuset_getaffinity" => {
|
||||
// The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically.
|
||||
let [level, which, id, set_size, mask] =
|
||||
this.check_shim(abi, Conv::C, link_name, args)?;
|
||||
|
||||
let level = this.read_scalar(level)?.to_i32()?;
|
||||
let which = this.read_scalar(which)?.to_i32()?;
|
||||
let id = this.read_scalar(id)?.to_i64()?;
|
||||
let set_size = this.read_target_usize(set_size)?; // measured in bytes
|
||||
let mask = this.read_pointer(mask)?;
|
||||
|
||||
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");
|
||||
|
||||
let _which_tid = this.eval_libc_i32("CPU_WHICH_TID");
|
||||
let which_pid = this.eval_libc_i32("CPU_WHICH_PID");
|
||||
let _which_jail = this.eval_libc_i32("CPU_WHICH_JAIL");
|
||||
let _which_cpuset = this.eval_libc_i32("CPU_WHICH_CPUSET");
|
||||
let _which_irq = this.eval_libc_i32("CPU_WHICH_IRQ");
|
||||
|
||||
// For sched_getaffinity, the current process is identified by -1.
|
||||
// TODO: Use gettid? I'm (LorrensP-2158466) not that familiar with this api .
|
||||
let id = match id {
|
||||
-1 => this.active_thread(),
|
||||
_ =>
|
||||
throw_unsup_format!(
|
||||
"`cpuset_getaffinity` is only supported with a pid of -1 (indicating the current thread)"
|
||||
),
|
||||
};
|
||||
|
||||
if this.ptr_is_null(mask)? {
|
||||
this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
|
||||
}
|
||||
// We only support CPU_LEVEL_WHICH and CPU_WHICH_PID for now.
|
||||
// This is the bare minimum to make the tests pass.
|
||||
else if level != level_which || which != which_pid {
|
||||
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) {
|
||||
// `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.
|
||||
// If it's large enough, copying the kernel mask to user space is safe, regardless of the actual size.
|
||||
// See https://github.com/freebsd/freebsd-src/blob/909aa6781340f8c0b4ae01c6366bf1556ee2d1be/sys/kern/kern_cpuset.c#L1985
|
||||
if set_size < u64::from(this.machine.num_cpus).div_ceil(8) {
|
||||
this.set_last_error_and_return(LibcError("ERANGE"), dest)?;
|
||||
} else {
|
||||
let cpuset = cpuset.clone();
|
||||
let byte_count =
|
||||
Ord::min(cpuset.as_slice().len(), set_size.try_into().unwrap());
|
||||
this.write_bytes_ptr(
|
||||
mask,
|
||||
cpuset.as_slice()[..byte_count].iter().copied(),
|
||||
)?;
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
} else {
|
||||
// `id` is always that of the active thread, so this is currently unreachable.
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronization primitives
|
||||
"_umtx_op" => {
|
||||
let [obj, op, val, uaddr, uaddr2] =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
//@only-target: freebsd
|
||||
//@compile-flags: -Zmiri-num-cpus=256
|
||||
|
||||
use std::mem;
|
||||
|
||||
fn getaffinity() {
|
||||
let mut set: libc::cpuset_t = unsafe { mem::zeroed() };
|
||||
unsafe {
|
||||
if libc::cpuset_getaffinity(
|
||||
libc::CPU_LEVEL_WHICH,
|
||||
libc::CPU_WHICH_PID,
|
||||
-1,
|
||||
size_of::<libc::cpuset_t>(),
|
||||
&mut set,
|
||||
) == 0
|
||||
{
|
||||
assert!(libc::CPU_COUNT(&set) == 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_small_cpu_mask() {
|
||||
let mut set: libc::cpuset_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
|
||||
|
||||
// 256 CPUs so we need 32 bytes to represent this mask.
|
||||
// According to Freebsd only when `cpusetsize` is smaller than this value, does it return with ERANGE
|
||||
|
||||
let err = unsafe {
|
||||
libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 32, &mut set)
|
||||
};
|
||||
assert_eq!(err, 0, "Success Expected");
|
||||
|
||||
// 31 is not enough, so it should fail.
|
||||
let err = unsafe {
|
||||
libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 31, &mut set)
|
||||
};
|
||||
assert_eq!(err, -1, "Expected Failure");
|
||||
assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ERANGE);
|
||||
|
||||
// Zero should fail as well.
|
||||
let err = unsafe {
|
||||
libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 0, &mut set)
|
||||
};
|
||||
assert_eq!(err, -1, "Expected Failure");
|
||||
assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ERANGE);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
getaffinity();
|
||||
get_small_cpu_mask();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue