aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/netpoll_kqueue.go
diff options
context:
space:
mode:
authorAndy Pan <panjf2000@gmail.com>2020-03-27 03:21:17 +0000
committerIan Lance Taylor <iant@golang.org>2020-03-27 17:14:16 +0000
commit0cc1290174751971d282196e21ec9037b217e5a5 (patch)
treeb6d5698c1c4bc33df60d0259187d225326721cfd /src/runtime/netpoll_kqueue.go
parente4a1cf8a5698d7351af0e33d61e4f7078f3ab1ce (diff)
downloadgo-0cc1290174751971d282196e21ec9037b217e5a5.tar.gz
go-0cc1290174751971d282196e21ec9037b217e5a5.zip
runtime: converge duplicate calls to netpollBreak into one
There might be some concurrent (maybe not concurrent, just sequential but in a short time window) and duplicate calls to `netpollBreak`, trying to wake up a net-poller. If one has called `netpollBreak` and that waking event hasn't been received by epollwait/kevent/..., then the subsequent calls of `netpollBreak` ought to be ignored or in other words, these calls should be converged into one. Benchmarks go1.13.5 darwin/amd64: benchmark-func time/op (old) time/op (new) delta BenchmarkNetpollBreak-4 29668ns ±1% 3131ns ±2% -89.45% mem/B (old) mem/B (new) delta 154B ±13% 0B ±0% -100% Change-Id: I3cf757a5d6edc5a99adad7aea3baee4b7f2a8f5c GitHub-Last-Rev: 15bcfbab8a5db51f65da01315a5880a5dbf9e028 GitHub-Pull-Request: golang/go#36294 Reviewed-on: https://go-review.googlesource.com/c/go/+/212737 Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/runtime/netpoll_kqueue.go')
-rw-r--r--src/runtime/netpoll_kqueue.go30
1 files changed, 19 insertions, 11 deletions
diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go
index 39d402252d..2ff21d8fcb 100644
--- a/src/runtime/netpoll_kqueue.go
+++ b/src/runtime/netpoll_kqueue.go
@@ -8,12 +8,17 @@ package runtime
// Integrated network poller (kqueue-based implementation).
-import "unsafe"
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
var (
kq int32 = -1
netpollBreakRd, netpollBreakWr uintptr // for netpollBreak
+
+ netpollWakeSig uintptr // used to avoid duplicate calls of netpollBreak
)
func netpollinit() {
@@ -78,17 +83,19 @@ func netpollarm(pd *pollDesc, mode int) {
// netpollBreak interrupts a kevent.
func netpollBreak() {
- for {
- var b byte
- n := write(netpollBreakWr, unsafe.Pointer(&b), 1)
- if n == 1 || n == -_EAGAIN {
- break
- }
- if n == -_EINTR {
- continue
+ if atomic.Casuintptr(&netpollWakeSig, 0, 1) {
+ for {
+ var b byte
+ n := write(netpollBreakWr, unsafe.Pointer(&b), 1)
+ if n == 1 || n == -_EAGAIN {
+ break
+ }
+ if n == -_EINTR {
+ continue
+ }
+ println("runtime: netpollBreak write failed with", -n)
+ throw("runtime: netpollBreak write failed")
}
- println("runtime: netpollBreak write failed with", -n)
- throw("runtime: netpollBreak write failed")
}
}
@@ -145,6 +152,7 @@ retry:
// if blocking.
var tmp [16]byte
read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp)))
+ atomic.Storeuintptr(&netpollWakeSig, 0)
}
continue
}