| #![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() |
| }) |
| ); |
| } |