Skip to content

Commit fe551aa

Browse files
authored
kqueue: Ignore EPIPE coming out of kevent (#584)
This commit updates mio to ignore `EPIPE` coming out of `kevent`. It turns out that older versions of OSX (10.10 and 10.11 have been confirmed) will return an `EPIPE` when registering one half of a pipe where the other half has been closed. On other platforms this is an ok operation which just returns that the pipe is readable/writable (to return an error/eof), so this brings the OSX behavior in line by ignoring the error and moving to the next event. Closes #582
1 parent c401da5 commit fe551aa

File tree

2 files changed

+32
-8
lines changed

2 files changed

+32
-8
lines changed

src/sys/unix/kqueue.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,37 @@ impl Selector {
9595
::std::ptr::null())));
9696
for change in changes.iter() {
9797
debug_assert_eq!(change.flags & libc::EV_ERROR, libc::EV_ERROR);
98-
if change.data != 0 {
99-
// there’s some error, but we want to ignore ENOENT error for EV_DELETE
100-
let orig_flags = if change.filter == libc::EVFILT_READ { r } else { w };
101-
if !(change.data as i32 == libc::ENOENT && orig_flags & libc::EV_DELETE != 0) {
102-
return Err(::std::io::Error::from_raw_os_error(change.data as i32));
103-
}
98+
99+
// Test to see if an error happened
100+
if change.data == 0 {
101+
continue
102+
}
103+
104+
// Older versions of OSX (10.11 and 10.10 have been witnessed)
105+
// can return EPIPE when registering a pipe file descriptor
106+
// where the other end has already disappeared. For example code
107+
// that creates a pipe, closes a file descriptor, and then
108+
// registers the other end will see an EPIPE returned from
109+
// `register`.
110+
//
111+
// It also turns out that kevent will still report events on the
112+
// file descriptor, telling us that it's readable/hup at least
113+
// after we've done this registration. As a result we just
114+
// ignore `EPIPE` here instead of propagating it.
115+
//
116+
// More info can be found at carllerche/mio#582
117+
if change.data as i32 == libc::EPIPE &&
118+
change.filter == libc::EVFILT_WRITE {
119+
continue
104120
}
121+
122+
// ignore ENOENT error for EV_DELETE
123+
let orig_flags = if change.filter == libc::EVFILT_READ { r } else { w };
124+
if change.data as i32 == libc::ENOENT && orig_flags & libc::EV_DELETE != 0 {
125+
continue
126+
}
127+
128+
return Err(::std::io::Error::from_raw_os_error(change.data as i32));
105129
}
106130
Ok(())
107131
}

test/test_broken_pipe.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ pub fn broken_pipe() {
1919
let mut event_loop: EventLoop<BrokenPipeHandler> = EventLoop::new().unwrap();
2020
let (reader, _) = unix::pipe().unwrap();
2121

22-
// On Darwin this returns a "broken pipe" error.
23-
let _ = event_loop.register(&reader, Token(1), Ready::all(), PollOpt::edge());
22+
event_loop.register(&reader, Token(1), Ready::all(), PollOpt::edge())
23+
.unwrap();
2424

2525
let mut handler = BrokenPipeHandler;
2626
drop(reader);

0 commit comments

Comments
 (0)