From 2293828906cffff757dc29e27455b77e818b3604 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 19 Jan 2025 14:56:54 +0100 Subject: [PATCH] WIP: waitpid handler. --- src/procmngr.rs | 153 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 142 insertions(+), 11 deletions(-) diff --git a/src/procmngr.rs b/src/procmngr.rs index 904af7c011..bebb4b2e85 100644 --- a/src/procmngr.rs +++ b/src/procmngr.rs @@ -12,7 +12,7 @@ use alloc::vec::Vec; use hashbrown::hash_map::{DefaultHashBuilder, Entry, OccupiedEntry}; use hashbrown::{HashMap, HashSet}; use redox_rt::proc::FdGuard; -use redox_rt::protocol::{ProcCall, ProcMeta}; +use redox_rt::protocol::{ProcCall, ProcMeta, WaitFlags}; use redox_scheme::scheme::Op; use redox_scheme::{ CallerCtx, Id, OpenResult, RequestKind, Response, SendFdRequest, SignalBehavior, Socket, @@ -20,12 +20,9 @@ use redox_scheme::{ use slab::Slab; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, FobtainFdFlags, ProcSchemeAttrs, Result, EBADF, EBADFD, EEXIST, EINVAL, ENOENT, ENOSYS, - EOPNOTSUPP, EPERM, O_CLOEXEC, O_CREAT, + Error, FobtainFdFlags, ProcSchemeAttrs, Result, EAGAIN, EBADF, EBADFD, EEXIST, EINVAL, ENOENT, + ENOSYS, EOPNOTSUPP, EPERM, ESRCH, O_CLOEXEC, O_CREAT, }; -enum PendingState { - Waiting, -} pub fn run(write_fd: usize, auth: &FdGuard) { let socket = Socket::create("proc").expect("failed to open proc scheme socket"); @@ -102,7 +99,15 @@ pub fn run(write_fd: usize, auth: &FdGuard) { unreachable!() } +enum PendingState { + AwaitingStatusChange { + waiter: ProcessId, + target: WaitpidTarget, + }, + AwaitingThreadsTermination(ProcessId), +} +#[derive(Debug)] struct Process { threads: Vec>>, ppid: ProcessId, @@ -115,7 +120,20 @@ struct Process { egid: u32, rns: u32, ens: u32, + + status: ProcessStatus, + + waitpid: Vec, + children_waitpid: Vec, } +#[derive(Debug, Clone, Copy)] +enum ProcessStatus { + PossiblyRunnable, + Stopped(usize), + Exiting { status: i32 }, + Exited { status: i32 }, +} +#[derive(Debug)] struct Thread { fd: FdGuard, // sig_ctrl: MmapGuard<...> @@ -127,27 +145,35 @@ const INIT_PID: ProcessId = ProcessId(1); struct ProcScheme<'a> { processes: HashMap, - process_groups: HashSet, sessions: HashSet, handles: Slab, init_claimed: bool, next_id: ProcessId, + waitpgid: HashMap, DefaultHashBuilder>, auth: &'a FdGuard, } +#[derive(Debug)] enum Handle { Init, Proc(ProcessId), } +enum WaitpidTarget { + SingleProc(ProcessId), + ProcGroup(ProcessId), + AnyChild, + AnyGroupMember, +} + impl<'a> ProcScheme<'a> { pub fn new(auth: &'a FdGuard) -> ProcScheme { ProcScheme { processes: HashMap::new(), - process_groups: HashSet::new(), sessions: HashSet::new(), + waitpgid: HashMap::new(), handles: Slab::new(), init_claimed: false, next_id: ProcessId(2), @@ -182,9 +208,12 @@ impl<'a> ProcScheme<'a> { egid: 0, rns: 1, ens: 1, + + status: ProcessStatus::PossiblyRunnable, + waitpid: Vec::new(), + children_waitpid: Vec::new(), }, ); - self.process_groups.insert(INIT_PID); self.sessions.insert(INIT_PID); *st = Handle::Proc(INIT_PID); @@ -236,6 +265,10 @@ impl<'a> ProcScheme<'a> { egid, rns, ens, + + status: ProcessStatus::PossiblyRunnable, + waitpid: Vec::new(), + children_waitpid: Vec::new(), }, ); Ok(child_pid) @@ -339,11 +372,98 @@ impl<'a> ProcScheme<'a> { ) .map(|()| 0), ), - ProcCall::Waitpid => Ready(Err(Error::new(EOPNOTSUPP))), + ProcCall::Exit => self.on_exit_start(pid, metadata[1] as i32, state), + ProcCall::Waitpid | ProcCall::Waitpgid => { + let req_pid = ProcessId(metadata[1] as usize); + let target = match (verb, metadata[1] == 0) { + (ProcCall::Waitpid, true) => WaitpidTarget::AnyChild, + (ProcCall::Waitpid, false) => WaitpidTarget::SingleProc(req_pid), + (ProcCall::Waitpgid, true) => WaitpidTarget::AnyGroupMember, + (ProcCall::Waitpgid, false) => WaitpidTarget::ProcGroup(req_pid), + _ => unreachable!(), + }; + self.on_waitpid( + pid, + target, + plain::from_mut_bytes(payload).map_err(|_| Error::new(EINVAL))?, + WaitFlags::from_bits(metadata[2] as usize).ok_or(Error::new(EINVAL))?, + state, + ) + } } } } } + pub fn on_exit_start( + &mut self, + pid: ProcessId, + status: i32, + mut state: Entry, + ) -> Poll> { + let process = self.processes.get_mut(&pid).ok_or(Error::new(EBADFD))?; + match process.status { + ProcessStatus::Stopped(_) | ProcessStatus::PossiblyRunnable => (), + //ProcessStatus::Exiting => return Pending, + ProcessStatus::Exiting { .. } => return Ready(Err(Error::new(EAGAIN))), + ProcessStatus::Exited { .. } => return Ready(Err(Error::new(ESRCH))), + } + process.status = ProcessStatus::Exiting { status }; + if process.threads.is_empty() { + Self::on_exit_complete(); + Ready(Ok(0)) + } else { + let _ = syscall::write(1, b"\nEXIT PENDING\n"); + self.debug(); + // TODO: check? + state.insert(PendingState::AwaitingThreadsTermination(pid)); + Pending + } + } + fn on_exit_complete() { + // TODO: send waitpid status + } + pub fn on_waitpid( + &mut self, + this_pid: ProcessId, + target: WaitpidTarget, + stat_loc: &mut i32, + flags: WaitFlags, + mut state: Entry, + ) -> Poll> { + let _ = syscall::write(1, b"\nWAITPID\n"); + self.debug(); + Pending + } + fn ancestors(&self, pid: ProcessId) -> impl Iterator + '_ { + struct Iter<'a> { + cur: Option, + procs: &'a HashMap, + } + impl Iterator for Iter<'_> { + type Item = ProcessId; + + fn next(&mut self) -> Option { + let proc = self.procs.get(&self.cur?)?; + self.cur = Some(proc.ppid); + Some(proc.ppid) + } + } + Iter { + cur: Some(pid), + procs: &self.processes, + } + } + fn check_waitpid_queues( + &mut self, + waiter: ProcessId, + target: WaitpidTarget, + mask: WaitFlags, + ) -> Option<(ProcessId, i32)> { + /*match target { + //WaitpidTarget::SingleProc(target_pid) => , + }*/ + todo!() + } pub fn on_setrens(&mut self, pid: ProcessId, rns: Option, ens: Option) -> Result<()> { let process = self.processes.get_mut(&pid).ok_or(Error::new(EBADFD))?; let setrns = if rns.is_none() { @@ -407,7 +527,18 @@ impl<'a> ProcScheme<'a> { ) -> Poll { match entry.get_mut() { // TODO - PendingState::Waiting => Poll::Pending, + PendingState::AwaitingThreadsTermination(_) => Pending, + PendingState::AwaitingStatusChange { waiter, target } => Pending, } } + fn debug(&self) { + let _ = syscall::write( + 1, + alloc::format!("PROCESSES\n\n{:#?}\n\n", self.processes).as_bytes(), + ); + let _ = syscall::write( + 1, + alloc::format!("HANDLES\n\n{:#?}\n\n", self.handles).as_bytes(), + ); + } }