]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.11] runtime: in semasleep, subtract time spent so far from timeout
authorKeith Randall <khr@golang.org>
Wed, 5 Sep 2018 21:36:20 +0000 (14:36 -0700)
committerIan Lance Taylor <iant@golang.org>
Fri, 7 Sep 2018 18:58:38 +0000 (18:58 +0000)
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

src/runtime/os_darwin.go
src/runtime/os_nacl.go
src/runtime/os_netbsd.go

index d2144edf2ebdf48debc4c1dfc18693169e181ff1..26b02820cd32c12b70d7ecc94aff59b7e75bc977 100644 (file)
@@ -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)
index 23ab03b953e961bf62dc4f8a16d9d8704510c5fc..ac7bf69582533edaf7c6ce156c51a5bc1054dc47 100644 (file)
@@ -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)
index a9bf407a363882a46685f7362e5e28eff7357324..7deab3ed03569c134cf7c195e0e72f5b18fd5f86 100644 (file)
@@ -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)
                }
        }
 }