Skip to content

Commit

Permalink
Use the real pipe2(2) on all BSD targets.
Browse files Browse the repository at this point in the history
All supported non-Apple platforms now use the native syscall.  Only ios
and macos lack it.  It was added in:
* DragonflyBSD 4.2
* FreeBSD 10.0
* NetBSD 6.0
* OpenBSD 5.7
  • Loading branch information
asomers committed Nov 19, 2017
1 parent 1b9d205 commit ea98f44
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#602](https://github.com/nix-rust/nix/pull/774))

### Changed
- Use native `pipe` on all BSD targets. Users should notice no difference.
([#777](https://github.com/nix-rust/nix/pull/777))
- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))
- Marked `sys::ptrace::ptrace` as `unsafe`.
- Changed function signature of `socket()` and `socketpair()`. The `protocol` argument
Expand Down
37 changes: 27 additions & 10 deletions src/unistd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,10 +855,22 @@ pub fn pipe() -> Result<(RawFd, RawFd)> {
}
}

// libc only defines `pipe2` in `libc::notbsd`.
#[cfg(any(target_os = "linux",
target_os = "android",
target_os = "emscripten"))]
/// Like `pipe`, but allows setting certain file descriptor flags.
///
/// The following flags are supported, and will be set atomically as the pipe is
/// created:
///
/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
///
/// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html)
#[cfg(any(target_os = "android",
target_os = "dragonfly",
target_os = "emscripten",
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd"))]
pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };

Expand All @@ -869,9 +881,15 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
Ok((fds[0], fds[1]))
}

#[cfg(not(any(target_os = "linux",
target_os = "android",
target_os = "emscripten")))]
/// Like `pipe`, but allows setting certain file descriptor flags.
///
/// The following flags are supported, and will be set after the pipe is
/// created:
///
/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
#[cfg(any(target_os = "ios",
target_os = "macos"))]
pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };

Expand All @@ -884,9 +902,8 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
Ok((fds[0], fds[1]))
}

#[cfg(not(any(target_os = "linux",
target_os = "android",
target_os = "emscripten")))]
#[cfg(any(target_os = "ios",
target_os = "macos"))]
fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
use fcntl::O_NONBLOCK;
use fcntl::FcntlArg::F_SETFL;
Expand Down
24 changes: 24 additions & 0 deletions test/test_unistd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ extern crate tempdir;

use nix::unistd::*;
use nix::unistd::ForkResult::*;
use nix::fcntl;
use nix::sys::wait::*;
use nix::sys::stat;
use std::{env, iter};
Expand Down Expand Up @@ -291,3 +292,26 @@ fn test_sysconf_unsupported() {
let open_max = sysconf(SysconfVar::_XOPEN_CRYPT);
assert!(open_max.expect("sysconf failed").is_none())
}

// Test that we can create a pair of pipes. No need to verify that they pass
// data; that's the domain of the OS, not nix.
#[test]
fn test_pipe() {
let (fd0, fd1) = pipe().unwrap();
let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode);
// S_IFIFO means it's a pipe
assert_eq!(m0, stat::S_IFIFO);
let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode);
assert_eq!(m1, stat::S_IFIFO);
}

// pipe2(2) is the same as pipe(2), except it allows setting some flags. Check
// that we can set a flag.
#[test]
fn test_pipe2() {
let (fd0, fd1) = pipe2(fcntl::O_CLOEXEC).unwrap();
let f0 = fcntl::FdFlag::from_bits_truncate(fcntl::fcntl(fd0, fcntl::F_GETFD).unwrap());
assert!(f0.contains(fcntl::FD_CLOEXEC));
let f1 = fcntl::FdFlag::from_bits_truncate(fcntl::fcntl(fd1, fcntl::F_GETFD).unwrap());
assert!(f1.contains(fcntl::FD_CLOEXEC));
}

0 comments on commit ea98f44

Please sign in to comment.