diff options
| author | Ian Lance Taylor <iant@golang.org> | 2017-10-19 16:01:43 -0700 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2017-10-20 22:26:30 +0000 |
| commit | 23aad448b1e3f7c3b4ba2af90120bde91ac865b4 (patch) | |
| tree | d0b60cd4e817998a50a07b9ce62b92954b110e69 /src/runtime/netpoll_kqueue.go | |
| parent | 4e64ee423c3a755ed31c3c98bfba98adc5995b4a (diff) | |
| download | go-23aad448b1e3f7c3b4ba2af90120bde91ac865b4.tar.xz | |
runtime: for kqueue treat EVFILT_READ with EV_EOF as permitting a write
On systems that use kqueue, we always register descriptors for both
EVFILT_READ and EVFILT_WRITE. On at least FreeBSD and OpenBSD, when
the write end of a pipe is registered for EVFILT_READ and EVFILT_WRITE
events, and the read end of the pipe is closed, kqueue reports an
EVFILT_READ event with EV_EOF set, but does not report an EVFILT_WRITE
event. Since the write to the pipe is waiting for an EVFILT_WRITE
event, closing the read end of a pipe can cause the write end to hang
rather than attempt another write which will fail with EPIPE.
Fix this by treating EVFILT_READ with EV_EOF set as making both reads
and writes ready to proceed.
The real test for this is in CL 71770, which tests using various
timeouts with pipes.
Updates #22114
Change-Id: Ib23fbaaddbccd8eee77bdf18f27a7f0aa50e2742
Reviewed-on: https://go-review.googlesource.com/71973
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/runtime/netpoll_kqueue.go')
| -rw-r--r-- | src/runtime/netpoll_kqueue.go | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go index 71de98bcd6..4d5d1a4ea8 100644 --- a/src/runtime/netpoll_kqueue.go +++ b/src/runtime/netpoll_kqueue.go @@ -88,10 +88,23 @@ retry: for i := 0; i < int(n); i++ { ev := &events[i] var mode int32 - if ev.filter == _EVFILT_READ { + switch ev.filter { + case _EVFILT_READ: mode += 'r' - } - if ev.filter == _EVFILT_WRITE { + + // On some systems when the read end of a pipe + // is closed the write end will not get a + // _EVFILT_WRITE event, but will get a + // _EVFILT_READ event with EV_EOF set. + // Note that setting 'w' here just means that we + // will wake up a goroutine waiting to write; + // that goroutine will try the write again, + // and the appropriate thing will happen based + // on what that write returns (success, EPIPE, EAGAIN). + if ev.flags&_EV_EOF != 0 { + mode += 'w' + } + case _EVFILT_WRITE: mode += 'w' } if mode != 0 { |
