Add sched_attr system call series

This commit is contained in:
js2xxx
2025-02-11 13:35:24 +00:00
committed by Tate, Hongliang Tian
parent 9e1c939a3f
commit c1dde01fc3
24 changed files with 588 additions and 42 deletions

View File

@ -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 | ✅ |

View File

@ -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")

View File

@ -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},
};

View File

@ -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()
}

View File

@ -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())
}
}

View File

@ -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 {

View File

@ -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]);

View File

@ -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]);

View File

@ -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,

View File

@ -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;

View 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))
}

View 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))
}

View 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))
}

View 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))
}

View 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))
}

View 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))
}

View 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))
}

View 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))
}

View 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))
}

View File

@ -36,6 +36,7 @@ TEST_APPS := \
prctl \
pthread \
pty \
sched \
shm \
signal_c \
vsock \

5
test/apps/sched/Makefile Normal file
View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: MPL-2.0
include ../test_common.mk
EXTRA_C_FLAGS :=

View 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, &param),
_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, &param), EINVAL);
TEST_ERRNO(sched_setscheduler(-100, SCHED_FIFO, &param), EINVAL);
TEST_ERRNO(sched_setscheduler(1234567890, SCHED_FIFO, &param), ESRCH);
TEST_RES(sched_setscheduler(0, SCHED_FIFO, &param), _ret == 0);
sleep(1);
TEST_RES(sched_getscheduler(0), _ret == SCHED_FIFO);
TEST_RES(sched_getparam(0, &param),
_ret == 0 && param.sched_priority == 50);
param.sched_priority = 1234567890;
TEST_ERRNO(sched_setparam(0, NULL), EINVAL);
TEST_ERRNO(sched_setparam(-100, &param), EINVAL);
TEST_ERRNO(sched_setparam(1234567890, &param), ESRCH);
TEST_ERRNO(sched_setparam(0, &param), EINVAL);
param.sched_priority = 51;
TEST_RES(sched_setparam(0, &param), _ret == 0);
sleep(1);
TEST_RES(sched_getparam(0, &param),
_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()

View File

@ -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

View File

@ -38,6 +38,8 @@ TESTS ?= \
readv_test \
rename_test \
rlimits_test \
sched_test \
sched_yield_test \
semaphore_test \
sendfile_test \
sigaltstack_test \