diff options
author | Andy Pan <panjf2000@gmail.com> | 2020-03-27 03:21:17 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-03-27 17:14:16 +0000 |
commit | 0cc1290174751971d282196e21ec9037b217e5a5 (patch) | |
tree | b6d5698c1c4bc33df60d0259187d225326721cfd /src/runtime/netpoll_solaris.go | |
parent | e4a1cf8a5698d7351af0e33d61e4f7078f3ab1ce (diff) | |
download | go-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_solaris.go')
-rw-r--r-- | src/runtime/netpoll_solaris.go | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/src/runtime/netpoll_solaris.go b/src/runtime/netpoll_solaris.go index 15818cb4ea..34b3ee9308 100644 --- a/src/runtime/netpoll_solaris.go +++ b/src/runtime/netpoll_solaris.go @@ -4,7 +4,10 @@ package runtime -import "unsafe" +import ( + "runtime/internal/atomic" + "unsafe" +) // Solaris runtime-integrated network poller. // @@ -85,6 +88,7 @@ var ( libc_port_dissociate, libc_port_getn, libc_port_alert libcFunc + netpollWakeSig uintptr // used to avoid duplicate calls of netpollBreak ) func errno() int32 { @@ -187,15 +191,17 @@ func netpollarm(pd *pollDesc, mode int) { // netpollBreak interrupts a port_getn wait. func netpollBreak() { - // Use port_alert to put portfd into alert mode. - // This will wake up all threads sleeping in port_getn on portfd, - // and cause their calls to port_getn to return immediately. - // Further, until portfd is taken out of alert mode, - // all calls to port_getn will return immediately. - if port_alert(portfd, _PORT_ALERT_UPDATE, _POLLHUP, uintptr(unsafe.Pointer(&portfd))) < 0 { - if e := errno(); e != _EBUSY { - println("runtime: port_alert failed with", e) - throw("runtime: netpoll: port_alert failed") + if atomic.Casuintptr(&netpollWakeSig, 0, 1) { + // Use port_alert to put portfd into alert mode. + // This will wake up all threads sleeping in port_getn on portfd, + // and cause their calls to port_getn to return immediately. + // Further, until portfd is taken out of alert mode, + // all calls to port_getn will return immediately. + if port_alert(portfd, _PORT_ALERT_UPDATE, _POLLHUP, uintptr(unsafe.Pointer(&portfd))) < 0 { + if e := errno(); e != _EBUSY { + println("runtime: port_alert failed with", e) + throw("runtime: netpoll: port_alert failed") + } } } } @@ -268,6 +274,7 @@ retry: println("runtime: port_alert failed with", e) throw("runtime: netpoll: port_alert failed") } + atomic.Storeuintptr(&netpollWakeSig, 0) } continue } |