From 404587185dd89511a42343168b4e8f2ab81c7019 Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Sun, 26 May 2024 17:30:29 +0700 Subject: [PATCH] Moves sys_cpuset_getaffinity to ProcManager (#868) --- src/kernel/src/process/cpuset.rs | 67 ++++++++++++------- src/kernel/src/process/mod.rs | 108 ++++++++++++++++++++++++++++++- src/kernel/src/process/proc.rs | 75 +-------------------- src/kernel/src/process/thread.rs | 18 +++++- 4 files changed, 168 insertions(+), 100 deletions(-) diff --git a/src/kernel/src/process/cpuset.rs b/src/kernel/src/process/cpuset.rs index 80812586..20d70722 100644 --- a/src/kernel/src/process/cpuset.rs +++ b/src/kernel/src/process/cpuset.rs @@ -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 for CpuLevel { +impl CpuLevel { + pub fn new(v: i32) -> Option { + Some(match v { + 1 => Self::Root, + 2 => Self::Cpuset, + 3 => Self::Which, + _ => return None, + }) + } +} + +impl TryFrom for CpuLevel { type Error = SysErr; - fn try_from(value: i32) -> Result { - match value { - 1 => Ok(Self::Root), - 2 => Ok(Self::Cpuset), - 3 => Ok(Self::Which), - _ => Err(SysErr::Raw(EINVAL)), - } + fn try_from(value: SysArg) -> Result { + 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 for CpuWhich { - type Error = SysErr; - - fn try_from(value: i32) -> Result { - 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 { + Some(match v { + 1 => Self::Tid, + 2 => Self::Pid, + 3 => Self::Cpuset, + 4 => Self::Irq, + 5 => Self::Jail, + _ => return None, + }) + } +} + +impl TryFrom for CpuWhich { + type Error = SysErr; + + fn try_from(value: SysArg) -> Result { + value + .try_into() + .ok() + .and_then(|v| Self::new(v)) + .ok_or(SysErr::Raw(EINVAL)) } } diff --git a/src/kernel/src/process/mod.rs b/src/kernel/src/process/mod.rs index 384d12b8..62b0c984 100644 --- a/src/kernel/src/process/mod.rs +++ b/src/kernel/src/process/mod.rs @@ -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, _: &VThread, i: &SysIn) -> Result { + // 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::( + 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, td: &VThread, _: &SysIn) -> Result { 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, Arc), 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) -> Option> { + // 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); diff --git a/src/kernel/src/process/proc.rs b/src/kernel/src/process/proc.rs index a9608d0b..9f12bc21 100644 --- a/src/kernel/src/process/proc.rs +++ b/src/kernel/src/process/proc.rs @@ -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, _: &VThread, i: &SysIn) -> Result { - // Get arguments. - let level: CpuLevel = TryInto::::try_into(i.args[0]).unwrap().try_into()?; - let which: CpuWhich = TryInto::::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::( - 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, _: &VThread, i: &SysIn) -> Result { - let level: CpuLevel = TryInto::::try_into(i.args[0]).unwrap().try_into()?; - let which: CpuWhich = TryInto::::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, 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)] diff --git a/src/kernel/src/process/thread.rs b/src/kernel/src/process/thread.rs index 4cba5046..ea756cc6 100644 --- a/src/kernel/src/process/thread.rs +++ b/src/kernel/src/process/thread.rs @@ -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) -> 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> = Tls::new(); - +/// Represents an error when [`VThread::can_sched()`] fails. #[derive(Debug, Error, Errno)] -pub enum FileAllocError {} +pub enum CanSchedError {} + +static VTHREAD: Tls> = Tls::new();