Skip to content

Commit 1135f2e

Browse files
authored
Fix unix changing from real-time to normal policy (#39)
* Adds a failing unit test for unix scheduling policy No effect when changing from real-time to normal policy. * Fixes behavior when changing from real-time to normal policy
1 parent 17539c0 commit 1135f2e

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

src/unix.rs

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -596,19 +596,29 @@ pub fn set_thread_priority_and_policy(
596596
e => Err(Error::OS(e)),
597597
}
598598
} else {
599-
// If this is a normal-scheduled thread, the priority is
600-
// set via niceness.
601-
set_errno(0);
599+
// Normal priority threads must be set with static priority 0.
600+
let params = ScheduleParams { sched_priority: 0 }.into_posix();
602601

603-
let ret = unsafe { libc::setpriority(libc::PRIO_PROCESS, 0, fixed_priority) };
604-
if ret == 0 {
605-
return Ok(());
602+
let ret = unsafe {
603+
libc::pthread_setschedparam(
604+
native,
605+
policy.to_posix(),
606+
&params as *const libc::sched_param,
607+
)
608+
};
609+
610+
if ret != 0 {
611+
return Err(Error::OS(ret));
606612
}
607613

608-
match errno() {
609-
0 => Ok(()),
610-
e => Err(Error::OS(e)),
614+
// Normal priority threads adjust relative priority through niceness.
615+
set_errno(0);
616+
let ret = unsafe { libc::setpriority(libc::PRIO_PROCESS, 0, fixed_priority) };
617+
if ret != 0 {
618+
return Err(Error::OS(errno()));
611619
}
620+
621+
Ok(())
612622
}
613623
}
614624
}
@@ -820,6 +830,44 @@ mod tests {
820830
assert!(thread_schedule_policy_param(thread_id).is_ok());
821831
}
822832

833+
// Running this test requires CAP_SYS_NICE.
834+
#[test]
835+
fn change_between_realtime_and_normal_policies_requires_capabilities() {
836+
use crate::ThreadPriorityOsValue;
837+
838+
const TEST_PRIORITY: u8 = 15;
839+
840+
let realtime_policy = ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo);
841+
let normal_policy = ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other);
842+
843+
// While we may desire an OS-specific priority, the reported value is always crossplatform.
844+
let desired_priority = ThreadPriority::Os(ThreadPriorityOsValue(TEST_PRIORITY as _));
845+
let expected_priority = ThreadPriority::Crossplatform(ThreadPriorityValue(TEST_PRIORITY));
846+
847+
let thread = std::thread::current();
848+
thread
849+
.set_priority_and_policy(realtime_policy, desired_priority)
850+
.expect("to set realtime fifo policy");
851+
852+
assert_eq!(thread.get_schedule_policy(), Ok(realtime_policy));
853+
assert_eq!(thread.get_priority(), Ok(expected_priority));
854+
855+
thread
856+
.set_priority_and_policy(normal_policy, desired_priority)
857+
.expect("to set normal other policy");
858+
859+
assert_eq!(thread.get_schedule_policy(), Ok(normal_policy));
860+
861+
// On linux, normal priority threads always have static priority 0. Instead the "nice" value is used.
862+
#[cfg(not(target_os = "linux"))]
863+
assert_eq!(thread.get_priority(), Ok(expected_priority));
864+
#[cfg(target_os = "linux")]
865+
{
866+
let nice = unsafe { libc::getpriority(0, 0) };
867+
assert_eq!(nice, TEST_PRIORITY as i32);
868+
}
869+
}
870+
823871
#[test]
824872
#[cfg(target_os = "linux")]
825873
fn set_deadline_policy() {

0 commit comments

Comments
 (0)