pal/unix/pipe.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use super::SyscallResult;
5use std::fs::File;
6use std::io::Result;
7use std::os::unix::prelude::*;
8
9/// Creates a connected pair of pipes, returning (read, write).
10pub fn pair() -> Result<(File, File)> {
11 // SAFETY: calling C APIs as documented, with no special requirements.
12 unsafe {
13 let mut fds = [0; 2];
14 #[cfg(target_os = "linux")]
15 {
16 // Use pipe2 to set O_CLOEXEC atomically with pipe creation.
17 libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC).syscall_result()?;
18 }
19 #[cfg(not(target_os = "linux"))]
20 {
21 // Create the pipes and then set O_CLOEXEC as a separate step since
22 // pipe2 is not available.
23 //
24 // N.B. There is a race window here where the pipe will be inherited
25 // by a child process if the fork occurs right after this call
26 // before O_CLOEXEC is set.
27 libc::pipe(fds.as_mut_ptr()).syscall_result()?;
28 libc::fcntl(fds[0], libc::F_SETFL, libc::O_CLOEXEC)
29 .syscall_result()
30 .unwrap();
31 libc::fcntl(fds[1], libc::F_SETFL, libc::O_CLOEXEC)
32 .syscall_result()
33 .unwrap();
34 }
35 Ok((File::from_raw_fd(fds[0]), File::from_raw_fd(fds[1])))
36 }
37}
38
39/// Sets a file's nonblocking state.
40pub fn set_nonblocking(file: &File, nonblock: bool) -> Result<()> {
41 // SAFETY: the fd is owned, and changing the nonblocking state should not
42 // result in any memory safety issues since it just changes the conditions
43 // under which an IO will fail.
44 unsafe {
45 let mut flags = libc::fcntl(file.as_raw_fd(), libc::F_GETFL).syscall_result()?;
46 if nonblock {
47 flags |= libc::O_NONBLOCK;
48 } else {
49 flags &= !libc::O_NONBLOCK;
50 }
51 libc::fcntl(file.as_raw_fd(), libc::F_SETFL, flags).syscall_result()?;
52 }
53 Ok(())
54}