Skip to content

Commit 42257a2

Browse files
committed
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 #27520 Change-Id: I6601e120e44a4b8ef436eef75a1e7c8cf1d39e39 Reviewed-on: https://go-review.googlesource.com/133655 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 204cc14 commit 42257a2

File tree

3 files changed

+30
-24
lines changed

3 files changed

+30
-24
lines changed

src/runtime/os_darwin.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ func semacreate(mp *m) {
3434

3535
//go:nosplit
3636
func semasleep(ns int64) int32 {
37+
var start int64
38+
if ns >= 0 {
39+
start = nanotime()
40+
}
3741
mp := getg().m
3842
pthread_mutex_lock(&mp.mutex)
3943
for {
@@ -43,8 +47,13 @@ func semasleep(ns int64) int32 {
4347
return 0
4448
}
4549
if ns >= 0 {
50+
spent := nanotime() - start
51+
if spent >= ns {
52+
pthread_mutex_unlock(&mp.mutex)
53+
return -1
54+
}
4655
var t timespec
47-
t.set_nsec(ns)
56+
t.set_nsec(ns - spent)
4857
err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
4958
if err == _ETIMEDOUT {
5059
pthread_mutex_unlock(&mp.mutex)

src/runtime/os_nacl.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,23 +197,23 @@ func semacreate(mp *m) {
197197
//go:nosplit
198198
func semasleep(ns int64) int32 {
199199
var ret int32
200-
201200
systemstack(func() {
202201
_g_ := getg()
203202
if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
204203
throw("semasleep")
205204
}
206-
205+
var ts timespec
206+
if ns >= 0 {
207+
end := ns + nanotime()
208+
ts.tv_sec = end / 1e9
209+
ts.tv_nsec = int32(end % 1e9)
210+
}
207211
for _g_.m.waitsemacount == 0 {
208212
if ns < 0 {
209213
if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
210214
throw("semasleep")
211215
}
212216
} else {
213-
var ts timespec
214-
end := ns + nanotime()
215-
ts.tv_sec = end / 1e9
216-
ts.tv_nsec = int32(end % 1e9)
217217
r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
218218
if r == -_ETIMEDOUT {
219219
nacl_mutex_unlock(_g_.m.waitsemalock)

src/runtime/os_netbsd.go

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,9 @@ func semacreate(mp *m) {
126126
//go:nosplit
127127
func semasleep(ns int64) int32 {
128128
_g_ := getg()
129-
130-
// Compute sleep deadline.
131-
var tsp *timespec
132-
var ts timespec
129+
var deadline int64
133130
if ns >= 0 {
134-
var nsec int32
135-
ts.set_sec(timediv(ns, 1000000000, &nsec))
136-
ts.set_nsec(nsec)
137-
tsp = &ts
131+
deadline = nanotime() + ns
138132
}
139133

140134
for {
@@ -147,18 +141,21 @@ func semasleep(ns int64) int32 {
147141
}
148142

149143
// Sleep until unparked by semawakeup or timeout.
144+
var tsp *timespec
145+
var ts timespec
146+
if ns >= 0 {
147+
wait := deadline - nanotime()
148+
if wait <= 0 {
149+
return -1
150+
}
151+
var nsec int32
152+
ts.set_sec(timediv(wait, 1000000000, &nsec))
153+
ts.set_nsec(nsec)
154+
tsp = &ts
155+
}
150156
ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
151157
if ret == _ETIMEDOUT {
152158
return -1
153-
} else if ret == _EINTR && ns >= 0 {
154-
// Avoid sleeping forever if we keep getting
155-
// interrupted (for example by the profiling
156-
// timer). It would be if tsp upon return had the
157-
// remaining time to sleep, but this is good enough.
158-
var nsec int32
159-
ns /= 2
160-
ts.set_sec(timediv(ns, 1000000000, &nsec))
161-
ts.set_nsec(nsec)
162159
}
163160
}
164161
}

0 commit comments

Comments
 (0)