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 be careful what kind of data
5 //! we continue to work with.
8 use std
::os
::raw
::c_int
;
9 use std
::os
::unix
::io
::{FromRawFd, IntoRawFd}
;
10 use std
::panic
::UnwindSafe
;
12 use crate::io
::pipe
::{self, Pipe}
;
13 use crate::syscall
::SyscallStatus
;
16 pub async
fn forking_syscall
<F
>(func
: F
) -> io
::Result
<SyscallStatus
>
18 F
: FnOnce() -> io
::Result
<SyscallStatus
> + UnwindSafe
,
20 let mut fork
= Fork
::new(func
)?
;
21 let result
= fork
.get_result().await?
;
27 pid
: Option
<libc
::pid_t
>,
28 // FIXME: abuse! tokio-fs is not updated to futures@0.3 yet, but a TcpStream does the same
29 // thing as a file when it's already open anyway...
30 out
: Pipe
<pipe
::Read
>,
35 if self.pid
.is_some() {
49 pub fn new
<F
>(func
: F
) -> io
::Result
<Self>
51 F
: FnOnce() -> io
::Result
<SyscallStatus
> + UnwindSafe
,
53 let (pipe_r
, pipe_w
) = pipe
::pipe()?
;
55 let pid
= c_try
!(unsafe { libc::fork() }
);
58 let mut pipe_w
= unsafe { Fd::from_raw_fd(pipe_w.into_raw_fd()) }
;
59 let _
= std
::panic
::catch_unwind(move || {
60 pipe_w
.set_nonblocking(false).unwrap();
61 let mut pipe_w
= unsafe { std::fs::File::from_raw_fd(pipe_w.into_raw_fd()) }
;
62 let out
= match func() {
63 Ok(SyscallStatus
::Ok(val
)) => Data
{
68 Ok(SyscallStatus
::Err(error
)) => Data
{
76 failure
: err
.raw_os_error().unwrap_or(libc
::EFAULT
),
81 std
::slice
::from_raw_parts(
82 &out
as *const Data
as *const u8,
83 std
::mem
::size_of
::<Data
>(),
88 match pipe_w
.write_all(slice
) {
89 Ok(()) => unsafe { libc::_exit(0) }
,
90 Err(_
) => unsafe { libc::_exit(1) }
,
105 pub fn wait(&mut self) -> io
::Result
<()> {
106 let my_pid
= self.pid
.take().unwrap();
107 let mut status
: c_int
= -1;
110 match c_result
!(unsafe { libc::waitpid(my_pid, &mut status, 0) }
) {
111 Ok(pid
) if pid
== my_pid
=> break,
112 Ok(_other
) => continue,
113 Err(ref err
) if err
.kind() == io
::ErrorKind
::Interrupted
=> continue,
114 Err(other
) => return Err(other
),
120 io
::ErrorKind
::Other
,
121 "error in child process",
128 pub async
fn get_result(&mut self) -> io
::Result
<SyscallStatus
> {
129 let mut data
: Data
= unsafe { std::mem::zeroed() }
;
130 // Compiler bug: we currently need to put the slice into a temporary variable...
131 let dataslice
: &mut [u8] = unsafe {
132 std
::slice
::from_raw_parts_mut(
133 &mut data
as *mut Data
as *mut u8,
134 std
::mem
::size_of
::<Data
>(),
137 self.out
.read_exact(dataslice
).await?
;
138 //self.read_exact(unsafe {
139 // std::slice::from_raw_parts_mut(
140 // &mut data as *mut Data as *mut u8,
141 // std::mem::size_of::<Data>(),
145 if data
.failure
!= 0 {
146 Err(io
::Error
::from_raw_os_error(data
.failure
))
147 } else if data
.error
== 0 {
148 Ok(SyscallStatus
::Ok(data
.val
))
150 Ok(SyscallStatus
::Err(data
.error
))