From 8008643bb420c0700f5509975a6d298c15cea0bf Mon Sep 17 00:00:00 2001 From: Avril Date: Thu, 26 Aug 2021 23:44:44 +0100 Subject: [PATCH] `sys/fork`: Added moving arbitrary values into a stream, and moving them out of a stream again. This is for returning errors/return values from child process(es). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for comfork's current commit: Curse − 凶 --- src/sys/fork.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/sys/fork.rs b/src/sys/fork.rs index 2c64c49..5b88904 100644 --- a/src/sys/fork.rs +++ b/src/sys/fork.rs @@ -7,6 +7,17 @@ use libc::{ setuid, }; use std::{fmt, error}; +use std::io::{ + self, + Read, + Write, +}; +use std::marker::Unpin; +use std::panic::{ + AssertUnwindSafe, + catch_unwind, + resume_unwind, +}; use errno::Errno; @@ -27,6 +38,49 @@ pub enum ErrorKind Pipe(pipe::ErrorKind), } +// TODO: Add non-`sys` type: `Channel`, which can be used to send/recv typed data between parent and child. +// It should leverage the two below functions: `move_*_stream()`. + +/// Move a value into a stream. +/// +/// This function will return `Ok` if and only if all bytes from `val` were successfully written to the stream `to`. +/// If only a subset of them were written, then the data is corrupt and that is counted as an error. +/// +/// # Safety +/// The object `val` is written into the stream `to` verbatim. Its destructor is not run. +/// The object should be read verbatim from the stream with no errors or corruption before its dropped, or it will leak resources. +/// +/// This function is safe, but reading from the stream into a new object is not. +/// +/// ## Unpin +/// `T` should be `Unpin` in case it contains self-referrential data, as those references will no longer be valid after being moved across a stream. +// TODO: Should we expose these to the user somehow, with an unsafe helper module maybe? They could be useful. +// Or perhaps: Add the functionality to move types to/from the child/parent into the library, similar to `mpsc`. +pub(crate) fn move_write_value(mut to: S, val: T) -> io::Result<()> +{ + let bytes = unsafe { + std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::()) + }; + // Catch any panics that may happen in `write`. + let res = catch_unwind(AssertUnwindSafe(move || { + to.write_all(bytes) + })); + // Ensure this happens even if the above panics. + drop(bytes); // Make sure `bytes` isn't dangling after we move `val` into `forget()`. + std::mem::forget(val); + // Resume unwind if one occoured, if not return the value + match res { + Ok(v) => v, + Err(panic) => resume_unwind(panic), + } +} + +//TODO: Counterpart to `move_write_value()`. This function should be `unsafe` as it is extermely unsafe. +pub(crate) unsafe fn move_read_value(mut from: S) -> io::Result +{ + todo!() +} + /// An error in either forking or communicating with the child process during its setup. #[derive(Debug)] #[repr(transparent)]