3 //! Note that forking in rust can be dangerous. A fork must consider all mutexes to be in a broken
4 //! state, and cannot rely on any of its reference life times, so we must be careful what kind of
5 //! data we continue to work with.
7 use std
::convert
::TryInto
;
9 use std
::os
::raw
::c_int
;
10 use std
::os
::unix
::io
::{FromRawFd, IntoRawFd}
;
11 use std
::panic
::UnwindSafe
;
13 use tokio
::io
::AsyncReadExt
;
15 use crate::io
::pipe
::{self, Pipe}
;
16 use crate::syscall
::SyscallStatus
;
18 pub async
fn forking_syscall
<F
>(func
: F
) -> io
::Result
<SyscallStatus
>
20 F
: FnOnce() -> io
::Result
<SyscallStatus
> + UnwindSafe
,
22 let mut fork
= Fork
::new(func
)?
;
23 let result
= fork
.get_result().await?
;
29 pid
: Option
<libc
::pid_t
>,
30 // FIXME: abuse! tokio-fs is not updated to futures@0.3 yet, but a TcpStream does the same
31 // thing as a file when it's already open anyway...
32 out
: Pipe
<pipe
::Read
>,
37 if self.pid
.is_some() {
51 pub fn new
<F
>(func
: F
) -> io
::Result
<Self>
53 F
: FnOnce() -> io
::Result
<SyscallStatus
> + UnwindSafe
,
55 let (pipe_r
, pipe_w
) = pipe
::pipe_fds()?
;
57 let pid
= c_try
!(unsafe { libc::fork() }
);
60 let pipe_w
= pipe_w
.into_fd();
61 let _
= std
::panic
::catch_unwind(move || {
62 crate::tools
::set_fd_nonblocking(&pipe_w
, false).unwrap();
63 let mut pipe_w
= unsafe { std::fs::File::from_raw_fd(pipe_w.into_raw_fd()) }
;
64 let out
= match func() {
65 Ok(SyscallStatus
::Ok(val
)) => Data
{
70 Ok(SyscallStatus
::Err(error
)) => Data
{
78 failure
: err
.raw_os_error().unwrap_or(libc
::EFAULT
),
83 std
::slice
::from_raw_parts(
84 &out
as *const Data
as *const u8,
85 std
::mem
::size_of
::<Data
>(),
90 match pipe_w
.write_all(slice
) {
91 Ok(()) => unsafe { libc::_exit(0) }
,
92 Err(_
) => unsafe { libc::_exit(1) }
,
101 let pipe_r
= match pipe_r
.try_into() {
117 pub fn wait(&mut self) -> io
::Result
<()> {
118 let my_pid
= self.pid
.take().unwrap();
119 let mut status
: c_int
= -1;
122 match c_result
!(unsafe { libc::waitpid(my_pid, &mut status, 0) }
) {
123 Ok(pid
) if pid
== my_pid
=> break,
124 Ok(_other
) => continue,
125 Err(ref err
) if err
.kind() == io
::ErrorKind
::Interrupted
=> continue,
126 Err(other
) => return Err(other
),
132 io
::ErrorKind
::Other
,
133 "error in child process",
140 pub async
fn get_result(&mut self) -> io
::Result
<SyscallStatus
> {
141 let mut data
: Data
= unsafe { std::mem::zeroed() }
;
142 // Compiler bug: we currently need to put the slice into a temporary variable...
143 let dataslice
: &mut [u8] = unsafe {
144 std
::slice
::from_raw_parts_mut(
145 &mut data
as *mut Data
as *mut u8,
146 std
::mem
::size_of
::<Data
>(),
149 self.out
.read_exact(dataslice
).await?
;
150 //self.read_exact(unsafe {
151 // std::slice::from_raw_parts_mut(
152 // &mut data as *mut Data as *mut u8,
153 // std::mem::size_of::<Data>(),
157 if data
.failure
!= 0 {
158 Err(io
::Error
::from_raw_os_error(data
.failure
))
159 } else if data
.error
== 0 {
160 Ok(SyscallStatus
::Ok(data
.val
))
162 Ok(SyscallStatus
::Err(data
.error
))