aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2018-09-05 14:36:20 -0700
committerIan Lance Taylor <iant@golang.org>2018-09-07 18:58:38 +0000
commit57534891d446b8ef5e0ebf62c027beb7d6a55f67 (patch)
tree1804be89e92cecf36de89475bb56c3041bfff6a9
parentebf5d985d1a51440d19bd6ac6a43654179527fdc (diff)
downloadgo-57534891d446b8ef5e0ebf62c027beb7d6a55f67.tar.gz
go-57534891d446b8ef5e0ebf62c027beb7d6a55f67.zip
[release-branch.go1.11] runtime: in semasleep, subtract time spent so far from timeout
When pthread_cond_timedwait_relative_np gets a spurious wakeup (due to a signal, typically), we used to retry with the same relative timeout. That's incorrect, we should lower the timeout by the time we've spent in this function so far. In the worst case, signals come in and cause spurious wakeups faster than the timeout, causing semasleep to never time out. Also fix nacl and netbsd while we're here. They have similar issues. Fixes #27521 Change-Id: I6601e120e44a4b8ef436eef75a1e7c8cf1d39e39 Reviewed-on: https://go-review.googlesource.com/133655 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> (cherry picked from commit 2bf1370f4369d75f4fffffc6fc05722bce13481b) Reviewed-on: https://go-review.googlesource.com/134096
-rw-r--r--src/runtime/os_darwin.go11
-rw-r--r--src/runtime/os_nacl.go12
-rw-r--r--src/runtime/os_netbsd.go31
3 files changed, 30 insertions, 24 deletions
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index d2144edf2e..26b02820cd 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -34,6 +34,10 @@ func semacreate(mp *m) {
//go:nosplit
func semasleep(ns int64) int32 {
+ var start int64
+ if ns >= 0 {
+ start = nanotime()
+ }
mp := getg().m
pthread_mutex_lock(&mp.mutex)
for {
@@ -43,8 +47,13 @@ func semasleep(ns int64) int32 {
return 0
}
if ns >= 0 {
+ spent := nanotime() - start
+ if spent >= ns {
+ pthread_mutex_unlock(&mp.mutex)
+ return -1
+ }
var t timespec
- t.set_nsec(ns)
+ t.set_nsec(ns - spent)
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
if err == _ETIMEDOUT {
pthread_mutex_unlock(&mp.mutex)
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index 23ab03b953..ac7bf69582 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -197,23 +197,23 @@ func semacreate(mp *m) {
//go:nosplit
func semasleep(ns int64) int32 {
var ret int32
-
systemstack(func() {
_g_ := getg()
if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
throw("semasleep")
}
-
+ var ts timespec
+ if ns >= 0 {
+ end := ns + nanotime()
+ ts.tv_sec = end / 1e9
+ ts.tv_nsec = int32(end % 1e9)
+ }
for _g_.m.waitsemacount == 0 {
if ns < 0 {
if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
throw("semasleep")
}
} else {
- var ts timespec
- end := ns + nanotime()
- ts.tv_sec = end / 1e9
- ts.tv_nsec = int32(end % 1e9)
r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
if r == -_ETIMEDOUT {
nacl_mutex_unlock(_g_.m.waitsemalock)
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index a9bf407a36..7deab3ed03 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -126,15 +126,9 @@ func semacreate(mp *m) {
//go:nosplit
func semasleep(ns int64) int32 {
_g_ := getg()
-
- // Compute sleep deadline.
- var tsp *timespec
- var ts timespec
+ var deadline int64
if ns >= 0 {
- var nsec int32
- ts.set_sec(timediv(ns, 1000000000, &nsec))
- ts.set_nsec(nsec)
- tsp = &ts
+ deadline = nanotime() + ns
}
for {
@@ -147,18 +141,21 @@ func semasleep(ns int64) int32 {
}
// Sleep until unparked by semawakeup or timeout.
+ var tsp *timespec
+ var ts timespec
+ if ns >= 0 {
+ wait := deadline - nanotime()
+ if wait <= 0 {
+ return -1
+ }
+ var nsec int32
+ ts.set_sec(timediv(wait, 1000000000, &nsec))
+ ts.set_nsec(nsec)
+ tsp = &ts
+ }
ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
if ret == _ETIMEDOUT {
return -1
- } else if ret == _EINTR && ns >= 0 {
- // Avoid sleeping forever if we keep getting
- // interrupted (for example by the profiling
- // timer). It would be if tsp upon return had the
- // remaining time to sleep, but this is good enough.
- var nsec int32
- ns /= 2
- ts.set_sec(timediv(ns, 1000000000, &nsec))
- ts.set_nsec(nsec)
}
}
}