|
1 |
| -use std::ptr; |
| 1 | +use std::{mem, ptr}; |
2 | 2 | use std::c_str::{CString, ToCStr};
|
3 | 3 | use libc::{c_char, c_void, c_int, size_t};
|
4 |
| -use fcntl::{Fd, OFlag}; |
| 4 | +use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC, F_SETFD, F_SETFL}; |
5 | 5 | use errno::{SysResult, SysError, from_ffi};
|
6 | 6 |
|
7 | 7 | #[cfg(target_os = "linux")]
|
8 | 8 | pub use self::linux::*;
|
9 | 9 |
|
10 | 10 | mod ffi {
|
11 | 11 | use libc::{c_char, c_int, size_t};
|
12 |
| - pub use libc::{close, read, write}; |
| 12 | + pub use libc::{close, read, write, pipe}; |
13 | 13 |
|
14 | 14 | extern {
|
15 | 15 | // duplicate a file descriptor
|
@@ -151,6 +151,99 @@ pub fn write(fd: Fd, buf: &[u8]) -> SysResult<uint> {
|
151 | 151 | return Ok(res as uint)
|
152 | 152 | }
|
153 | 153 |
|
| 154 | +pub fn pipe() -> SysResult<(Fd, Fd)> { |
| 155 | + unsafe { |
| 156 | + let mut res; |
| 157 | + let mut fds: [c_int, ..2] = mem::uninitialized(); |
| 158 | + |
| 159 | + res = ffi::pipe(fds.as_mut_ptr()); |
| 160 | + |
| 161 | + if res < 0 { |
| 162 | + return Err(SysError::last()); |
| 163 | + } |
| 164 | + |
| 165 | + Ok((fds[0], fds[1])) |
| 166 | + } |
| 167 | +} |
| 168 | + |
| 169 | +#[cfg(target_os = "linux")] |
| 170 | +pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> { |
| 171 | + type F = unsafe extern "C" fn(fds: *mut c_int, flags: c_int) -> c_int; |
| 172 | + |
| 173 | + extern { |
| 174 | + #[linkage = "extern_weak"] |
| 175 | + static pipe2: *const (); |
| 176 | + } |
| 177 | + |
| 178 | + let feat_atomic = !pipe2.is_null(); |
| 179 | + |
| 180 | + unsafe { |
| 181 | + let mut res; |
| 182 | + let mut fds: [c_int, ..2] = mem::uninitialized(); |
| 183 | + |
| 184 | + if feat_atomic { |
| 185 | + res = mem::transmute::<*const (), F>(pipe2)( |
| 186 | + fds.as_mut_ptr(), flags.bits()); |
| 187 | + } else { |
| 188 | + res = ffi::pipe(fds.as_mut_ptr()); |
| 189 | + } |
| 190 | + |
| 191 | + if res < 0 { |
| 192 | + return Err(SysError::last()); |
| 193 | + } |
| 194 | + |
| 195 | + if !feat_atomic { |
| 196 | + try!(pipe2_setflags(fds[0], fds[1], flags)); |
| 197 | + } |
| 198 | + |
| 199 | + Ok((fds[0], fds[1])) |
| 200 | + } |
| 201 | +} |
| 202 | + |
| 203 | +#[cfg(target_os = "macos")] |
| 204 | +#[cfg(target_os = "ios")] |
| 205 | +pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> { |
| 206 | + unsafe { |
| 207 | + let mut res; |
| 208 | + let mut fds: [c_int, ..2] = mem::uninitialized(); |
| 209 | + |
| 210 | + res = ffi::pipe(fds.as_mut_ptr()); |
| 211 | + |
| 212 | + if res < 0 { |
| 213 | + return Err(SysError::last()); |
| 214 | + } |
| 215 | + |
| 216 | + try!(pipe2_setflags(fds[0], fds[1], flags)); |
| 217 | + |
| 218 | + Ok((fds[0], fds[1])) |
| 219 | + } |
| 220 | +} |
| 221 | + |
| 222 | +fn pipe2_setflags(fd1: Fd, fd2: Fd, flags: OFlag) -> SysResult<()> { |
| 223 | + let mut res = Ok(()); |
| 224 | + |
| 225 | + if flags.contains(O_CLOEXEC) { |
| 226 | + res = res |
| 227 | + .and_then(|_| fcntl(fd1, F_SETFD(FD_CLOEXEC))) |
| 228 | + .and_then(|_| fcntl(fd2, F_SETFD(FD_CLOEXEC))); |
| 229 | + } |
| 230 | + |
| 231 | + if flags.contains(O_NONBLOCK) { |
| 232 | + res = res |
| 233 | + .and_then(|_| fcntl(fd1, F_SETFL(O_NONBLOCK))) |
| 234 | + .and_then(|_| fcntl(fd2, F_SETFL(O_NONBLOCK))); |
| 235 | + } |
| 236 | + |
| 237 | + match res { |
| 238 | + Ok(_) => Ok(()), |
| 239 | + Err(e) => { |
| 240 | + let _ = close(fd1); |
| 241 | + let _ = close(fd2); |
| 242 | + return Err(e); |
| 243 | + } |
| 244 | + } |
| 245 | +} |
| 246 | + |
154 | 247 | #[cfg(target_os = "linux")]
|
155 | 248 | mod linux {
|
156 | 249 | use std::path::Path;
|
|
0 commit comments