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 std
::task
::{Context, Poll}
;
14 use futures
::future
::poll_fn
;
15 use futures
::io
::AsyncRead
;
17 use crate::syscall
::SyscallStatus
;
19 use crate::{libc_try, libc_wrap}
;
21 pub async
fn forking_syscall
<F
>(func
: F
) -> io
::Result
<SyscallStatus
>
23 F
: FnOnce() -> io
::Result
<SyscallStatus
> + UnwindSafe
,
25 let mut fork
= Fork
::new(func
)?
;
26 let mut buf
= [0u8; 10];
28 use futures
::io
::AsyncReadExt
;
29 fork
.read_exact(&mut buf
).await?
;
32 Ok(SyscallStatus
::Err(libc
::ENOENT
))
36 pid
: Option
<libc
::pid_t
>,
37 // FIXME: abuse! tokio-fs is not updated to futures@0.3 yet, but a TcpStream does the same
38 // thing as a file when it's already open anyway...
39 out
: crate::tools
::GenericStream
,
44 if self.pid
.is_some() {
51 pub fn new
<F
>(func
: F
) -> io
::Result
<Self>
53 F
: FnOnce() -> io
::Result
<SyscallStatus
> + UnwindSafe
,
55 let mut pipe
: [c_int
; 2] = [0, 0];
56 libc_try
!(unsafe { libc::pipe2(pipe.as_mut_ptr(), libc::O_CLOEXEC | libc::O_NONBLOCK) }
);
57 let (pipe_r
, pipe_w
) = (Fd(pipe
[0]), Fd(pipe
[1]));
59 let pipe_r
= match crate::tools
::GenericStream
::from_fd(pipe_r
) {
61 Err(err
) => return Err(io
::Error
::new(io
::ErrorKind
::Other
, err
.to_string())),
64 let pid
= libc_try
!(unsafe { libc::fork() }
);
66 std
::mem
::drop(pipe_r
);
67 let mut pipe_w
= unsafe { std::fs::File::from_raw_fd(pipe_w.into_raw_fd()) }
;
69 let _
= std
::panic
::catch_unwind(move || {
70 let mut buf
= [0u8; 10];
73 Ok(SyscallStatus
::Ok(value
)) => unsafe {
74 std
::ptr
::write(buf
.as_mut_ptr().add(1) as *mut i64, value
);
76 Ok(SyscallStatus
::Err(value
)) => {
79 std
::ptr
::write(buf
.as_mut_ptr().add(1) as *mut i32, value
);
82 Err(err
) => match err
.raw_os_error() {
86 std
::ptr
::write(buf
.as_mut_ptr().add(1) as *mut i32, err
);
96 match pipe_w
.write_all(&buf
) {
97 Ok(()) => unsafe { libc::_exit(0) }
,
98 Err(_
) => unsafe { libc::_exit(1) }
,
112 pub fn wait(&mut self) -> io
::Result
<()> {
113 let my_pid
= self.pid
.take().unwrap();
116 let mut status
: c_int
= -1;
117 match libc_wrap
!(unsafe { libc::waitpid(my_pid, &mut status, 0) }
) {
118 Ok(pid
) if pid
== my_pid
=> break,
119 Ok(_other
) => continue,
120 Err(ref err
) if err
.kind() == io
::ErrorKind
::Interrupted
=> continue,
121 Err(other
) => return Err(other
),
128 pub async
fn async_read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
129 poll_fn(|cx
| Pin
::new(&mut *self).poll_read(cx
, buf
)).await
133 // default impl will work
134 impl AsyncRead
for Fork
{
136 self: Pin
<&mut Self>,
139 ) -> Poll
<io
::Result
<usize>> {
140 unsafe { self.map_unchecked_mut(|this| &mut this.out) }
.poll_read(cx
, buf
)
143 unsafe fn initializer(&self) -> futures
::io
::Initializer
{
144 self.out
.initializer()
147 fn poll_read_vectored(
148 self: Pin
<&mut Self>,
150 bufs
: &mut [futures
::io
::IoSliceMut
],
151 ) -> Poll
<io
::Result
<usize>> {
152 unsafe { self.map_unchecked_mut(|this| &mut this.out) }
.poll_read_vectored(cx
, bufs
)