alnyan/yggdrasil: process spawn + wait
This commit is contained in:
@@ -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) -> ! {
|
||||
|
||||
@@ -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!()
|
||||
}
|
||||
@@ -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!()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user