Skip to content

Commit fa21ad5

Browse files
committed
runtime: wake every waiter when stopping the signal watcher
The watcher is not the only thing that sleeps on signalFutex. sleepTicks waits on it, and so does waitForEvents. Waking a single waiter could therefore wake a sleeping goroutine instead of the watcher: that goroutine consumes the value with its own Swap, and the watcher is left asleep on a futex that is 0 again, never seeing the stop flag it was told to look at — which is the thread leak this function exists to prevent. WakeAll is what the signal handler already uses on this futex a few lines below, for the same reason.
1 parent e626202 commit fa21ad5

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

src/runtime/runtime_unix.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,8 +457,15 @@ func stopSignalWatcher(s uint32) {
457457
// Wake it so it can observe the flag. The value bump matters as much as the
458458
// wake: Wait(0) returns immediately if the futex is already non-zero, which
459459
// closes the window between the store above and a watcher about to sleep.
460+
//
461+
// WakeAll rather than Wake because the watcher is not the only thing that
462+
// sleeps on this futex: sleepTicks waits on it too, and so does
463+
// waitForEvents. Waking one waiter could wake a sleeping goroutine instead
464+
// — which would consume the value with its own Swap and leave the watcher
465+
// asleep on a futex that is 0 again, never seeing the flag it was told to
466+
// look at. The signal handler wakes this futex the same way.
460467
signalFutex.Store(1)
461-
signalFutex.Wake()
468+
signalFutex.WakeAll()
462469
}
463470

464471
// signalWatcher runs on its own thread under the threads scheduler. It blocks on

0 commit comments

Comments
 (0)