blob: 0bac4681dfe6258ff53016a8775571e4f10944d8 [file] [log] [blame]
#![cfg(not(windows))]
use rstest::rstest;
use std::convert::TryInto;
use thread_priority::*;
#[cfg(target_os = "linux")]
#[test]
fn get_and_set_priority_with_normal_and_crossplatform() {
let nice = unsafe { libc::getpriority(0, 0) };
assert_eq!(nice, 0);
crate::set_current_thread_priority(ThreadPriority::Crossplatform(30u8.try_into().unwrap()))
.unwrap();
let nice = unsafe { libc::getpriority(0, 0) };
assert!(nice > 0);
// Note that increasing priority requires extra permissions (e.g. sudo)
crate::set_current_thread_priority(ThreadPriority::Crossplatform(70u8.try_into().unwrap()))
.unwrap();
let nice = unsafe { libc::getpriority(0, 0) };
assert!(nice < 0);
}
#[cfg(target_os = "linux")]
#[rstest]
fn get_and_set_priority_with_normal_policies(
#[values(
ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other),
ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Idle),
ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Batch)
)]
policy: ThreadSchedulePolicy,
#[values(ThreadPriority::Min, ThreadPriority::Max, ThreadPriority::Crossplatform(23u8.try_into().unwrap()))]
priority: ThreadPriority,
) {
let ret = set_thread_priority_and_policy(thread_native_id(), priority, policy);
if policy == ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Idle)
&& priority == ThreadPriority::Crossplatform(23u8.try_into().unwrap())
{
assert_eq!(ret, Err(Error::PriorityNotInRange(0..=0)));
} else {
assert!(ret.is_ok());
}
}
// In macOS it is allowed to specify number as a SCHED_OTHER policy priority.
#[cfg(any(
target_os = "macos",
target_os = "openbsd",
target_os = "vxworks",
target_os = "freebsd",
target_os = "netbsd"
))]
#[rstest]
fn get_and_set_priority_with_normal_policies(
#[values(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other))]
policy: ThreadSchedulePolicy,
#[values(ThreadPriority::Min, ThreadPriority::Max, ThreadPriority::Crossplatform(23u8.try_into().unwrap()))]
priority: ThreadPriority,
) {
assert!(set_thread_priority_and_policy(thread_native_id(), priority, policy).is_ok());
}
#[rstest]
#[cfg(target_os = "linux")]
#[case(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Idle), 0..=0)]
#[cfg(target_os = "linux")]
#[case(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Batch), -20..=19)]
#[cfg(not(target_os = "vxworks"))]
#[case(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other), -20..=19)]
#[cfg(not(target_os = "vxworks"))]
#[case(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo), 0..=99)]
#[cfg(not(target_os = "vxworks"))]
#[case(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::RoundRobin), 0..=99)]
#[cfg(target_os = "vxworks")]
#[case(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other), 0.=255)]
#[cfg(target_os = "vxworks")]
#[case(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo), 0..=255)]
#[cfg(target_os = "vxworks")]
#[case(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::RoundRobin), 0..=255)]
#[cfg(target_os = "vxworks")]
#[case(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Sporadic), 0..=255)]
fn check_min_and_max_priority_values(
#[case] policy: ThreadSchedulePolicy,
#[case] posix_range: std::ops::RangeInclusive<i32>,
) {
let max_value = ThreadPriority::max_value_for_policy(policy).unwrap();
let min_value = ThreadPriority::min_value_for_policy(policy).unwrap();
assert!(posix_range.contains(&max_value));
assert!(posix_range.contains(&min_value));
}
#[rstest]
#[cfg(target_os = "linux")]
#[case(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Idle))]
#[cfg(target_os = "linux")]
#[case(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Batch))]
#[case(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other))]
fn set_priority_with_normal_policy_but_with_invalid_value(#[case] policy: ThreadSchedulePolicy) {
let thread_id = thread_native_id();
#[cfg(target_os = "linux")]
let expected = if policy == ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Idle) {
// In Linux we should get an error whenever a non-zero value is passed as priority and a normal
// scheduling policy is used.
Err(Error::PriorityNotInRange(0..=0))
} else {
Ok(())
};
assert_eq!(
set_thread_priority_and_policy(
thread_id,
ThreadPriority::Crossplatform(23u8.try_into().unwrap()),
policy,
),
expected
);
}
#[cfg(any(
target_os = "macos",
target_os = "openbsd",
target_os = "vxworks",
target_os = "freebsd",
target_os = "netbsd"
))]
#[test]
// In macOS the SCHED_OTHER policy allows having a non-zero priority value,
// but the crate doesn't use this opportunity for normal threads and uses niceness instead.
fn get_and_set_priority_with_normal_policy() {
let thread_id = thread_native_id();
let normal_policy = ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other);
assert_eq!(
set_thread_priority_and_policy(
thread_id,
ThreadPriority::Crossplatform(23u8.try_into().unwrap()),
normal_policy,
),
Ok(())
);
assert_eq!(thread_schedule_policy(), Ok(normal_policy));
}
#[rstest]
#[case::fifo(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo))]
#[case::roundrobin(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::RoundRobin))]
fn get_and_set_priority_with_realtime_policy_requires_capabilities(
#[case] realtime_policy: ThreadSchedulePolicy,
) {
let thread_id = thread_native_id();
let max_value = ThreadPriority::max_value_for_policy(realtime_policy).unwrap();
let min_value = ThreadPriority::min_value_for_policy(realtime_policy).unwrap();
assert_eq!(
set_thread_priority_and_policy(thread_id, ThreadPriority::Max, realtime_policy,),
Ok(())
);
assert_eq!(thread_schedule_policy(), Ok(realtime_policy));
assert_eq!(
thread_schedule_policy_param(thread_native_id()),
Ok((
realtime_policy,
ScheduleParams {
sched_priority: max_value
}
))
);
assert_eq!(
Thread::current(),
Ok(Thread {
priority: ThreadPriority::Crossplatform((max_value as u8).try_into().unwrap()),
id: thread_native_id()
})
);
assert_eq!(
set_thread_priority_and_policy(
thread_id,
ThreadPriority::Crossplatform(23u8.try_into().unwrap()),
realtime_policy,
),
Ok(())
);
assert_eq!(thread_schedule_policy(), Ok(realtime_policy));
assert_eq!(
thread_schedule_policy_param(thread_native_id()),
Ok((realtime_policy, ScheduleParams { sched_priority: 23 }))
);
assert_eq!(
Thread::current(),
Ok(Thread {
priority: ThreadPriority::Crossplatform(23u8.try_into().unwrap()),
id: thread_native_id()
})
);
assert_eq!(
set_thread_priority_and_policy(thread_id, ThreadPriority::Min, realtime_policy,),
Ok(())
);
assert_eq!(thread_schedule_policy(), Ok(realtime_policy));
assert_eq!(
thread_schedule_policy_param(thread_native_id()),
Ok((
realtime_policy,
ScheduleParams {
sched_priority: min_value
}
))
);
assert_eq!(
Thread::current(),
Ok(Thread {
priority: ThreadPriority::Crossplatform((min_value as u8).try_into().unwrap()),
id: thread_native_id()
})
);
}