1use std::convert::TryFrom;
8
9#[cfg(target_os = "android")]
10use libc::SCHED_NORMAL as SCHED_OTHER;
11#[cfg(not(target_os = "android"))]
12use libc::SCHED_OTHER;
13#[cfg(target_os = "vxworks")]
14use libc::SCHED_SPORADIC;
15#[cfg(any(target_os = "linux", target_os = "android"))]
16use libc::{SCHED_BATCH, SCHED_IDLE};
17use libc::{SCHED_FIFO, SCHED_RR};
18
19use crate::{Error, ThreadPriority, ThreadPriorityValue};
20use std::mem::MaybeUninit;
21
22pub type ThreadId = libc::pthread_t;
32
33pub const NICENESS_MAX: i8 = -20;
36pub const NICENESS_MIN: i8 = 19;
39
40#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
42pub struct ScheduleParams {
43 pub sched_priority: libc::c_int,
45}
46
47fn errno() -> libc::c_int {
48 unsafe {
49 cfg_if::cfg_if! {
50 if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "android"))] {
51 *libc::__errno()
52 } else if #[cfg(target_os = "linux")] {
53 *libc::__errno_location()
54 } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] {
55 *libc::__error()
56 } else if #[cfg(target_os = "vxworks")] {
57 libc::errnoGet()
58 } else {
59 compile_error!("Your OS is probably not supported.")
60 }
61 }
62 }
63}
64
65fn set_errno(number: libc::c_int) {
66 unsafe {
67 cfg_if::cfg_if! {
68 if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "android"))] {
69 *libc::__errno() = number;
70 } else if #[cfg(target_os = "linux")] {
71 *libc::__errno_location() = number;
72 } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] {
73 *libc::__error() = number;
74 } else if #[cfg(target_os = "vxworks")] {
75 let _ = libc::errnoSet(number);
76 } else {
77 compile_error!("Your OS is probably not supported.")
78 }
79 }
80 }
81}
82
83fn do_with_errno<F: FnOnce() -> libc::c_int>(f: F) -> Result<libc::c_int, Error> {
84 let return_value = f();
85 if return_value < 0 {
86 Err(Error::OS(errno()))
87 } else {
88 Ok(return_value)
89 }
90}
91
92#[derive(Debug, Default)]
97#[cfg(any(target_os = "linux", target_os = "android"))]
98#[repr(C)]
99pub struct SchedAttr {
100 size: u32,
101 sched_policy: u32,
102 sched_flags: u64,
103 sched_nice: i32,
105 sched_priority: u32,
107 sched_runtime: u64,
109 sched_deadline: u64,
111 sched_period: u64,
113 sched_util_min: u32,
115 sched_util_max: u32,
117}
118
119impl ScheduleParams {
120 fn into_posix(self) -> libc::sched_param {
121 let mut param = unsafe { MaybeUninit::<libc::sched_param>::zeroed().assume_init() };
122 param.sched_priority = self.sched_priority;
123 param
124 }
125
126 fn from_posix(sched_param: libc::sched_param) -> Self {
127 ScheduleParams {
128 sched_priority: sched_param.sched_priority,
129 }
130 }
131}
132
133#[cfg(any(target_os = "linux", target_os = "android"))]
134bitflags::bitflags! {
135 #[repr(transparent)]
137 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
138 pub struct DeadlineFlags: u64 {
139 const RESET_ON_FORK = 0x01;
142 const RECLAIM = 0x02;
145 const DEADLINE_OVERRUN = 0x04;
148 }
149}
150
151#[cfg(any(target_os = "linux", target_os = "android"))]
153pub fn get_thread_scheduling_attributes() -> Result<SchedAttr, Error> {
154 let mut sched_attr = SchedAttr::default();
155 let current_thread = 0;
156 let flags = 0;
157 let ret = unsafe {
158 libc::syscall(
159 libc::SYS_sched_getattr,
160 current_thread,
161 &mut sched_attr as *mut _,
162 std::mem::size_of::<SchedAttr>() as u32,
163 flags,
164 )
165 };
166 if ret < 0 {
167 return Err(Error::OS(errno()));
168 }
169 Ok(sched_attr)
170}
171
172#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
175pub enum RealtimeThreadSchedulePolicy {
176 Fifo,
178 RoundRobin,
180 #[cfg(target_os = "vxworks")]
183 Sporadic,
184 #[cfg(all(
188 any(target_os = "linux", target_os = "android"),
189 not(target_arch = "wasm32")
190 ))]
191 Deadline,
192}
193
194impl RealtimeThreadSchedulePolicy {
195 fn to_posix(self) -> libc::c_int {
196 match self {
197 RealtimeThreadSchedulePolicy::Fifo => SCHED_FIFO,
198 RealtimeThreadSchedulePolicy::RoundRobin => SCHED_RR,
199 #[cfg(target_os = "vxworks")]
200 RealtimeThreadSchedulePolicy::Sporadic => SCHED_SPORADIC,
201 #[cfg(all(
202 any(target_os = "linux", target_os = "android"),
203 not(target_arch = "wasm32")
204 ))]
205 RealtimeThreadSchedulePolicy::Deadline => 6,
206 }
207 }
208}
209
210#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
214pub enum NormalThreadSchedulePolicy {
215 #[cfg(any(target_os = "linux", target_os = "android"))]
222 Idle,
223 #[cfg(any(target_os = "linux", target_os = "android"))]
235 Batch,
236 Other,
251}
252impl NormalThreadSchedulePolicy {
253 fn to_posix(self) -> libc::c_int {
254 match self {
255 #[cfg(any(target_os = "linux", target_os = "android"))]
256 NormalThreadSchedulePolicy::Idle => SCHED_IDLE,
257 #[cfg(any(target_os = "linux", target_os = "android"))]
258 NormalThreadSchedulePolicy::Batch => SCHED_BATCH,
259 NormalThreadSchedulePolicy::Other => SCHED_OTHER,
260 }
261 }
262}
263
264#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
266pub enum ThreadSchedulePolicy {
267 Normal(NormalThreadSchedulePolicy),
269 Realtime(RealtimeThreadSchedulePolicy),
271}
272impl ThreadSchedulePolicy {
273 fn to_posix(self) -> libc::c_int {
274 match self {
275 ThreadSchedulePolicy::Normal(p) => p.to_posix(),
276 ThreadSchedulePolicy::Realtime(p) => p.to_posix(),
277 }
278 }
279
280 fn from_posix(policy: libc::c_int) -> Result<ThreadSchedulePolicy, Error> {
281 match policy {
282 SCHED_OTHER => Ok(ThreadSchedulePolicy::Normal(
283 NormalThreadSchedulePolicy::Other,
284 )),
285 #[cfg(any(target_os = "linux", target_os = "android"))]
286 SCHED_BATCH => Ok(ThreadSchedulePolicy::Normal(
287 NormalThreadSchedulePolicy::Batch,
288 )),
289 #[cfg(any(target_os = "linux", target_os = "android"))]
290 SCHED_IDLE => Ok(ThreadSchedulePolicy::Normal(
291 NormalThreadSchedulePolicy::Idle,
292 )),
293 SCHED_FIFO => Ok(ThreadSchedulePolicy::Realtime(
294 RealtimeThreadSchedulePolicy::Fifo,
295 )),
296 SCHED_RR => Ok(ThreadSchedulePolicy::Realtime(
297 RealtimeThreadSchedulePolicy::RoundRobin,
298 )),
299 #[cfg(target_os = "vxworks")]
300 SCHED_SPORADIC => Ok(ThreadSchedulePolicy::Realtime(
301 RealtimeThreadSchedulePolicy::Sporadic,
302 )),
303 #[cfg(all(
304 any(target_os = "linux", target_os = "android"),
305 not(target_arch = "wasm32")
306 ))]
307 6 => Ok(ThreadSchedulePolicy::Realtime(
308 RealtimeThreadSchedulePolicy::Deadline,
309 )),
310 _ => Err(Error::Ffi("Can't parse schedule policy from posix")),
311 }
312 }
313}
314
315#[derive(Debug, Copy, Clone)]
317pub enum PriorityPolicyEdgeValueType {
318 Minimum,
320 Maximum,
322}
323
324impl ThreadPriority {
325 pub fn max_value_for_policy(policy: ThreadSchedulePolicy) -> Result<libc::c_int, Error> {
328 Self::get_edge_value_for_policy(policy, PriorityPolicyEdgeValueType::Maximum)
329 }
330
331 pub fn min_value_for_policy(policy: ThreadSchedulePolicy) -> Result<libc::c_int, Error> {
334 Self::get_edge_value_for_policy(policy, PriorityPolicyEdgeValueType::Minimum)
335 }
336
337 fn get_edge_value_for_policy(
339 policy: ThreadSchedulePolicy,
340 edge: PriorityPolicyEdgeValueType,
341 ) -> Result<libc::c_int, Error> {
342 let get_edge_priority = match edge {
343 PriorityPolicyEdgeValueType::Minimum => Self::get_min_priority,
344 PriorityPolicyEdgeValueType::Maximum => Self::get_max_priority,
345 };
346
347 match policy {
348 #[cfg_attr(
349 not(any(target_os = "linux", target_os = "android")),
350 allow(unused_variables)
351 )]
352 ThreadSchedulePolicy::Normal(normal) => {
353 cfg_if::cfg_if! {
354 if #[cfg(any(target_os = "linux", target_os = "android"))] {
355 if normal == NormalThreadSchedulePolicy::Idle {
356 Ok(0)
358 } else {
359 Ok(match edge {
361 PriorityPolicyEdgeValueType::Minimum => NICENESS_MIN as libc::c_int,
362 PriorityPolicyEdgeValueType::Maximum => NICENESS_MAX as libc::c_int,
363 })
364 }
365 } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "vxworks"))] {
366 get_edge_priority(policy)
368 } else {
369 Err(Error::Priority(
370 "Unsupported thread priority for this OS. Change the scheduling policy or use a supported OS.",
371 ))
372 }
373 }
374 }
375 _ => get_edge_priority(policy),
376 }
377 }
378
379 fn get_max_priority(policy: ThreadSchedulePolicy) -> Result<libc::c_int, Error> {
381 do_with_errno(|| unsafe { libc::sched_get_priority_max(policy.to_posix()) })
382 }
383
384 fn get_min_priority(policy: ThreadSchedulePolicy) -> Result<libc::c_int, Error> {
386 do_with_errno(|| unsafe { libc::sched_get_priority_min(policy.to_posix()) })
387 }
388
389 pub fn to_allowed_value_for_policy(
391 priority: libc::c_int,
392 policy: ThreadSchedulePolicy,
393 ) -> Result<libc::c_int, Error> {
394 let min_priority = Self::min_value_for_policy(policy)?;
395 let max_priority = Self::max_value_for_policy(policy)?;
396 let (min, max) = (
397 std::cmp::min(min_priority, max_priority),
398 std::cmp::max(min_priority, max_priority),
399 );
400 let allowed_range = min..=max;
401 if allowed_range.contains(&priority) {
402 Ok(priority)
403 } else {
404 Err(Error::PriorityNotInRange(allowed_range))
405 }
406 }
407
408 pub fn to_posix(self, policy: ThreadSchedulePolicy) -> Result<libc::c_int, Error> {
417 let ret = match self {
418 ThreadPriority::Min => match policy {
419 #[cfg(all(
421 any(target_os = "linux", target_os = "android"),
422 not(target_arch = "wasm32")
423 ))]
424 ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) => Err(
425 Error::Priority("Deadline scheduling must use deadline priority."),
426 ),
427 _ => Self::min_value_for_policy(policy).map(|v| v as u32),
428 },
429 ThreadPriority::Crossplatform(ThreadPriorityValue(p)) => match policy {
430 #[cfg(all(
432 any(target_os = "linux", target_os = "android"),
433 not(target_arch = "wasm32")
434 ))]
435 ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) => Err(
436 Error::Priority("Deadline scheduling must use deadline priority."),
437 ),
438 ThreadSchedulePolicy::Realtime(_) => {
439 Self::to_allowed_value_for_policy(p as i32, policy).map(|v| v as u32)
440 }
441 #[cfg(all(
445 any(target_os = "macos", target_os = "ios", target_os = "vxworks"),
446 not(target_arch = "wasm32")
447 ))]
448 ThreadSchedulePolicy::Normal(_) => {
449 Self::to_allowed_value_for_policy(p as i32, policy).map(|v| v as u32)
450 }
451 #[cfg(not(all(
452 any(target_os = "macos", target_os = "ios", target_os = "vxworks"),
453 not(target_arch = "wasm32")
454 )))]
455 ThreadSchedulePolicy::Normal(_) => {
456 let niceness_values = NICENESS_MAX.abs() + NICENESS_MIN.abs();
459 let ratio = 1f32 - (p as f32 / ThreadPriorityValue::MAX as f32);
460 let niceness = ((niceness_values as f32 * ratio) as i8 + NICENESS_MAX) as i32;
461 Self::to_allowed_value_for_policy(niceness, policy).map(|v| v as u32)
462 }
463 },
464 ThreadPriority::Os(crate::ThreadPriorityOsValue(p)) => match policy {
466 #[cfg(all(
468 any(target_os = "linux", target_os = "android"),
469 not(target_arch = "wasm32")
470 ))]
471 ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) => Err(
472 Error::Priority("Deadline scheduling must use deadline priority."),
473 ),
474 _ => Self::to_allowed_value_for_policy(p as i32, policy).map(|v| v as u32),
475 },
476 ThreadPriority::Max => match policy {
477 #[cfg(all(
479 any(target_os = "linux", target_os = "android"),
480 not(target_arch = "wasm32")
481 ))]
482 ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) => Err(
483 Error::Priority("Deadline scheduling must use deadline priority."),
484 ),
485 _ => Self::max_value_for_policy(policy).map(|v| v as u32),
486 },
487 #[cfg(all(
488 any(target_os = "linux", target_os = "android"),
489 not(target_arch = "wasm32")
490 ))]
491 ThreadPriority::Deadline { .. } => Err(Error::Priority(
492 "Deadline is non-POSIX and cannot be converted.",
493 )),
494 };
495 ret.map(|p| p as libc::c_int)
496 }
497
498 pub fn from_posix(params: ScheduleParams) -> ThreadPriority {
502 ThreadPriority::Crossplatform(ThreadPriorityValue(params.sched_priority as u8))
503 }
504}
505
506#[cfg(any(target_os = "linux", target_os = "android"))]
507fn set_thread_priority_and_policy_deadline(
508 native: ThreadId,
509 priority: ThreadPriority,
510) -> Result<(), Error> {
511 use std::convert::TryInto as _;
512
513 let (runtime, deadline, period, flags) = match priority {
514 ThreadPriority::Deadline {
515 runtime,
516 deadline,
517 period,
518 flags,
519 } => (|| {
520 Ok((
521 runtime.as_nanos().try_into()?,
522 deadline.as_nanos().try_into()?,
523 period.as_nanos().try_into()?,
524 flags,
525 ))
526 })()
527 .map_err(|_: std::num::TryFromIntError| {
528 Error::Priority("Deadline policy durations don't fit into a `u64`.")
529 })?,
530 _ => {
531 return Err(Error::Priority(
532 "Deadline policy given without deadline priority.",
533 ));
534 }
535 };
536 let tid = native as libc::pid_t;
537 let sched_attr = SchedAttr {
538 size: std::mem::size_of::<SchedAttr>() as u32,
539 sched_policy: RealtimeThreadSchedulePolicy::Deadline.to_posix() as u32,
540 sched_runtime: runtime,
541 sched_deadline: deadline,
542 sched_period: period,
543 sched_flags: flags.bits(),
544 ..Default::default()
545 };
546 let ret =
547 unsafe { libc::syscall(libc::SYS_sched_setattr, tid, &sched_attr as *const _, 0) as i32 };
548
549 match ret {
550 0 => Ok(()),
551 e => Err(Error::OS(e)),
552 }
553}
554
555pub fn set_thread_priority_and_policy(
578 native: ThreadId,
579 priority: ThreadPriority,
580 policy: ThreadSchedulePolicy,
581) -> Result<(), Error> {
582 match policy {
583 #[cfg(any(target_os = "linux", target_os = "android"))]
585 ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) => {
586 set_thread_priority_and_policy_deadline(native, priority)
587 }
588 _ => {
589 let fixed_priority = priority.to_posix(policy)?;
590 if matches!(policy, ThreadSchedulePolicy::Realtime(_))
593 || cfg!(any(
594 target_os = "macos",
595 target_os = "ios",
596 target_os = "vxworks"
597 ))
598 {
599 let params = ScheduleParams {
602 sched_priority: fixed_priority,
603 }
604 .into_posix();
605
606 let ret = unsafe {
607 libc::pthread_setschedparam(
608 native,
609 policy.to_posix(),
610 ¶ms as *const libc::sched_param,
611 )
612 };
613
614 match ret {
615 0 => Ok(()),
616 e => Err(Error::OS(e)),
617 }
618 } else {
619 #[cfg(target_os = "vxworks")]
621 unsafe fn setpriority(
622 _which: u32,
623 _who: u32,
624 _priority: libc::c_int,
625 ) -> libc::c_int {
626 set_errno(libc::ENOSYS);
627 -1
628 }
629
630 #[cfg(not(target_os = "vxworks"))]
631 use libc::setpriority;
632
633 let params = ScheduleParams { sched_priority: 0 }.into_posix();
635
636 let ret = unsafe {
637 libc::pthread_setschedparam(
638 native,
639 policy.to_posix(),
640 ¶ms as *const libc::sched_param,
641 )
642 };
643
644 if ret != 0 {
645 return Err(Error::OS(ret));
646 }
647
648 set_errno(0);
650 let ret = unsafe { setpriority(libc::PRIO_PROCESS, 0, fixed_priority) };
651 if ret != 0 {
652 return Err(Error::OS(errno()));
653 }
654
655 Ok(())
656 }
657 }
658 }
659}
660
661pub fn set_current_thread_priority(priority: ThreadPriority) -> Result<(), Error> {
676 let thread_id = thread_native_id();
677 let policy = thread_schedule_policy()?;
678 set_thread_priority_and_policy(thread_id, priority, policy)
679}
680
681pub fn thread_schedule_policy() -> Result<ThreadSchedulePolicy, Error> {
691 thread_schedule_policy_param(thread_native_id()).map(|policy| policy.0)
692}
693
694pub fn thread_schedule_policy_param(
705 native: ThreadId,
706) -> Result<(ThreadSchedulePolicy, ScheduleParams), Error> {
707 unsafe {
708 let mut policy = 0i32;
709 let mut params = ScheduleParams { sched_priority: 0 }.into_posix();
710
711 let ret = libc::pthread_getschedparam(
712 native,
713 &mut policy as *mut libc::c_int,
714 &mut params as *mut libc::sched_param,
715 );
716 match ret {
717 0 => Ok((
718 ThreadSchedulePolicy::from_posix(policy)?,
719 ScheduleParams::from_posix(params),
720 )),
721 e => Err(Error::OS(e)),
722 }
723 }
724}
725
726pub fn get_thread_priority(native: ThreadId) -> Result<ThreadPriority, Error> {
728 Ok(ThreadPriority::from_posix(
729 thread_schedule_policy_param(native)?.1,
730 ))
731}
732
733pub fn get_current_thread_priority() -> Result<ThreadPriority, Error> {
735 get_thread_priority(thread_native_id())
736}
737
738pub trait ThreadExt {
752 fn get_priority(&self) -> Result<ThreadPriority, Error> {
761 get_current_thread_priority()
762 }
763
764 fn set_priority(&self, priority: ThreadPriority) -> Result<(), Error> {
773 priority.set_for_current()
774 }
775
776 fn get_schedule_policy(&self) -> Result<ThreadSchedulePolicy, Error> {
779 thread_schedule_policy()
780 }
781
782 fn get_schedule_policy_param(&self) -> Result<(ThreadSchedulePolicy, ScheduleParams), Error> {
785 thread_schedule_policy_param(thread_native_id())
786 }
787
788 fn set_priority_and_policy(
791 &self,
792 policy: ThreadSchedulePolicy,
793 priority: ThreadPriority,
794 ) -> Result<(), Error> {
795 cfg_if::cfg_if! {
796 if #[cfg(all(any(target_os = "linux", target_os = "android"), not(target_arch = "wasm32")))] {
797 if policy == ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) {
798 set_thread_priority_and_policy(thread_native_id(), ThreadPriority::Crossplatform(ThreadPriorityValue(0)), policy)
799 } else {
800 set_thread_priority_and_policy(thread_native_id(), priority, policy)
801 }
802 } else {
803 set_thread_priority_and_policy(thread_native_id(), priority, policy)
804 }
805 }
806 }
807
808 fn get_native_id(&self) -> Result<ThreadId, Error>;
816}
817
818impl ThreadExt for std::thread::Thread {
820 fn get_native_id(&self) -> Result<ThreadId, Error> {
821 if self.id() == std::thread::current().id() {
822 Ok(thread_native_id())
823 } else {
824 Err(Error::Priority(
825 "The `ThreadExt::get_native_id()` is currently limited to be called on the current thread.",
826 ))
827 }
828 }
829}
830
831pub fn thread_native_id() -> ThreadId {
843 unsafe { libc::pthread_self() }
844}
845
846impl TryFrom<u8> for ThreadPriority {
847 type Error = &'static str;
848
849 fn try_from(value: u8) -> Result<Self, Self::Error> {
850 if let 0..=100 = value {
851 Ok(ThreadPriority::Crossplatform(ThreadPriorityValue(value)))
852 } else {
853 Err("The thread priority value must be in range of [0; 100].")
854 }
855 }
856}
857
858#[cfg(test)]
859mod tests {
860 use crate::unix::*;
861
862 #[test]
863 fn thread_schedule_policy_param_test() {
864 let thread_id = thread_native_id();
865
866 assert!(thread_schedule_policy_param(thread_id).is_ok());
867 }
868
869 #[test]
871 fn change_between_realtime_and_normal_policies_requires_capabilities() {
872 use crate::ThreadPriorityOsValue;
873
874 const TEST_PRIORITY: u8 = 15;
875
876 let realtime_policy = ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo);
877 let normal_policy = ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Other);
878
879 let desired_priority = ThreadPriority::Os(ThreadPriorityOsValue(TEST_PRIORITY as _));
881 let expected_priority = ThreadPriority::Crossplatform(ThreadPriorityValue(TEST_PRIORITY));
882
883 let thread = std::thread::current();
884 thread
885 .set_priority_and_policy(realtime_policy, desired_priority)
886 .expect("to set realtime fifo policy");
887
888 assert_eq!(thread.get_schedule_policy(), Ok(realtime_policy));
889 assert_eq!(thread.get_priority(), Ok(expected_priority));
890
891 thread
892 .set_priority_and_policy(normal_policy, desired_priority)
893 .expect("to set normal other policy");
894
895 assert_eq!(thread.get_schedule_policy(), Ok(normal_policy));
896
897 #[cfg(not(target_os = "linux"))]
899 assert_eq!(thread.get_priority(), Ok(expected_priority));
900 #[cfg(target_os = "linux")]
901 {
902 let nice = unsafe { libc::getpriority(0, 0) };
903 assert_eq!(nice, TEST_PRIORITY as i32);
904 }
905 }
906
907 #[test]
908 #[cfg(target_os = "linux")]
909 fn set_deadline_policy() {
910 #![allow(clippy::identity_op)]
912 use std::time::Duration;
913
914 assert!(
915 set_thread_priority_and_policy(
916 0, ThreadPriority::Deadline {
918 runtime: Duration::from_millis(1),
919 deadline: Duration::from_millis(10),
920 period: Duration::from_millis(100),
921 flags: DeadlineFlags::RESET_ON_FORK,
922 },
923 ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline)
924 )
925 .is_ok()
926 );
927
928 let attributes = get_thread_scheduling_attributes().unwrap();
929 assert_eq!(
930 attributes.sched_policy,
931 RealtimeThreadSchedulePolicy::Deadline.to_posix() as u32
932 );
933 assert_eq!(attributes.sched_runtime, 1 * 10_u64.pow(6));
934 assert_eq!(attributes.sched_deadline, 10 * 10_u64.pow(6));
935 assert_eq!(attributes.sched_period, 100 * 10_u64.pow(6));
936 assert_eq!(attributes.sched_flags, DeadlineFlags::RESET_ON_FORK.bits());
937 }
938}