use std::io;
use std::mem;
pub const STACK_PREFAULT_BYTES: usize = 256 * 1024;
pub fn set_fifo(priority: u8) -> io::Result<()> {
let mut param: libc::sched_param = unsafe { mem::zeroed() };
param.sched_priority = priority as libc::c_int;
let ret = unsafe {
libc::syscall(
libc::SYS_sched_setscheduler,
0 as libc::pid_t,
libc::SCHED_FIFO,
¶m as *const libc::sched_param,
)
};
if ret < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
fn cpu_set(cpus: &[usize]) -> libc::cpu_set_t {
unsafe {
let mut set: libc::cpu_set_t = mem::zeroed();
for &cpu in cpus {
libc::CPU_SET(cpu, &mut set);
}
set
}
}
pub fn set_affinity(cpus: &[usize]) -> io::Result<()> {
if cpus.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"empty CPU list",
));
}
let max_cpu = 8 * mem::size_of::<libc::cpu_set_t>();
if let Some(&cpu) = cpus.iter().find(|&&cpu| cpu >= max_cpu) {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("cpu {cpu} out of range (max {max_cpu})"),
));
}
let set = cpu_set(cpus);
let ret = unsafe {
libc::syscall(
libc::SYS_sched_setaffinity,
0 as libc::pid_t,
mem::size_of::<libc::cpu_set_t>() as libc::size_t,
&set as *const libc::cpu_set_t,
)
};
if ret < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn lock_memory() -> io::Result<()> {
let ret = unsafe { libc::mlockall(libc::MCL_CURRENT | libc::MCL_FUTURE) };
if ret < 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn prefault_stack() {
let mut buf = [0u8; STACK_PREFAULT_BYTES];
let mut i = 0;
while i < buf.len() {
buf[i] = 1;
i += 4096;
}
std::hint::black_box(&buf);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cpu_set_holds_exactly_the_requested_cpus() {
let set = cpu_set(&[0, 2]);
unsafe {
assert!(libc::CPU_ISSET(0, &set));
assert!(!libc::CPU_ISSET(1, &set));
assert!(libc::CPU_ISSET(2, &set));
assert!(!libc::CPU_ISSET(3, &set));
}
}
#[test]
fn set_affinity_rejects_an_empty_list() {
assert_eq!(
set_affinity(&[]).unwrap_err().kind(),
std::io::ErrorKind::InvalidInput
);
}
#[test]
fn set_affinity_rejects_a_cpu_beyond_the_bitmap_width() {
let max_cpu = 8 * mem::size_of::<libc::cpu_set_t>();
assert_eq!(
set_affinity(&[max_cpu]).unwrap_err().kind(),
std::io::ErrorKind::InvalidInput
);
assert_eq!(
set_affinity(&[0, max_cpu]).unwrap_err().kind(),
std::io::ErrorKind::InvalidInput
);
}
#[test]
fn set_affinity_to_the_current_cpu_succeeds() {
let cpu = unsafe { libc::sched_getcpu() };
assert!(cpu >= 0);
set_affinity(&[cpu as usize]).unwrap();
}
#[test]
fn prefault_stack_returns() {
prefault_stack();
}
#[test]
#[ignore]
fn set_fifo_applies() {
set_fifo(10).unwrap();
}
#[test]
#[ignore]
fn lock_memory_applies() {
lock_memory().unwrap();
}
}