mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 23:26:32 +00:00
Add sched_attr
system call series
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
9e1c939a3f
commit
c1dde01fc3
@ -162,12 +162,12 @@ provided by Linux on x86-64 architecture.
|
||||
| 139 | sysfs | ❌ |
|
||||
| 140 | getpriority | ✅ |
|
||||
| 141 | setpriority | ✅ |
|
||||
| 142 | sched_setparam | ❌ |
|
||||
| 143 | sched_getparam | ❌ |
|
||||
| 144 | sched_setscheduler | ❌ |
|
||||
| 145 | sched_getscheduler | ❌ |
|
||||
| 146 | sched_get_priority_max | ❌ |
|
||||
| 147 | sched_get_priority_min | ❌ |
|
||||
| 142 | sched_setparam | ✅ |
|
||||
| 143 | sched_getparam | ✅ |
|
||||
| 144 | sched_setscheduler | ✅ |
|
||||
| 145 | sched_getscheduler | ✅ |
|
||||
| 146 | sched_get_priority_max | ✅ |
|
||||
| 147 | sched_get_priority_min | ✅ |
|
||||
| 148 | sched_rr_get_interval | ❌ |
|
||||
| 149 | mlock | ❌ |
|
||||
| 150 | munlock | ❌ |
|
||||
@ -334,6 +334,8 @@ provided by Linux on x86-64 architecture.
|
||||
| 311 | process_vm_writev | ❌ |
|
||||
| 312 | kcmp | ❌ |
|
||||
| 313 | finit_module | ❌ |
|
||||
| 314 | sched_setattr | ✅ |
|
||||
| 315 | sched_getattr | ✅ |
|
||||
| 318 | getrandom | ✅ |
|
||||
| 322 | execveat | ✅ |
|
||||
| 327 | preadv2 | ✅ |
|
||||
|
@ -246,6 +246,12 @@ impl From<aster_block::bio::BioStatus> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::num::TryFromIntError> for Error {
|
||||
fn from(_: core::num::TryFromIntError) -> Self {
|
||||
Error::with_message(Errno::EINVAL, "Invalid integer")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::str::Utf8Error> for Error {
|
||||
fn from(_: core::str::Utf8Error) -> Self {
|
||||
Error::with_message(Errno::EINVAL, "Invalid utf-8 string")
|
||||
|
@ -6,6 +6,6 @@ mod stats;
|
||||
|
||||
pub use self::{
|
||||
nice::{AtomicNice, Nice},
|
||||
sched_class::{init, SchedAttr, SchedPolicy},
|
||||
sched_class::{init, RealTimePolicy, RealTimePriority, SchedAttr, SchedPolicy},
|
||||
stats::{loadavg, nr_queued_and_running},
|
||||
};
|
||||
|
@ -33,8 +33,11 @@ mod idle;
|
||||
mod real_time;
|
||||
mod stop;
|
||||
|
||||
pub use self::policy::SchedPolicy;
|
||||
use self::policy::{SchedPolicyKind, SchedPolicyState};
|
||||
pub use self::{
|
||||
policy::SchedPolicy,
|
||||
real_time::{RealTimePolicy, RealTimePriority},
|
||||
};
|
||||
|
||||
type SchedEntity = (Arc<Task>, Arc<Thread>);
|
||||
|
||||
@ -140,7 +143,7 @@ impl SchedAttr {
|
||||
real_time: {
|
||||
let (prio, policy) = match policy {
|
||||
SchedPolicy::RealTime { rt_prio, rt_policy } => (rt_prio.get(), rt_policy),
|
||||
_ => (real_time::RtPrio::MAX.get(), Default::default()),
|
||||
_ => (real_time::RealTimePriority::MAX.get(), Default::default()),
|
||||
};
|
||||
real_time::RealTimeAttr::new(prio, policy)
|
||||
},
|
||||
@ -174,6 +177,10 @@ impl SchedAttr {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn update_policy<T>(&self, f: impl FnOnce(&mut SchedPolicy) -> T) -> T {
|
||||
self.policy.update(f)
|
||||
}
|
||||
|
||||
fn last_cpu(&self) -> Option<CpuId> {
|
||||
self.last_cpu.get()
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use atomic_integer_wrapper::define_atomic_version_of_integer_like_type;
|
||||
use int_to_c_enum::TryFromInt;
|
||||
use ostd::sync::SpinLock;
|
||||
|
||||
pub use super::real_time::{RealTimePolicy, RtPrio};
|
||||
pub use super::real_time::{RealTimePolicy, RealTimePriority};
|
||||
use crate::sched::nice::Nice;
|
||||
|
||||
/// The User-chosen scheduling policy.
|
||||
@ -16,7 +16,7 @@ use crate::sched::nice::Nice;
|
||||
pub enum SchedPolicy {
|
||||
Stop,
|
||||
RealTime {
|
||||
rt_prio: RtPrio,
|
||||
rt_prio: RealTimePriority,
|
||||
rt_policy: RealTimePolicy,
|
||||
},
|
||||
Fair(Nice),
|
||||
@ -101,4 +101,8 @@ impl SchedPolicyState {
|
||||
self.kind.store(policy.kind(), Relaxed);
|
||||
*this = policy;
|
||||
}
|
||||
|
||||
pub fn update<T>(&self, update: impl FnOnce(&mut SchedPolicy) -> T) -> T {
|
||||
update(&mut *self.policy.disable_irq().lock())
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use ostd::{
|
||||
use super::{time::base_slice_clocks, CurrentRuntime, SchedAttr, SchedClassRq};
|
||||
use crate::{sched::nice::RangedU8, thread::AsThread};
|
||||
|
||||
pub type RtPrio = RangedU8<0, 99>;
|
||||
pub type RealTimePriority = RangedU8<1, 99>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum RealTimePolicy {
|
||||
|
@ -26,6 +26,7 @@ use crate::syscall::{
|
||||
flock::sys_flock,
|
||||
fsync::{sys_fdatasync, sys_fsync},
|
||||
futex::sys_futex,
|
||||
get_priority::sys_get_priority,
|
||||
getcpu::sys_getcpu,
|
||||
getcwd::sys_getcwd,
|
||||
getdents64::sys_getdents64,
|
||||
@ -81,6 +82,14 @@ use crate::syscall::{
|
||||
rt_sigprocmask::sys_rt_sigprocmask,
|
||||
rt_sigsuspend::sys_rt_sigsuspend,
|
||||
sched_affinity::{sys_sched_getaffinity, sys_sched_setaffinity},
|
||||
sched_get_priority_max::sys_sched_get_priority_max,
|
||||
sched_get_priority_min::sys_sched_get_priority_min,
|
||||
sched_getattr::sys_sched_getattr,
|
||||
sched_getparam::sys_sched_getparam,
|
||||
sched_getscheduler::sys_sched_getscheduler,
|
||||
sched_setattr::sys_sched_setattr,
|
||||
sched_setparam::sys_sched_setparam,
|
||||
sched_setscheduler::sys_sched_setscheduler,
|
||||
sched_yield::sys_sched_yield,
|
||||
semctl::sys_semctl,
|
||||
semget::sys_semget,
|
||||
@ -88,7 +97,7 @@ use crate::syscall::{
|
||||
sendfile::sys_sendfile,
|
||||
sendmsg::sys_sendmsg,
|
||||
sendto::sys_sendto,
|
||||
set_get_priority::{sys_get_priority, sys_set_priority},
|
||||
set_priority::sys_set_priority,
|
||||
set_robust_list::sys_set_robust_list,
|
||||
set_tid_address::sys_set_tid_address,
|
||||
setfsgid::sys_setfsgid,
|
||||
@ -192,9 +201,15 @@ impl_syscall_nums_and_dispatch_fn! {
|
||||
SYS_SETITIMER = 103 => sys_setitimer(args[..3]);
|
||||
SYS_TIMER_CREATE = 107 => sys_timer_create(args[..3]);
|
||||
SYS_TIMER_DELETE = 111 => sys_timer_delete(args[..1]);
|
||||
SYS_SCHED_SETPARAM = 118 => sys_sched_setparam(args[..2]);
|
||||
SYS_SCHED_SETSCHEDULER = 119 => sys_sched_setscheduler(args[..3]);
|
||||
SYS_SCHED_GETSCHEDULER = 120 => sys_sched_getscheduler(args[..1]);
|
||||
SYS_SCHED_GETPARAM = 121 => sys_sched_getparam(args[..2]);
|
||||
SYS_SCHED_SETAFFINITY = 122 => sys_sched_setaffinity(args[..3]);
|
||||
SYS_SCHED_GETAFFINITY = 123 => sys_sched_getaffinity(args[..3]);
|
||||
SYS_SCHED_YIELD = 124 => sys_sched_yield(args[..0]);
|
||||
SYS_SCHED_GET_PRIORITY_MAX = 125 => sys_sched_get_priority_max(args[..1]);
|
||||
SYS_SCHED_GET_PRIORITY_MIN = 126 => sys_sched_get_priority_min(args[..1]);
|
||||
SYS_KILL = 129 => sys_kill(args[..2]);
|
||||
SYS_TGKILL = 131 => sys_tgkill(args[..3]);
|
||||
SYS_SIGALTSTACK = 132 => sys_sigaltstack(args[..2]);
|
||||
@ -264,6 +279,8 @@ impl_syscall_nums_and_dispatch_fn! {
|
||||
SYS_ACCEPT4 = 242 => sys_accept4(args[..4]);
|
||||
SYS_WAIT4 = 260 => sys_wait4(args[..4]);
|
||||
SYS_PRLIMIT64 = 261 => sys_prlimit64(args[..4]);
|
||||
SYS_SCHED_SETATTR = 274 => sys_sched_setattr(args[..3]);
|
||||
SYS_SCHED_GETATTR = 275 => sys_sched_getattr(args[..4]);
|
||||
SYS_GETRANDOM = 278 => sys_getrandom(args[..3]);
|
||||
SYS_EXECVEAT = 281 => sys_execveat(args[..5], &mut user_ctx);
|
||||
SYS_PREADV2 = 286 => sys_preadv2(args[..5]);
|
||||
|
@ -29,6 +29,7 @@ use crate::syscall::{
|
||||
fork::sys_fork,
|
||||
fsync::{sys_fdatasync, sys_fsync},
|
||||
futex::sys_futex,
|
||||
get_priority::sys_get_priority,
|
||||
getcpu::sys_getcpu,
|
||||
getcwd::sys_getcwd,
|
||||
getdents64::{sys_getdents, sys_getdents64},
|
||||
@ -89,6 +90,14 @@ use crate::syscall::{
|
||||
rt_sigreturn::sys_rt_sigreturn,
|
||||
rt_sigsuspend::sys_rt_sigsuspend,
|
||||
sched_affinity::{sys_sched_getaffinity, sys_sched_setaffinity},
|
||||
sched_get_priority_max::sys_sched_get_priority_max,
|
||||
sched_get_priority_min::sys_sched_get_priority_min,
|
||||
sched_getattr::sys_sched_getattr,
|
||||
sched_getparam::sys_sched_getparam,
|
||||
sched_getscheduler::sys_sched_getscheduler,
|
||||
sched_setattr::sys_sched_setattr,
|
||||
sched_setparam::sys_sched_setparam,
|
||||
sched_setscheduler::sys_sched_setscheduler,
|
||||
sched_yield::sys_sched_yield,
|
||||
select::sys_select,
|
||||
semctl::sys_semctl,
|
||||
@ -97,7 +106,7 @@ use crate::syscall::{
|
||||
sendfile::sys_sendfile,
|
||||
sendmsg::sys_sendmsg,
|
||||
sendto::sys_sendto,
|
||||
set_get_priority::{sys_get_priority, sys_set_priority},
|
||||
set_priority::sys_set_priority,
|
||||
set_robust_list::sys_set_robust_list,
|
||||
set_tid_address::sys_set_tid_address,
|
||||
setfsgid::sys_setfsgid,
|
||||
@ -260,6 +269,12 @@ impl_syscall_nums_and_dispatch_fn! {
|
||||
SYS_FSTATFS = 138 => sys_fstatfs(args[..2]);
|
||||
SYS_GET_PRIORITY = 140 => sys_get_priority(args[..2]);
|
||||
SYS_SET_PRIORITY = 141 => sys_set_priority(args[..3]);
|
||||
SYS_SCHED_SETPARAM = 142 => sys_sched_setparam(args[..2]);
|
||||
SYS_SCHED_GETPARAM = 143 => sys_sched_getparam(args[..2]);
|
||||
SYS_SCHED_SETSCHEDULER = 144 => sys_sched_setscheduler(args[..3]);
|
||||
SYS_SCHED_GETSCHEDULER = 145 => sys_sched_getscheduler(args[..1]);
|
||||
SYS_SCHED_GET_PRIORITY_MAX = 146 => sys_sched_get_priority_max(args[..1]);
|
||||
SYS_SCHED_GET_PRIORITY_MIN = 147 => sys_sched_get_priority_min(args[..1]);
|
||||
SYS_PRCTL = 157 => sys_prctl(args[..5]);
|
||||
SYS_ARCH_PRCTL = 158 => sys_arch_prctl(args[..2], &mut user_ctx);
|
||||
SYS_SETRLIMIT = 160 => sys_setrlimit(args[..2]);
|
||||
@ -316,6 +331,8 @@ impl_syscall_nums_and_dispatch_fn! {
|
||||
SYS_PWRITEV = 296 => sys_pwritev(args[..4]);
|
||||
SYS_PRLIMIT64 = 302 => sys_prlimit64(args[..4]);
|
||||
SYS_GETCPU = 309 => sys_getcpu(args[..3]);
|
||||
SYS_SCHED_SETATTR = 314 => sys_sched_setattr(args[..3]);
|
||||
SYS_SCHED_GETATTR = 315 => sys_sched_getattr(args[..4]);
|
||||
SYS_GETRANDOM = 318 => sys_getrandom(args[..3]);
|
||||
SYS_EXECVEAT = 322 => sys_execveat(args[..5], &mut user_ctx);
|
||||
SYS_PREADV2 = 327 => sys_preadv2(args[..5]);
|
||||
|
@ -9,29 +9,6 @@ use crate::{
|
||||
sched::Nice,
|
||||
};
|
||||
|
||||
pub fn sys_set_priority(which: i32, who: u32, prio: i32, ctx: &Context) -> Result<SyscallReturn> {
|
||||
let prio_target = PriorityTarget::new(which, who, ctx)?;
|
||||
let new_nice: Nice = {
|
||||
let nice_raw = prio.clamp(
|
||||
Nice::MIN.value().get() as i32,
|
||||
Nice::MAX.value().get() as i32,
|
||||
) as i8;
|
||||
nice_raw.try_into().unwrap()
|
||||
};
|
||||
|
||||
debug!(
|
||||
"set_priority prio_target: {:?}, new_nice: {:?}",
|
||||
prio_target, new_nice
|
||||
);
|
||||
|
||||
let processes = get_processes(prio_target)?;
|
||||
for process in processes.iter() {
|
||||
process.nice().store(new_nice, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn sys_get_priority(which: i32, who: u32, ctx: &Context) -> Result<SyscallReturn> {
|
||||
let prio_target = PriorityTarget::new(which, who, ctx)?;
|
||||
debug!("get_priority prio_target: {:?}", prio_target);
|
||||
@ -55,7 +32,7 @@ pub fn sys_get_priority(which: i32, who: u32, ctx: &Context) -> Result<SyscallRe
|
||||
Ok(SyscallReturn::Return(highest_prio as _))
|
||||
}
|
||||
|
||||
fn get_processes(prio_target: PriorityTarget) -> Result<Vec<Arc<Process>>> {
|
||||
pub(super) fn get_processes(prio_target: PriorityTarget) -> Result<Vec<Arc<Process>>> {
|
||||
Ok(match prio_target {
|
||||
PriorityTarget::Process(pid) => {
|
||||
let process = process_table::get_process(pid).ok_or(Error::new(Errno::ESRCH))?;
|
||||
@ -90,14 +67,14 @@ fn get_processes(prio_target: PriorityTarget) -> Result<Vec<Arc<Process>>> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum PriorityTarget {
|
||||
pub(super) enum PriorityTarget {
|
||||
Process(Pid),
|
||||
ProcessGroup(Pgid),
|
||||
User(Uid),
|
||||
}
|
||||
|
||||
impl PriorityTarget {
|
||||
fn new(which: i32, who: u32, ctx: &Context) -> Result<Self> {
|
||||
pub(super) fn new(which: i32, who: u32, ctx: &Context) -> Result<Self> {
|
||||
let which = Which::try_from(which)
|
||||
.map_err(|_| Error::with_message(Errno::EINVAL, "invalid which value"))?;
|
||||
Ok(match which {
|
||||
@ -132,7 +109,7 @@ impl PriorityTarget {
|
||||
#[expect(non_camel_case_types)]
|
||||
#[derive(Clone, Debug, TryFromInt)]
|
||||
#[repr(i32)]
|
||||
enum Which {
|
||||
pub(super) enum Which {
|
||||
PRIO_PROCESS = 0,
|
||||
PRIO_PGRP = 1,
|
||||
PRIO_USER = 2,
|
@ -37,6 +37,7 @@ mod flock;
|
||||
mod fork;
|
||||
mod fsync;
|
||||
mod futex;
|
||||
mod get_priority;
|
||||
mod getcpu;
|
||||
mod getcwd;
|
||||
mod getdents64;
|
||||
@ -96,6 +97,14 @@ mod rt_sigprocmask;
|
||||
mod rt_sigreturn;
|
||||
mod rt_sigsuspend;
|
||||
mod sched_affinity;
|
||||
mod sched_get_priority_max;
|
||||
mod sched_get_priority_min;
|
||||
mod sched_getattr;
|
||||
mod sched_getparam;
|
||||
mod sched_getscheduler;
|
||||
mod sched_setattr;
|
||||
mod sched_setparam;
|
||||
mod sched_setscheduler;
|
||||
mod sched_yield;
|
||||
mod select;
|
||||
mod semctl;
|
||||
@ -104,7 +113,7 @@ mod semop;
|
||||
mod sendfile;
|
||||
mod sendmsg;
|
||||
mod sendto;
|
||||
mod set_get_priority;
|
||||
mod set_priority;
|
||||
mod set_robust_list;
|
||||
mod set_tid_address;
|
||||
mod setfsgid;
|
||||
|
38
kernel/src/syscall/sched_get_priority_max.rs
Normal file
38
kernel/src/syscall/sched_get_priority_max.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::ops::RangeInclusive;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::{prelude::*, sched::RealTimePriority};
|
||||
|
||||
pub(super) const fn rt_to_static(prio: RealTimePriority) -> u32 {
|
||||
(100 - prio.get()) as u32
|
||||
}
|
||||
|
||||
pub(super) const fn static_to_rt(prio: u32) -> Result<RealTimePriority> {
|
||||
if *RT_PRIORITY_RANGE.start() <= prio && prio <= *RT_PRIORITY_RANGE.end() {
|
||||
Ok(RealTimePriority::new((100 - prio) as u8))
|
||||
} else {
|
||||
Err(Error::with_message(Errno::EINVAL, "invalid priority"))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) const RT_PRIORITY_RANGE: RangeInclusive<u32> =
|
||||
rt_to_static(RealTimePriority::MAX)..=rt_to_static(RealTimePriority::MIN);
|
||||
pub(super) const SCHED_PRIORITY_RANGE: &[RangeInclusive<u32>] = &[
|
||||
0..=0, // SCHED_NORMAL
|
||||
RT_PRIORITY_RANGE, // SCHED_FIFO
|
||||
RT_PRIORITY_RANGE, // SCHED_RR
|
||||
0..=0, // SCHED_BATCH
|
||||
0..=0, // SCHED_ISO
|
||||
0..=0, // SCHED_IDLE
|
||||
0..=0, // SCHED_DEADLINE
|
||||
0..=0, // SCHED_EXT
|
||||
];
|
||||
|
||||
pub fn sys_sched_get_priority_max(policy: u32, _: &Context) -> Result<SyscallReturn> {
|
||||
let range = SCHED_PRIORITY_RANGE
|
||||
.get(policy as usize)
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid scheduling policy"))?;
|
||||
Ok(SyscallReturn::Return(*range.end() as isize))
|
||||
}
|
11
kernel/src/syscall/sched_get_priority_min.rs
Normal file
11
kernel/src/syscall/sched_get_priority_min.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{sched_get_priority_max::SCHED_PRIORITY_RANGE, SyscallReturn};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn sys_sched_get_priority_min(policy: u32, _: &Context) -> Result<SyscallReturn> {
|
||||
let range = SCHED_PRIORITY_RANGE
|
||||
.get(policy as usize)
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid scheduling policy"))?;
|
||||
Ok(SyscallReturn::Return(*range.start() as isize))
|
||||
}
|
212
kernel/src/syscall/sched_getattr.rs
Normal file
212
kernel/src/syscall/sched_getattr.rs
Normal file
@ -0,0 +1,212 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::mem;
|
||||
|
||||
use super::{
|
||||
sched_get_priority_max::{rt_to_static, static_to_rt, SCHED_PRIORITY_RANGE},
|
||||
SyscallReturn,
|
||||
};
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::posix_thread::thread_table,
|
||||
sched::{Nice, RealTimePolicy, SchedAttr, SchedPolicy},
|
||||
thread::Tid,
|
||||
};
|
||||
|
||||
pub(super) const SCHED_NORMAL: u32 = 0;
|
||||
pub(super) const SCHED_FIFO: u32 = 1;
|
||||
pub(super) const SCHED_RR: u32 = 2;
|
||||
// pub(super) const SCHED_BATCH: u32 = 3; // not supported (never).
|
||||
// SCHED_ISO: reserved but not implemented yet on Linux.
|
||||
pub(super) const SCHED_IDLE: u32 = 5;
|
||||
// pub(super) const SCHED_DEADLINE: u32 = 6; // not supported yet.
|
||||
// pub(super) const SCHED_EXT: u32 = 7; // not supported (never).
|
||||
|
||||
#[derive(Default, Debug, Pod, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub(super) struct LinuxSchedAttr {
|
||||
// Size of this structure
|
||||
pub(super) size: u32,
|
||||
|
||||
// Policy (SCHED_*)
|
||||
pub(super) sched_policy: u32,
|
||||
// Flags
|
||||
pub(super) sched_flags: u64,
|
||||
|
||||
// Nice value (SCHED_NORMAL, SCHED_BATCH)
|
||||
pub(super) sched_nice: i32,
|
||||
|
||||
// Static priority (SCHED_FIFO, SCHED_RR)
|
||||
pub(super) sched_priority: u32,
|
||||
|
||||
// For SCHED_DEADLINE
|
||||
pub(super) sched_runtime: u64,
|
||||
pub(super) sched_deadline: u64,
|
||||
pub(super) sched_period: u64,
|
||||
|
||||
// Utilization hints
|
||||
pub(super) sched_util_min: u32,
|
||||
pub(super) sched_util_max: u32,
|
||||
}
|
||||
|
||||
impl TryFrom<SchedPolicy> for LinuxSchedAttr {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: SchedPolicy) -> Result<Self> {
|
||||
Ok(match value {
|
||||
SchedPolicy::Stop => LinuxSchedAttr {
|
||||
sched_policy: SCHED_FIFO,
|
||||
sched_priority: 99, // Linux uses 99 as the default priority for STOP tasks.
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
SchedPolicy::RealTime { rt_prio, rt_policy } => LinuxSchedAttr {
|
||||
sched_policy: match rt_policy {
|
||||
RealTimePolicy::Fifo => SCHED_FIFO,
|
||||
RealTimePolicy::RoundRobin { .. } => SCHED_RR,
|
||||
},
|
||||
sched_priority: rt_to_static(rt_prio),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
SchedPolicy::Fair(nice) => LinuxSchedAttr {
|
||||
sched_policy: SCHED_NORMAL,
|
||||
sched_nice: nice.value().get().into(),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
SchedPolicy::Idle => LinuxSchedAttr {
|
||||
sched_policy: SCHED_IDLE,
|
||||
..Default::default()
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<LinuxSchedAttr> for SchedPolicy {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: LinuxSchedAttr) -> Result<Self> {
|
||||
Ok(match value.sched_policy {
|
||||
SCHED_FIFO | SCHED_RR => SchedPolicy::RealTime {
|
||||
rt_prio: static_to_rt(value.sched_priority)?,
|
||||
rt_policy: match value.sched_policy {
|
||||
SCHED_FIFO => RealTimePolicy::Fifo,
|
||||
SCHED_RR => RealTimePolicy::RoundRobin {
|
||||
base_slice_factor: None,
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
},
|
||||
|
||||
_ if value.sched_priority != 0 => {
|
||||
return Err(Error::with_message(
|
||||
Errno::EINVAL,
|
||||
"Invalid scheduling priority",
|
||||
))
|
||||
}
|
||||
|
||||
SCHED_NORMAL => SchedPolicy::Fair(Nice::new(
|
||||
i8::try_from(value.sched_nice)?
|
||||
.try_into()
|
||||
.map_err(|msg| Error::with_message(Errno::EINVAL, msg))?,
|
||||
)),
|
||||
|
||||
SCHED_IDLE => SchedPolicy::Idle,
|
||||
|
||||
_ => {
|
||||
return Err(Error::with_message(
|
||||
Errno::EINVAL,
|
||||
"Invalid scheduling policy",
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn read_linux_sched_attr_from_user(
|
||||
addr: Vaddr,
|
||||
ctx: &Context,
|
||||
) -> Result<LinuxSchedAttr> {
|
||||
let type_size = mem::size_of::<LinuxSchedAttr>();
|
||||
|
||||
let space = CurrentUserSpace::new(ctx.task);
|
||||
|
||||
let mut attr = LinuxSchedAttr::default();
|
||||
|
||||
space.read_bytes(
|
||||
addr,
|
||||
&mut VmWriter::from(&mut attr.as_bytes_mut()[..mem::size_of::<u32>()]),
|
||||
)?;
|
||||
|
||||
let size = type_size.min(attr.size as usize);
|
||||
space.read_bytes(addr, &mut VmWriter::from(&mut attr.as_bytes_mut()[..size]))?;
|
||||
|
||||
if let Some(additional_size) = attr.size.checked_sub(type_size as u32) {
|
||||
let mut buf = vec![0; additional_size as usize];
|
||||
space.read_bytes(addr + type_size, &mut VmWriter::from(&mut *buf))?;
|
||||
|
||||
if buf.iter().any(|&b| b != 0) {
|
||||
return Err(Error::with_message(Errno::E2BIG, "too big sched_attr"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(attr)
|
||||
}
|
||||
|
||||
pub(super) fn write_linux_sched_attr_to_user(
|
||||
mut attr: LinuxSchedAttr,
|
||||
addr: Vaddr,
|
||||
user_size: u32,
|
||||
ctx: &Context,
|
||||
) -> Result<()> {
|
||||
let space = CurrentUserSpace::new(ctx.task);
|
||||
|
||||
attr.size = (mem::size_of::<LinuxSchedAttr>() as u32).min(user_size);
|
||||
|
||||
let range = SCHED_PRIORITY_RANGE
|
||||
.get(attr.sched_policy as usize)
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid scheduling policy"))?;
|
||||
attr.sched_util_min = *range.start();
|
||||
attr.sched_util_max = *range.end();
|
||||
|
||||
space.write_bytes(
|
||||
addr,
|
||||
&mut VmReader::from(&attr.as_bytes()[..attr.size as usize]),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn access_sched_attr_with<T>(
|
||||
tid: Tid,
|
||||
ctx: &Context,
|
||||
f: impl FnOnce(&SchedAttr) -> Result<T>,
|
||||
) -> Result<T> {
|
||||
match tid {
|
||||
0 => f(&ctx.thread.sched_attr()),
|
||||
_ if tid > (i32::MAX as u32) => Err(Error::with_message(Errno::EINVAL, "invalid tid")),
|
||||
_ => f(&thread_table::get_thread(tid)
|
||||
.ok_or_else(|| Error::with_message(Errno::ESRCH, "thread does not exist"))?
|
||||
.sched_attr()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sys_sched_getattr(
|
||||
tid: Tid,
|
||||
addr: Vaddr,
|
||||
user_size: u32,
|
||||
flags: u32,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
if flags != 0 {
|
||||
// TODO: support flags soch as `RESET_ON_FORK`.
|
||||
return Err(Error::with_message(Errno::EINVAL, "unsupported flags"));
|
||||
}
|
||||
|
||||
let policy = access_sched_attr_with(tid, ctx, |attr| Ok(attr.policy()))?;
|
||||
let attr: LinuxSchedAttr = policy.try_into()?;
|
||||
write_linux_sched_attr_to_user(attr, addr, user_size, ctx)
|
||||
.map_err(|_| Error::new(Errno::EINVAL))?;
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
19
kernel/src/syscall/sched_getparam.rs
Normal file
19
kernel/src/syscall/sched_getparam.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{sched_getattr::access_sched_attr_with, SyscallReturn};
|
||||
use crate::{prelude::*, sched::SchedPolicy, thread::Tid};
|
||||
|
||||
pub fn sys_sched_getparam(tid: Tid, addr: Vaddr, ctx: &Context) -> Result<SyscallReturn> {
|
||||
let policy = access_sched_attr_with(tid, ctx, |attr| Ok(attr.policy()))?;
|
||||
let rt_prio = match policy {
|
||||
SchedPolicy::RealTime { rt_prio, .. } => rt_prio.get().into(),
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
let space = CurrentUserSpace::new(ctx.task);
|
||||
space
|
||||
.write_val(addr, &rt_prio)
|
||||
.map_err(|_| Error::new(Errno::EINVAL))?;
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
13
kernel/src/syscall/sched_getscheduler.rs
Normal file
13
kernel/src/syscall/sched_getscheduler.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{
|
||||
sched_getattr::{access_sched_attr_with, LinuxSchedAttr},
|
||||
SyscallReturn,
|
||||
};
|
||||
use crate::{prelude::*, thread::Tid};
|
||||
|
||||
pub fn sys_sched_getscheduler(tid: Tid, ctx: &Context) -> Result<SyscallReturn> {
|
||||
let policy = access_sched_attr_with(tid, ctx, |attr| Ok(attr.policy()))?;
|
||||
let policy = LinuxSchedAttr::try_from(policy)?.sched_policy;
|
||||
Ok(SyscallReturn::Return(policy as isize))
|
||||
}
|
28
kernel/src/syscall/sched_setattr.rs
Normal file
28
kernel/src/syscall/sched_setattr.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{
|
||||
sched_getattr::{access_sched_attr_with, read_linux_sched_attr_from_user},
|
||||
SyscallReturn,
|
||||
};
|
||||
use crate::{prelude::*, sched::SchedPolicy, thread::Tid};
|
||||
|
||||
pub fn sys_sched_setattr(
|
||||
tid: Tid,
|
||||
addr: Vaddr,
|
||||
flags: u32,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
if flags != 0 {
|
||||
// TODO: support flags soch as `RESET_ON_FORK`.
|
||||
return Err(Error::with_message(Errno::EINVAL, "unsupported flags"));
|
||||
}
|
||||
|
||||
let attr = read_linux_sched_attr_from_user(addr, ctx).map_err(|_| Error::new(Errno::EINVAL))?;
|
||||
let policy = SchedPolicy::try_from(attr)?;
|
||||
access_sched_attr_with(tid, ctx, |attr| {
|
||||
attr.set_policy(policy);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
27
kernel/src/syscall/sched_setparam.rs
Normal file
27
kernel/src/syscall/sched_setparam.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{sched_getattr::access_sched_attr_with, SyscallReturn};
|
||||
use crate::{prelude::*, sched::SchedPolicy, thread::Tid};
|
||||
|
||||
pub fn sys_sched_setparam(tid: Tid, addr: Vaddr, ctx: &Context) -> Result<SyscallReturn> {
|
||||
let space = CurrentUserSpace::new(ctx.task);
|
||||
let prio: i32 = space
|
||||
.read_val(addr)
|
||||
.map_err(|_| Error::new(Errno::EINVAL))?;
|
||||
|
||||
let update = |policy: &mut SchedPolicy| {
|
||||
match policy {
|
||||
SchedPolicy::RealTime { rt_prio, .. } => {
|
||||
*rt_prio = u8::try_from(prio)?
|
||||
.try_into()
|
||||
.map_err(|msg| Error::with_message(Errno::EINVAL, msg))?;
|
||||
}
|
||||
_ if prio != 0 => return Err(Error::with_message(Errno::EINVAL, "invalid priority")),
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
access_sched_attr_with(tid, ctx, |attr| attr.update_policy(update))?;
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
33
kernel/src/syscall/sched_setscheduler.rs
Normal file
33
kernel/src/syscall/sched_setscheduler.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{
|
||||
sched_getattr::{access_sched_attr_with, LinuxSchedAttr},
|
||||
SyscallReturn,
|
||||
};
|
||||
use crate::{prelude::*, thread::Tid};
|
||||
|
||||
pub fn sys_sched_setscheduler(
|
||||
tid: Tid,
|
||||
policy: i32,
|
||||
addr: Vaddr,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
let space = CurrentUserSpace::new(&ctx.task);
|
||||
let prio = space
|
||||
.read_val(addr)
|
||||
.map_err(|_| Error::new(Errno::EINVAL))?;
|
||||
|
||||
let attr = LinuxSchedAttr {
|
||||
sched_policy: policy as u32,
|
||||
sched_priority: prio,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let policy = attr.try_into()?;
|
||||
access_sched_attr_with(tid, ctx, |attr| {
|
||||
attr.set_policy(policy);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
42
kernel/src/syscall/set_priority.rs
Normal file
42
kernel/src/syscall/set_priority.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::ResourceType::RLIMIT_NICE,
|
||||
sched::Nice,
|
||||
syscall::get_priority::{get_processes, PriorityTarget},
|
||||
};
|
||||
|
||||
pub fn sys_set_priority(which: i32, who: u32, prio: i32, ctx: &Context) -> Result<SyscallReturn> {
|
||||
let prio_target = PriorityTarget::new(which, who, ctx)?;
|
||||
let new_nice: Nice = {
|
||||
let nice_raw = prio.clamp(
|
||||
Nice::MIN.value().get() as i32,
|
||||
Nice::MAX.value().get() as i32,
|
||||
) as i8;
|
||||
nice_raw.try_into().unwrap()
|
||||
};
|
||||
|
||||
debug!(
|
||||
"set_priority prio_target: {:?}, new_nice: {:?}",
|
||||
prio_target, new_nice
|
||||
);
|
||||
|
||||
let processes = get_processes(prio_target)?;
|
||||
for process in processes.iter() {
|
||||
let rlimit = process.resource_limits().lock();
|
||||
let limit = (rlimit.get_rlimit(RLIMIT_NICE).get_cur() as i8)
|
||||
.try_into()
|
||||
.map_err(|msg| Error::with_message(Errno::EINVAL, msg))?;
|
||||
|
||||
if new_nice < limit {
|
||||
return_errno!(Errno::EACCES);
|
||||
}
|
||||
process.nice().store(new_nice, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
@ -36,6 +36,7 @@ TEST_APPS := \
|
||||
prctl \
|
||||
pthread \
|
||||
pty \
|
||||
sched \
|
||||
shm \
|
||||
signal_c \
|
||||
vsock \
|
||||
|
5
test/apps/sched/Makefile
Normal file
5
test/apps/sched/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
75
test/apps/sched/sched_attr.c
Normal file
75
test/apps/sched/sched_attr.c
Normal file
@ -0,0 +1,75 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "../network/test.h"
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sched.h>
|
||||
|
||||
FN_SETUP()
|
||||
{
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
FN_TEST(sched_param)
|
||||
{
|
||||
TEST_ERRNO(sched_getscheduler(-100), EINVAL);
|
||||
TEST_ERRNO(sched_getscheduler(1234567890), ESRCH);
|
||||
TEST_RES(sched_getscheduler(0), _ret == SCHED_OTHER);
|
||||
|
||||
struct sched_param param;
|
||||
|
||||
TEST_ERRNO(sched_getparam(0, NULL), EINVAL);
|
||||
TEST_RES(sched_getparam(0, ¶m),
|
||||
_ret == 0 && param.sched_priority == 0);
|
||||
|
||||
param.sched_priority = 50;
|
||||
TEST_ERRNO(sched_setscheduler(0, SCHED_FIFO, NULL), EINVAL);
|
||||
TEST_ERRNO(sched_setscheduler(0, 1234567890, ¶m), EINVAL);
|
||||
TEST_ERRNO(sched_setscheduler(-100, SCHED_FIFO, ¶m), EINVAL);
|
||||
TEST_ERRNO(sched_setscheduler(1234567890, SCHED_FIFO, ¶m), ESRCH);
|
||||
TEST_RES(sched_setscheduler(0, SCHED_FIFO, ¶m), _ret == 0);
|
||||
sleep(1);
|
||||
|
||||
TEST_RES(sched_getscheduler(0), _ret == SCHED_FIFO);
|
||||
TEST_RES(sched_getparam(0, ¶m),
|
||||
_ret == 0 && param.sched_priority == 50);
|
||||
|
||||
param.sched_priority = 1234567890;
|
||||
TEST_ERRNO(sched_setparam(0, NULL), EINVAL);
|
||||
TEST_ERRNO(sched_setparam(-100, ¶m), EINVAL);
|
||||
TEST_ERRNO(sched_setparam(1234567890, ¶m), ESRCH);
|
||||
TEST_ERRNO(sched_setparam(0, ¶m), EINVAL);
|
||||
param.sched_priority = 51;
|
||||
TEST_RES(sched_setparam(0, ¶m), _ret == 0);
|
||||
sleep(1);
|
||||
|
||||
TEST_RES(sched_getparam(0, ¶m),
|
||||
_ret == 0 && param.sched_priority == 51);
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
FN_TEST(sched_prio_limit)
|
||||
{
|
||||
TEST_ERRNO(sched_get_priority_max(-100), EINVAL);
|
||||
TEST_ERRNO(sched_get_priority_max(1234567890), EINVAL);
|
||||
TEST_ERRNO(sched_get_priority_min(-100), EINVAL);
|
||||
TEST_ERRNO(sched_get_priority_min(1234567890), EINVAL);
|
||||
|
||||
TEST_RES(sched_get_priority_max(SCHED_OTHER), _ret == 0);
|
||||
TEST_RES(sched_get_priority_min(SCHED_OTHER), _ret == 0);
|
||||
|
||||
TEST_RES(sched_get_priority_max(SCHED_FIFO), _ret == 99);
|
||||
TEST_RES(sched_get_priority_min(SCHED_FIFO), _ret == 1);
|
||||
|
||||
TEST_RES(sched_get_priority_max(SCHED_RR), _ret == 99);
|
||||
TEST_RES(sched_get_priority_min(SCHED_RR), _ret == 1);
|
||||
|
||||
#ifdef __USE_GNU
|
||||
TEST_RES(sched_get_priority_max(SCHED_IDLE), _ret == 0);
|
||||
TEST_RES(sched_get_priority_min(SCHED_IDLE), _ret == 0);
|
||||
#endif
|
||||
}
|
||||
END_TEST()
|
@ -30,6 +30,7 @@ mmap/mmap_shared_filebacked
|
||||
mmap/mmap_readahead
|
||||
pthread/pthread_test
|
||||
pty/open_pty
|
||||
sched/sched_attr
|
||||
shm/posix_shm
|
||||
signal_c/parent_death_signal
|
||||
signal_c/signal_test
|
||||
|
@ -38,6 +38,8 @@ TESTS ?= \
|
||||
readv_test \
|
||||
rename_test \
|
||||
rlimits_test \
|
||||
sched_test \
|
||||
sched_yield_test \
|
||||
semaphore_test \
|
||||
sendfile_test \
|
||||
sigaltstack_test \
|
||||
|
Reference in New Issue
Block a user