alnyan/yggdrasil: process spawn + wait

This commit is contained in:
2023-07-25 10:48:44 +03:00
parent 4621c13b78
commit 1390823c9c
3 changed files with 346 additions and 11 deletions
+2 -11
View File
@@ -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) -> ! {
+41
View File
@@ -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<usize> {
self.0
}
pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
self.0
}
pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0
}
pub fn is_read_vectored(&self) -> bool {
self.0
}
pub fn read_to_end(&self, _buf: &mut Vec<u8>) -> io::Result<usize> {
self.0
}
pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
self.0
}
pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0
}
pub fn is_write_vectored(&self) -> bool {
self.0
}
}
pub fn read2(_p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
todo!()
}
+303
View File
@@ -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<AnonPipe>,
pub stdout: Option<AnonPipe>,
pub stderr: Option<AnonPipe>,
}
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<ExitStatus> {
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<Option<ExitStatus>> {
todo!()
}
}
impl Stdio {
pub fn to_child_stdio(&self, _readable: bool) -> io::Result<(ChildStdio, Option<AnonPipe>)> {
match *self {
Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
Stdio::MakePipe => todo!(),
Stdio::Null => todo!(),
}
}
}
impl From<AnonPipe> for Stdio {
fn from(_pipe: AnonPipe) -> Stdio {
todo!()
}
}
impl From<File> 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<i32> {
Some(self.0)
}
}
impl ExitStatusError {
pub fn code(self) -> Option<NonZeroI32> {
// TODO change this when signals are introduced
Some(self.0)
}
}
impl From<ExitStatusError> 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<u8> 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<String>,
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<u8>, Vec<u8>)> {
todo!()
}
fn do_spawn(&mut self, pipes: &ChildPipes) -> io::Result<Process> {
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<usize>) {
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!()
}
}