diff --git a/src/sys/unix/kqueue.rs b/src/sys/unix/kqueue.rs index 6b8c92b93..b47be1afc 100644 --- a/src/sys/unix/kqueue.rs +++ b/src/sys/unix/kqueue.rs @@ -95,13 +95,37 @@ impl Selector { ::std::ptr::null()))); for change in changes.iter() { debug_assert_eq!(change.flags & libc::EV_ERROR, libc::EV_ERROR); - if change.data != 0 { - // there’s some error, but we want to ignore ENOENT error for EV_DELETE - let orig_flags = if change.filter == libc::EVFILT_READ { r } else { w }; - if !(change.data as i32 == libc::ENOENT && orig_flags & libc::EV_DELETE != 0) { - return Err(::std::io::Error::from_raw_os_error(change.data as i32)); - } + + // Test to see if an error happened + if change.data == 0 { + continue + } + + // Older versions of OSX (10.11 and 10.10 have been witnessed) + // can return EPIPE when registering a pipe file descriptor + // where the other end has already disappeared. For example code + // that creates a pipe, closes a file descriptor, and then + // registers the other end will see an EPIPE returned from + // `register`. + // + // It also turns out that kevent will still report events on the + // file descriptor, telling us that it's readable/hup at least + // after we've done this registration. As a result we just + // ignore `EPIPE` here instead of propagating it. + // + // More info can be found at carllerche/mio#582 + if change.data as i32 == libc::EPIPE && + change.filter == libc::EVFILT_WRITE { + continue } + + // ignore ENOENT error for EV_DELETE + let orig_flags = if change.filter == libc::EVFILT_READ { r } else { w }; + if change.data as i32 == libc::ENOENT && orig_flags & libc::EV_DELETE != 0 { + continue + } + + return Err(::std::io::Error::from_raw_os_error(change.data as i32)); } Ok(()) } diff --git a/test/test_broken_pipe.rs b/test/test_broken_pipe.rs index 1e3b73cd3..1cd0ca746 100644 --- a/test/test_broken_pipe.rs +++ b/test/test_broken_pipe.rs @@ -19,8 +19,8 @@ pub fn broken_pipe() { let mut event_loop: EventLoop = EventLoop::new().unwrap(); let (reader, _) = unix::pipe().unwrap(); - // On Darwin this returns a "broken pipe" error. - let _ = event_loop.register(&reader, Token(1), Ready::all(), PollOpt::edge()); + event_loop.register(&reader, Token(1), Ready::all(), PollOpt::edge()) + .unwrap(); let mut handler = BrokenPipeHandler; drop(reader);