@@ -596,19 +596,29 @@ pub fn set_thread_priority_and_policy(
596
596
e => Err ( Error :: OS ( e) ) ,
597
597
}
598
598
} 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 ( ) ;
602
601
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) ) ;
606
612
}
607
613
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 ( ) ) ) ;
611
619
}
620
+
621
+ Ok ( ( ) )
612
622
}
613
623
}
614
624
}
@@ -820,6 +830,44 @@ mod tests {
820
830
assert ! ( thread_schedule_policy_param( thread_id) . is_ok( ) ) ;
821
831
}
822
832
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
+
823
871
#[ test]
824
872
#[ cfg( target_os = "linux" ) ]
825
873
fn set_deadline_policy ( ) {
0 commit comments