From 1390823c9c424d1688e8847468f01e10392f4fad Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 25 Jul 2023 10:48:44 +0300 Subject: [PATCH] alnyan/yggdrasil: process spawn + wait --- library/std/src/sys/yggdrasil/mod.rs | 13 +- library/std/src/sys/yggdrasil/pipe.rs | 41 +++ library/std/src/sys/yggdrasil/process.rs | 303 +++++++++++++++++++++++ 3 files changed, 346 insertions(+), 11 deletions(-) create mode 100644 library/std/src/sys/yggdrasil/pipe.rs create mode 100644 library/std/src/sys/yggdrasil/process.rs diff --git a/library/std/src/sys/yggdrasil/mod.rs b/library/std/src/sys/yggdrasil/mod.rs index a1d876138af..bc13579c34d 100644 --- a/library/std/src/sys/yggdrasil/mod.rs +++ b/library/std/src/sys/yggdrasil/mod.rs @@ -6,10 +6,6 @@ use crate::io::ErrorKind; pub mod cmath; #[path = "../unix/os_str.rs"] pub mod os_str; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; -#[path = "../unsupported/process.rs"] -pub mod process; pub mod alloc; pub mod args; @@ -23,6 +19,8 @@ pub mod net; pub mod once; pub mod os; pub mod path; +pub mod pipe; +pub mod process; pub mod stdio; pub mod thread; pub mod thread_local_key; @@ -158,13 +156,6 @@ pub fn decode_error_kind(_errno: i32) -> ErrorKind { loop {} } -pub fn unsupported() -> ! { - unsafe { - yggdrasil_rt::sys::debug_trace("sys::yggrdasil::unsupported()"); - } - loop {} -} - #[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn runtime_entry(program_arg: usize) -> ! { diff --git a/library/std/src/sys/yggdrasil/pipe.rs b/library/std/src/sys/yggdrasil/pipe.rs new file mode 100644 index 00000000000..a43459b3b58 --- /dev/null +++ b/library/std/src/sys/yggdrasil/pipe.rs @@ -0,0 +1,41 @@ +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; + +pub struct AnonPipe(!); + +impl AnonPipe { + pub fn read(&self, _buf: &mut [u8]) -> io::Result { + self.0 + } + + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + + pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0 + } + + pub fn is_read_vectored(&self) -> bool { + self.0 + } + + pub fn read_to_end(&self, _buf: &mut Vec) -> io::Result { + self.0 + } + + pub fn write(&self, _buf: &[u8]) -> io::Result { + self.0 + } + + pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { + self.0 + } + + pub fn is_write_vectored(&self) -> bool { + self.0 + } +} + +pub fn read2(_p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { + todo!() +} diff --git a/library/std/src/sys/yggdrasil/process.rs b/library/std/src/sys/yggdrasil/process.rs new file mode 100644 index 00000000000..a3f50449f71 --- /dev/null +++ b/library/std/src/sys/yggdrasil/process.rs @@ -0,0 +1,303 @@ +use crate::ffi::OsStr; +use crate::fmt; +use crate::io; +use crate::num::NonZeroI32; +use crate::path::Path; +use crate::sys::cvt_io; +use crate::sys::fs::File; +use crate::sys::pipe::AnonPipe; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; + +pub use crate::ffi::OsString as EnvKey; + +use yggdrasil_rt::io::RawFd; +use yggdrasil_rt::process::{SpawnOption, SpawnOptions}; + +// Process + +// passed back to std::process with the pipes connected to the child, if any +// were requested +pub struct StdioPipes { + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, +} + +pub struct ChildPipes { + pub stdin: ChildStdio, + pub stdout: ChildStdio, + pub stderr: ChildStdio, +} + +#[derive(Debug)] +pub enum ChildStdio { + Inherit, +} + +#[derive(Debug)] +pub enum Stdio { + Inherit, + Null, + MakePipe, +} + +pub struct Process { + pid: u32, +} + +impl Process { + pub fn id(&self) -> u32 { + self.pid + } + + pub fn kill(&mut self) -> io::Result<()> { + todo!() + } + + pub fn wait(&mut self) -> io::Result { + let mut status = 0; + cvt_io(unsafe { yggdrasil_rt::sys::wait_process(self.pid, &mut status) })?; + Ok(ExitStatus(status)) + } + + pub fn try_wait(&mut self) -> io::Result> { + todo!() + } +} + +impl Stdio { + pub fn to_child_stdio(&self, _readable: bool) -> io::Result<(ChildStdio, Option)> { + match *self { + Stdio::Inherit => Ok((ChildStdio::Inherit, None)), + Stdio::MakePipe => todo!(), + Stdio::Null => todo!(), + } + } +} + +impl From for Stdio { + fn from(_pipe: AnonPipe) -> Stdio { + todo!() + } +} + +impl From for Stdio { + fn from(_file: File) -> Stdio { + todo!() + } +} + +// Status + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct ExitStatus(i32); + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct ExitStatusError(NonZeroI32); + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct ExitCode(bool); + +impl ExitStatus { + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + if self.0 == 0 { + Ok(()) + } else { + Err(ExitStatusError(unsafe { NonZeroI32::new_unchecked(self.0) })) + } + } + + pub fn code(&self) -> Option { + Some(self.0) + } +} + +impl ExitStatusError { + pub fn code(self) -> Option { + // TODO change this when signals are introduced + Some(self.0) + } +} + +impl From for ExitStatus { + fn from(value: ExitStatusError) -> Self { + Self(value.0.into()) + } +} + +impl ExitCode { + pub const SUCCESS: Self = Self(false); + pub const FAILURE: Self = Self(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + +impl From for ExitCode { + fn from(value: u8) -> Self { + Self(value != 0) + } +} + +impl fmt::Debug for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +// Command + +pub struct Command { + program: String, + args: Vec, + env: CommandEnv, +} + +pub struct CommandArgs<'a>(crate::slice::Iter<'a, String>); + +impl Command { + pub fn new(program: &OsStr) -> Self { + let program = program.to_str().unwrap().to_owned(); + + Self { program, args: vec![], env: Default::default() } + } + + pub fn arg(&mut self, arg: &OsStr) { + let arg = arg.to_str().unwrap().to_owned(); + + self.args.push(arg); + } + + pub fn env_mut(&mut self) -> &mut CommandEnv { + &mut self.env + } + + pub fn cwd(&mut self, _dir: &OsStr) { + todo!() + } + + pub fn stdin(&mut self, _stdin: Stdio) { + todo!() + } + + pub fn stdout(&mut self, _stdout: Stdio) { + todo!() + } + + pub fn stderr(&mut self, _stderr: Stdio) { + todo!() + } + + pub fn get_program(&self) -> &OsStr { + self.program.as_str().as_ref() + } + + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs(self.args.iter()) + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + todo!() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + todo!() + } + + pub fn spawn( + &mut self, + default: Stdio, + needs_stdin: bool, + ) -> io::Result<(Process, StdioPipes)> { + println!("spawn({:?}, {:?})", default, needs_stdin); + + let null = Stdio::Null; + let default_stdin = if needs_stdin { &default } else { &null }; + + let stdin = default_stdin; + let stdout = &default; + let stderr = &default; + + let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; + let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; + let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; + + let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr }; + let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr }; + + let process = self.do_spawn(&theirs)?; + + Ok((process, ours)) + } + + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { + todo!() + } + + fn do_spawn(&mut self, pipes: &ChildPipes) -> io::Result { + let mut optional = Vec::new(); + + optional.push(SpawnOption::InheritFile { + source: match pipes.stdin { + ChildStdio::Inherit => RawFd::STDIN, + }, + child: RawFd::STDIN, + }); + optional.push(SpawnOption::InheritFile { + source: match pipes.stdout { + ChildStdio::Inherit => RawFd::STDOUT, + }, + child: RawFd::STDOUT, + }); + optional.push(SpawnOption::InheritFile { + source: match pipes.stderr { + ChildStdio::Inherit => RawFd::STDERR, + }, + child: RawFd::STDERR, + }); + + let program = self.program.as_str(); + let arguments = &Vec::from_iter( + crate::iter::once(self.program.as_str()) + .chain(self.args.iter().map(|arg| arg.as_str())), + ); + + let options = SpawnOptions { program, arguments, optional: &optional }; + + let pid = cvt_io(unsafe { yggdrasil_rt::sys::spawn(&options) })?; + + Ok(Process { pid }) + } +} + +impl fmt::Debug for Command { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!() + } +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.0.next().map(|s| s.as_ref()) + } + + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> {} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!() + } +}