Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for SCHED_DEADLINE flags #15

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<DeadlineFlags>),
/// 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
Expand Down
81 changes: 69 additions & 12 deletions src/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ impl RealtimeThreadSchedulePolicy {
}
}

/// Flags for controlling Deadline scheduling behavior.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please also add a link to any online "man" where this is also documented? Just in case one needs more information.

#[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 {
Expand Down Expand Up @@ -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.",
)),
};
Expand Down Expand Up @@ -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.",
Expand All @@ -325,20 +336,17 @@ pub fn set_thread_schedule_policy(
let sched_attr = SchedAttr {
size: std::mem::size_of::<SchedAttr>() 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,
Expand Down Expand Up @@ -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());
Expand All @@ -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,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have already used this syscall twice. Perhaps, there is also use of it for others in the library? Can we extract it into a unix::get_scheduling_attributes or anything like that, or whatever you think is worth doing?

0, // current thread
&mut sched_attr as *mut _,
std::mem::size_of::<SchedAttr>() 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
)
}
}
}