@@ -15,6 +15,33 @@ pub struct ScheduleParams {
1515 pub sched_priority : libc:: c_int ,
1616}
1717
18+ /// Copy of the Linux kernel's sched_attr type
19+ #[ repr( C ) ]
20+ #[ derive( Debug , Default ) ]
21+ #[ cfg( target_os = "linux" ) ]
22+ pub struct SchedAttr {
23+ size : u32 ,
24+ sched_policy : u32 ,
25+ sched_flags : u64 ,
26+
27+ /// for SCHED_NORMAL and SCHED_BATCH
28+ sched_nice : i32 ,
29+ /// for SCHED_FIFO, SCHED_RR
30+ sched_priority : u32 ,
31+
32+ /// for SCHED_DEADLINE
33+ sched_runtime : u64 ,
34+ /// for SCHED_DEADLINE
35+ sched_deadline : u64 ,
36+ /// for SCHED_DEADLINE
37+ sched_period : u64 ,
38+
39+ /// Utilization hint
40+ sched_util_min : u32 ,
41+ /// Utilization hint
42+ sched_util_max : u32 ,
43+ }
44+
1845impl ScheduleParams {
1946 #[ cfg( not( target_env = "musl" ) ) ]
2047 fn into_posix ( self ) -> libc:: sched_param {
@@ -57,12 +84,19 @@ pub enum RealtimeThreadSchedulePolicy {
5784 Fifo ,
5885 /// A round-robin policy
5986 RoundRobin ,
87+ /// A deadline policy. Note, due to Linux expecting a pid_t and not a pthread_t, the given
88+ /// [ThreadId](struct.ThreadId) will be interpreted as a pid_t. This policy is NOT
89+ /// POSIX-compatible, so we only include it for linux targets.
90+ #[ cfg( target_os = "linux" ) ]
91+ Deadline ,
6092}
6193impl RealtimeThreadSchedulePolicy {
6294 fn to_posix ( self ) -> libc:: c_int {
6395 match self {
6496 RealtimeThreadSchedulePolicy :: Fifo => 1 ,
6597 RealtimeThreadSchedulePolicy :: RoundRobin => 2 ,
98+ #[ cfg( target_os = "linux" ) ]
99+ RealtimeThreadSchedulePolicy :: Deadline => 6 ,
66100 }
67101 }
68102}
@@ -122,6 +156,10 @@ impl ThreadSchedulePolicy {
122156 2 => Ok ( ThreadSchedulePolicy :: Realtime (
123157 RealtimeThreadSchedulePolicy :: RoundRobin ,
124158 ) ) ,
159+ #[ cfg( target_os = "linux" ) ]
160+ 6 => Ok ( ThreadSchedulePolicy :: Realtime (
161+ RealtimeThreadSchedulePolicy :: Deadline ,
162+ ) ) ,
125163 _ => Err ( Error :: Ffi ( "Can't parse schedule policy from posix" ) ) ,
126164 }
127165 }
@@ -133,10 +171,20 @@ impl ThreadPriority {
133171 pub fn to_posix ( self , policy : ThreadSchedulePolicy ) -> Result < libc:: c_int , Error > {
134172 let ret = match self {
135173 ThreadPriority :: Min => match policy {
174+ // SCHED_DEADLINE doesn't really have a notion of priority, this is an error
175+ #[ cfg( target_os = "linux" ) ]
176+ ThreadSchedulePolicy :: Realtime ( RealtimeThreadSchedulePolicy :: Deadline ) => Err (
177+ Error :: Priority ( "Deadline scheduling must use deadline priority." ) ,
178+ ) ,
136179 ThreadSchedulePolicy :: Realtime ( _) => Ok ( 1 ) ,
137180 _ => Ok ( 0 ) ,
138181 } ,
139182 ThreadPriority :: Specific ( p) => match policy {
183+ // SCHED_DEADLINE doesn't really have a notion of priority, this is an error
184+ #[ cfg( target_os = "linux" ) ]
185+ ThreadSchedulePolicy :: Realtime ( RealtimeThreadSchedulePolicy :: Deadline ) => Err (
186+ Error :: Priority ( "Deadline scheduling must use deadline priority." ) ,
187+ ) ,
140188 ThreadSchedulePolicy :: Realtime ( _) if ( p == 0 || p > 99 ) => {
141189 Err ( Error :: Priority ( "The value is out of range [0; 99]" ) )
142190 }
@@ -146,9 +194,18 @@ impl ThreadPriority {
146194 _ => Ok ( p) ,
147195 } ,
148196 ThreadPriority :: Max => match policy {
197+ // SCHED_DEADLINE doesn't really have a notion of priority, this is an error
198+ #[ cfg( target_os = "linux" ) ]
199+ ThreadSchedulePolicy :: Realtime ( RealtimeThreadSchedulePolicy :: Deadline ) => Err (
200+ Error :: Priority ( "Deadline scheduling must use deadline priority." ) ,
201+ ) ,
149202 ThreadSchedulePolicy :: Realtime ( _) => Ok ( 99 ) ,
150203 _ => Ok ( 0 ) ,
151204 } ,
205+ #[ cfg( target_os = "linux" ) ]
206+ ThreadPriority :: Deadline ( _, _, _) => Err ( Error :: Priority (
207+ "Deadline is non-POSIX and cannot be converted." ,
208+ ) ) ,
152209 } ;
153210 ret. map ( |p| p as libc:: c_int )
154211 }
@@ -183,9 +240,12 @@ pub fn set_thread_priority_and_policy(
183240 policy : ThreadSchedulePolicy ,
184241) -> Result < ( ) , Error > {
185242 let params = ScheduleParams {
186- sched_priority : priority. to_posix ( policy) ?,
243+ sched_priority : match policy {
244+ ThreadSchedulePolicy :: Realtime ( RealtimeThreadSchedulePolicy :: Deadline ) => 0 ,
245+ _ => priority. to_posix ( policy) ?,
246+ } ,
187247 } ;
188- set_thread_schedule_policy ( native, policy, params)
248+ set_thread_schedule_policy ( native, policy, params, priority )
189249}
190250
191251/// Set current thread's priority.
@@ -211,6 +271,8 @@ pub fn thread_schedule_policy() -> Result<ThreadSchedulePolicy, Error> {
211271/// Sets thread schedule policy.
212272///
213273/// * May require privileges
274+ /// * Deadline policy requires a tid, not a pthread_t, so invoking this while using a deadline
275+ /// policy will interpret the given [ThreadId](struct.ThreadId) as a pid_t (thread tid).
214276///
215277/// # Usage
216278/// ```rust,no_run
@@ -219,20 +281,54 @@ pub fn thread_schedule_policy() -> Result<ThreadSchedulePolicy, Error> {
219281/// let thread_id = thread_native_id();
220282/// let policy = ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo);
221283/// let params = ScheduleParams { sched_priority: 3 as libc::c_int };
222- /// assert!(set_thread_schedule_policy(thread_id, policy, params).is_ok());
284+ /// let priority = ThreadPriority::Min;
285+ /// assert!(set_thread_schedule_policy(thread_id, policy, params, priority).is_ok());
223286/// ```
224287pub fn set_thread_schedule_policy (
225288 native : ThreadId ,
226289 policy : ThreadSchedulePolicy ,
227290 params : ScheduleParams ,
291+ priority : ThreadPriority ,
228292) -> Result < ( ) , Error > {
229293 let params = params. into_posix ( ) ;
230294 unsafe {
231- let ret = libc:: pthread_setschedparam (
232- native,
233- policy. to_posix ( ) ,
234- & params as * const libc:: sched_param ,
235- ) ;
295+ let ret = match policy {
296+ // SCHED_DEADLINE policy requires its own syscall
297+ #[ cfg( target_os = "linux" ) ]
298+ ThreadSchedulePolicy :: Realtime ( RealtimeThreadSchedulePolicy :: Deadline ) => {
299+ let ( runtime, deadline, period) = match priority {
300+ ThreadPriority :: Deadline ( r, d, p) => ( r, d, p) ,
301+ _ => {
302+ return Err ( Error :: Priority (
303+ "Deadline policy given without deadline priority." ,
304+ ) )
305+ }
306+ } ;
307+ let tid = native as libc:: pid_t ;
308+ let sched_attr = SchedAttr {
309+ size : std:: mem:: size_of :: < SchedAttr > ( ) as u32 ,
310+ sched_policy : policy. to_posix ( ) as u32 ,
311+
312+ sched_runtime : runtime as u64 ,
313+ sched_deadline : deadline as u64 ,
314+ sched_period : period as u64 ,
315+
316+ ..Default :: default ( )
317+ } ;
318+ libc:: syscall (
319+ libc:: SYS_sched_setattr ,
320+ tid,
321+ & sched_attr as * const _ ,
322+ // we are not setting SCHED_FLAG_RECLAIM nor SCHED_FLAG_DL_OVERRUN
323+ 0 ,
324+ ) as i32
325+ }
326+ _ => libc:: pthread_setschedparam (
327+ native,
328+ policy. to_posix ( ) ,
329+ & params as * const libc:: sched_param ,
330+ ) ,
331+ } ;
236332 match ret {
237333 0 => Ok ( ( ) ) ,
238334 e => Err ( Error :: OS ( e) ) ,
@@ -328,4 +424,39 @@ mod tests {
328424 )
329425 . is_ok( ) ) ;
330426 }
427+
428+ #[ test]
429+ #[ cfg( target_os = "linux" ) ]
430+ fn set_deadline_policy ( ) {
431+ // allow the identity operation for clarity
432+ #![ allow( clippy:: identity_op) ]
433+
434+ assert ! ( set_thread_priority_and_policy(
435+ 0 , // current thread
436+ ThreadPriority :: Deadline ( 1 * 10_u64 . pow( 6 ) , 10 * 10_u64 . pow( 6 ) , 100 * 10_u64 . pow( 6 ) ) ,
437+ ThreadSchedulePolicy :: Realtime ( RealtimeThreadSchedulePolicy :: Deadline )
438+ )
439+ . is_ok( ) ) ;
440+
441+ // now we check the return values
442+ unsafe {
443+ let mut sched_attr = SchedAttr :: default ( ) ;
444+ let ret = libc:: syscall (
445+ libc:: SYS_sched_getattr ,
446+ 0 , // current thread
447+ & mut sched_attr as * mut _ ,
448+ std:: mem:: size_of :: < SchedAttr > ( ) as u32 ,
449+ 0 , // flags must be 0
450+ ) ;
451+
452+ assert ! ( ret >= 0 ) ;
453+ assert_eq ! (
454+ sched_attr. sched_policy,
455+ RealtimeThreadSchedulePolicy :: Deadline . to_posix( ) as u32
456+ ) ;
457+ assert_eq ! ( sched_attr. sched_runtime, 1 * 10_u64 . pow( 6 ) ) ;
458+ assert_eq ! ( sched_attr. sched_deadline, 10 * 10_u64 . pow( 6 ) ) ;
459+ assert_eq ! ( sched_attr. sched_period, 100 * 10_u64 . pow( 6 ) ) ;
460+ }
461+ }
331462}
0 commit comments