diff --git a/src/lib.rs b/src/lib.rs index 56d35b3..0833a05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -182,7 +182,7 @@ pub enum ThreadPriority { /// the nanoseconds for runtime, deadline, and period. Please note that the /// kernel enforces runtime <= deadline <= period. #[cfg(target_os = "linux")] - Deadline(u64, u64, u64), + Deadline(u64, u64, u64, Option), /// Holds a value representing the maximum possible priority. /// Should be used with caution, it solely depends on the target /// os where the program is going to be running on, how it will diff --git a/src/unix.rs b/src/unix.rs index cbbb878..a0c8f4a 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -103,6 +103,17 @@ impl RealtimeThreadSchedulePolicy { } } +/// Flags for controlling Deadline scheduling behavior. +#[derive(Debug, Clone, Copy, Ord, PartialEq, Eq, PartialOrd, Hash)] +pub enum DeadlineFlags { + /// Children created by fork will not inhered privileged scheduling policies. + ResetOnFork = 0x01, + /// The thread may reclaim bandwidth that is unused by another realtime thread. + Reclaim = 0x02, + /// Request to be sent SIGXCPU when this thread overruns its deadline. + DeadlineOverrun = 0x04, +} + /// Normal (usual) schedule policies #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum NormalThreadSchedulePolicy { @@ -220,7 +231,7 @@ impl ThreadPriority { _ => Ok(0), }, #[cfg(target_os = "linux")] - ThreadPriority::Deadline(_, _, _) => Err(Error::Priority( + ThreadPriority::Deadline(_, _, _, _) => Err(Error::Priority( "Deadline is non-POSIX and cannot be converted.", )), }; @@ -313,8 +324,8 @@ pub fn set_thread_schedule_policy( // SCHED_DEADLINE policy requires its own syscall #[cfg(target_os = "linux")] ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) => { - let (runtime, deadline, period) = match priority { - ThreadPriority::Deadline(r, d, p) => (r, d, p), + let (runtime, deadline, period, flags) = match priority { + ThreadPriority::Deadline(r, d, p, f) => (r, d, p, f), _ => { return Err(Error::Priority( "Deadline policy given without deadline priority.", @@ -325,20 +336,17 @@ pub fn set_thread_schedule_policy( let sched_attr = SchedAttr { size: std::mem::size_of::() as u32, sched_policy: policy.to_posix() as u32, - + sched_flags: match flags { + None => 0, + Some(flags) => flags as u64, + }, sched_runtime: runtime as u64, sched_deadline: deadline as u64, sched_period: period as u64, ..Default::default() }; - libc::syscall( - libc::SYS_sched_setattr, - tid, - &sched_attr as *const _, - // we are not setting SCHED_FLAG_RECLAIM nor SCHED_FLAG_DL_OVERRUN - 0, - ) as i32 + libc::syscall(libc::SYS_sched_setattr, tid, &sched_attr as *const _, 0) as i32 } _ => libc::pthread_setschedparam( native, @@ -543,7 +551,12 @@ mod tests { assert!(set_thread_priority_and_policy( 0, // current thread - ThreadPriority::Deadline(1 * 10_u64.pow(6), 10 * 10_u64.pow(6), 100 * 10_u64.pow(6)), + ThreadPriority::Deadline( + 1 * 10_u64.pow(6), + 10 * 10_u64.pow(6), + 100 * 10_u64.pow(6), + None + ), ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) ) .is_ok()); @@ -569,4 +582,48 @@ mod tests { assert_eq!(sched_attr.sched_period, 100 * 10_u64.pow(6)); } } + + #[test] + #[cfg(target_os = "linux")] + fn set_deadline_flags() { + // allow the identity operation for clarity + #![allow(clippy::identity_op)] + + assert!(set_thread_priority_and_policy( + 0, // current thread + ThreadPriority::Deadline( + 1 * 10_u64.pow(6), + 10 * 10_u64.pow(6), + 100 * 10_u64.pow(6), + Some(DeadlineFlags::DeadlineOverrun) + ), + ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Deadline) + ) + .is_ok()); + + // now we check the return values + unsafe { + let mut sched_attr = SchedAttr::default(); + let ret = libc::syscall( + libc::SYS_sched_getattr, + 0, // current thread + &mut sched_attr as *mut _, + std::mem::size_of::() as u32, + 0, // flags must be 0 + ); + + assert!(ret >= 0); + assert_eq!( + sched_attr.sched_policy, + RealtimeThreadSchedulePolicy::Deadline.to_posix() as u32 + ); + assert_eq!(sched_attr.sched_runtime, 1 * 10_u64.pow(6)); + assert_eq!(sched_attr.sched_deadline, 10 * 10_u64.pow(6)); + assert_eq!(sched_attr.sched_period, 100 * 10_u64.pow(6)); + assert_eq!( + sched_attr.sched_flags, + DeadlineFlags::DeadlineOverrun as u64 + ) + } + } }