use std::thread::{self, JoinHandle};
#[cfg(target_os = "linux")]
use libc::{
c_int, cpu_set_t, sched_get_priority_max, sched_get_priority_min,
sched_param, sched_setaffinity, sched_setscheduler, CPU_SET,
CPU_ZERO, SCHED_FIFO,
};
#[cfg(target_os = "linux")]
use rand::Rng;
use super::*;
#[cfg(target_os = "linux")]
const POLICY: c_int = SCHED_FIFO;
#[cfg(target_os = "linux")]
pub fn prioritize(prio: c_int) {
pin_cpu();
let param = sched_param {
sched_priority: prio,
};
let ret = unsafe {
sched_setscheduler(0, POLICY, ¶m as *const sched_param)
};
assert_eq!(
ret,
0,
"setscheduler is expected to return zero, was {}: {:?}",
ret,
std::io::Error::last_os_error()
);
thread::yield_now();
}
#[cfg(target_os = "linux")]
fn pin_cpu() {
unsafe {
let mut cpu_set: cpu_set_t = std::mem::zeroed();
CPU_ZERO(&mut cpu_set);
CPU_SET(0, &mut cpu_set);
let ret =
sched_setaffinity(0, 1, &cpu_set as *const cpu_set_t);
assert_eq!(
ret,
0,
"sched_setaffinity is expected to return 0, was {}: {:?}",
ret,
std::io::Error::last_os_error()
);
}
}
#[cfg(target_os = "linux")]
pub fn spawn_with_random_prio<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
let min = unsafe { sched_get_priority_min(POLICY) };
let max = unsafe { sched_get_priority_max(POLICY) };
prioritize(thread_rng().gen_range(min, max));
let prio = thread_rng().gen_range(min, max);
let context = context();
thread::spawn(move || {
prioritize(prio);
set_context(context);
f()
})
}
#[cfg(target_os = "linux")]
pub fn spawn_with_prio<F, T>(prio: c_int, f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
let context = context();
thread::spawn(move || {
prioritize(prio);
set_context(context);
f()
})
}
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
let context = context();
thread::spawn(move || {
set_context(context);
f()
})
}
#[test]
fn ensure_context_is_inherited() {
use std::ops::Add;
use std::time::Duration;
let time = UNIX_EPOCH.add(Duration::from_millis(55));
context::set_time(time.clone());
let child_time = spawn(|| context::now())
.join()
.expect("child should not crash");
assert_eq!(time, child_time);
}
#[test]
#[ignore]
#[cfg(target_os = "linux")]
fn gogogo() {
fn f1() {
for _ in 0..10 {
println!("1");
}
}
fn f2() {
for _ in 0..10 {
println!("2");
}
}
fn f3() {
for _ in 0..10 {
println!("3");
}
}
prioritize(4);
let threads = vec![
spawn_with_prio(3, f1),
spawn_with_prio(2, f2),
spawn_with_prio(1, f3),
];
for t in threads.into_iter() {
t.join().unwrap();
}
}