Moves sys_cpuset_getaffinity to ProcManager (#868)

This commit is contained in:
Putta Khunchalee 2024-05-26 17:30:29 +07:00 committed by GitHub
parent e23ba2b76d
commit 404587185d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 168 additions and 100 deletions

View File

@ -1,4 +1,5 @@
use crate::{errno::EINVAL, syscalls::SysErr};
use crate::errno::EINVAL;
use crate::syscalls::{SysArg, SysErr};
/// An implementation of `cpuset`.
#[derive(Debug)]
@ -24,30 +25,40 @@ pub struct CpuMask {
}
/// An implementation of `cpulevel_t`.
#[derive(Debug, Clone, Copy)]
#[repr(i32)]
#[derive(Debug, Clone, Copy)]
pub(super) enum CpuLevel {
Root = 1,
Cpuset = 2,
Which = 3,
}
impl TryFrom<i32> for CpuLevel {
impl CpuLevel {
pub fn new(v: i32) -> Option<Self> {
Some(match v {
1 => Self::Root,
2 => Self::Cpuset,
3 => Self::Which,
_ => return None,
})
}
}
impl TryFrom<SysArg> for CpuLevel {
type Error = SysErr;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::Root),
2 => Ok(Self::Cpuset),
3 => Ok(Self::Which),
_ => Err(SysErr::Raw(EINVAL)),
}
fn try_from(value: SysArg) -> Result<Self, Self::Error> {
value
.try_into()
.ok()
.and_then(|v| Self::new(v))
.ok_or(SysErr::Raw(EINVAL))
}
}
/// An implementation of `cpuwhich_t`.
#[derive(Debug, Clone, Copy)]
#[repr(i32)]
#[derive(Debug, Clone, Copy)]
pub(super) enum CpuWhich {
Tid = 1,
Pid = 2,
@ -56,17 +67,27 @@ pub(super) enum CpuWhich {
Jail = 5,
}
impl TryFrom<i32> for CpuWhich {
type Error = SysErr;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::Tid),
2 => Ok(Self::Pid),
3 => Ok(Self::Cpuset),
4 => Ok(Self::Irq),
5 => Ok(Self::Jail),
_ => Err(SysErr::Raw(EINVAL)),
}
impl CpuWhich {
pub fn new(v: i32) -> Option<Self> {
Some(match v {
1 => Self::Tid,
2 => Self::Pid,
3 => Self::Cpuset,
4 => Self::Irq,
5 => Self::Jail,
_ => return None,
})
}
}
impl TryFrom<SysArg> for CpuWhich {
type Error = SysErr;
fn try_from(value: SysArg) -> Result<Self, Self::Error> {
value
.try_into()
.ok()
.and_then(|v| Self::new(v))
.ok_or(SysErr::Raw(EINVAL))
}
}

View File

@ -1,6 +1,6 @@
use crate::budget::ProcType;
use crate::dev::DmemContainer;
use crate::errno::{EINVAL, ENAMETOOLONG, EPERM, ESRCH};
use crate::errno::{EINVAL, ENAMETOOLONG, EPERM, ERANGE, ESRCH};
use crate::fs::{Fs, Vnode};
use crate::info;
use crate::rcmgr::RcMgr;
@ -67,6 +67,7 @@ impl ProcManager {
sys.register(416, &mgr, Self::sys_sigaction);
sys.register(432, &mgr, Self::sys_thr_self);
sys.register(464, &mgr, Self::sys_thr_set_name);
sys.register(487, &mgr, Self::sys_cpuset_getaffinity);
sys.register(585, &mgr, Self::sys_is_in_sandbox);
sys.register(587, &mgr, Self::sys_get_authinfo);
sys.register(602, &mgr, Self::sys_randomized_path);
@ -335,6 +336,50 @@ impl ProcManager {
Ok(SysOut::ZERO)
}
fn sys_cpuset_getaffinity(self: &Arc<Self>, _: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
// Get arguments.
let level: CpuLevel = i.args[0].try_into()?;
let which: CpuWhich = i.args[1].try_into()?;
let id: i64 = i.args[2].into();
let cpusetsize: usize = i.args[3].into();
let mask: *mut u8 = i.args[4].into();
// TODO: Refactor this for readability.
if cpusetsize.wrapping_sub(8) > 8 {
return Err(SysErr::Raw(ERANGE));
}
let (_, td) = self.cpuset_which(which, id)?;
let mut buf = vec![0u8; cpusetsize];
match level {
CpuLevel::Which => match which {
CpuWhich::Tid => {
let v = td.cpuset().mask().bits[0].to_ne_bytes();
buf[..v.len()].copy_from_slice(&v);
}
v => todo!("sys_cpuset_getaffinity with which = {v:?}"),
},
v => todo!("sys_cpuset_getaffinity with level = {v:?}"),
}
// TODO: What is this?
let x = u32::from_ne_bytes(buf[..4].try_into().unwrap());
let y = (x >> 1 & 0x55) + (x & 0x55) * 2;
let z = (y >> 2 & 0xfffffff3) + (y & 0x33) * 4;
unsafe {
std::ptr::write_unaligned::<u64>(
buf.as_mut_ptr() as _,
(z >> 4 | (z & 0xf) << 4) as u64,
);
std::ptr::copy_nonoverlapping(buf.as_ptr(), mask, cpusetsize);
}
Ok(SysOut::ZERO)
}
fn sys_is_in_sandbox(self: &Arc<Self>, td: &VThread, _: &SysIn) -> Result<SysOut, SysErr> {
let v = !Arc::ptr_eq(&td.proc().files().root(), &self.fs.root());
@ -480,6 +525,67 @@ impl ProcManager {
Ok(SysOut::ZERO)
}
/// See `cpuset_which` on the PS4 for a reference.
fn cpuset_which(&self, which: CpuWhich, id: i64) -> Result<(Arc<VProc>, Arc<VThread>), SysErr> {
// Get process and thread.
let (p, td) = match which {
CpuWhich::Tid => {
let td = if id == -1 {
VThread::current().unwrap().clone()
} else {
id.try_into()
.ok()
.and_then(|id| NonZeroI32::new(id))
.and_then(|id| self.thread(id, None))
.ok_or(SysErr::Raw(ESRCH))?
};
(td.proc().clone(), Some(td))
}
v => todo!("cpuset_which with which = {v:?}"),
};
// Check if the calling thread can reschedule the process.
VThread::current().unwrap().can_sched(&p)?;
match td {
Some(td) => Ok((p, td)),
None => todo!(),
}
}
/// See `tdfind` on the PS4 for a reference.
fn thread(&self, tid: NonZeroI32, pid: Option<Pid>) -> Option<Arc<VThread>> {
// TODO: Use a proper implementation.
match pid {
Some(pid) => {
let proc = self
.list
.read()
.unwrap()
.get(&pid)
.and_then(|p| p.upgrade())?;
let threads = proc.threads();
threads.iter().find(|&t| t.id() == tid).cloned()
}
None => {
let procs = self.list.read().unwrap();
for p in procs.values().map(|p| p.upgrade()).filter_map(|i| i) {
let threads = p.threads();
let found = threads.iter().find(|&t| t.id() == tid).cloned();
if found.is_some() {
return found;
}
}
None
}
}
}
fn new_id() -> NonZeroI32 {
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);

View File

@ -94,7 +94,6 @@ impl VProc {
// TODO: Move all syscalls here to somewhere else.
sys.register(455, &vp, Self::sys_thr_new);
sys.register(466, &vp, Self::sys_rtprio_thread);
sys.register(487, &vp, Self::sys_cpuset_getaffinity);
sys.register(488, &vp, Self::sys_cpuset_setaffinity);
vp.abi.set(ProcAbi::new(sys)).unwrap();
@ -273,53 +272,9 @@ impl VProc {
Ok(SysOut::ZERO)
}
fn sys_cpuset_getaffinity(self: &Arc<Self>, _: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
// Get arguments.
let level: CpuLevel = TryInto::<i32>::try_into(i.args[0]).unwrap().try_into()?;
let which: CpuWhich = TryInto::<i32>::try_into(i.args[1]).unwrap().try_into()?;
let id: i64 = i.args[2].into();
let cpusetsize: usize = i.args[3].into();
let mask: *mut u8 = i.args[4].into();
// TODO: Refactor this for readability.
if cpusetsize.wrapping_sub(8) > 8 {
return Err(SysErr::Raw(ERANGE));
}
let td = self.cpuset_which(which, id)?;
let mut buf = vec![0u8; cpusetsize];
match level {
CpuLevel::Which => match which {
CpuWhich::Tid => {
let v = td.cpuset().mask().bits[0].to_ne_bytes();
buf[..v.len()].copy_from_slice(&v);
}
v => todo!("sys_cpuset_getaffinity with which = {v:?}"),
},
v => todo!("sys_cpuset_getaffinity with level = {v:?}"),
}
// TODO: What is this?
let x = u32::from_ne_bytes(buf[..4].try_into().unwrap());
let y = (x >> 1 & 0x55) + (x & 0x55) * 2;
let z = (y >> 2 & 0xfffffff3) + (y & 0x33) * 4;
unsafe {
std::ptr::write_unaligned::<u64>(
buf.as_mut_ptr() as _,
(z >> 4 | (z & 0xf) << 4) as u64,
);
std::ptr::copy_nonoverlapping(buf.as_ptr(), mask, cpusetsize);
}
Ok(SysOut::ZERO)
}
fn sys_cpuset_setaffinity(self: &Arc<Self>, _: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
let level: CpuLevel = TryInto::<i32>::try_into(i.args[0]).unwrap().try_into()?;
let which: CpuWhich = TryInto::<i32>::try_into(i.args[1]).unwrap().try_into()?;
let level: CpuLevel = i.args[0].try_into()?;
let which: CpuWhich = i.args[1].try_into()?;
let _id: i64 = i.args[2].into();
let cpusetsize: usize = i.args[3].into();
let _mask: *const u8 = i.args[4].into();
@ -339,32 +294,6 @@ impl VProc {
v => todo!("sys_cpuset_setaffinity with level = {v:?}"),
}
}
/// See `cpuset_which` on the PS4 for a reference.
fn cpuset_which(&self, which: CpuWhich, id: i64) -> Result<Arc<VThread>, SysErr> {
let td = match which {
CpuWhich::Tid => {
if id == -1 {
todo!("cpuset_which with id = -1");
} else {
let threads = self.threads.read();
let td = threads
.iter()
.find(|t| t.id().get() == id as i32)
.ok_or(SysErr::Raw(ESRCH))?
.clone();
Some(td)
}
}
v => todo!("cpuset_which with which = {v:?}"),
};
match td {
Some(v) => Ok(v),
None => todo!("cpuset_which with td = NULL"),
}
}
}
#[repr(C)]

View File

@ -107,6 +107,17 @@ impl VThread {
self.cred.priv_check(p)
}
/// Determine whether current thread may reschedule `p`.
///
/// See `p_cansched` on the PS4 for a reference.
pub fn can_sched(&self, p: &Arc<VProc>) -> Result<(), CanSchedError> {
if Arc::ptr_eq(&self.proc, p) {
return Ok(());
}
todo!()
}
/// Start the thread.
///
/// The caller is responsible for `stack` deallocation.
@ -185,7 +196,8 @@ impl Drop for Running {
}
}
static VTHREAD: Tls<Arc<VThread>> = Tls::new();
/// Represents an error when [`VThread::can_sched()`] fails.
#[derive(Debug, Error, Errno)]
pub enum FileAllocError {}
pub enum CanSchedError {}
static VTHREAD: Tls<Arc<VThread>> = Tls::new();