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
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))
|
||||
}
|
Reference in New Issue
Block a user