diff options
| author | Ian Lance Taylor <iant@golang.org> | 2017-11-22 19:12:12 -0800 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2017-11-30 23:29:30 +0000 |
| commit | eb97160f46cb18770ccb0bd57a08457c9ff20ccc (patch) | |
| tree | 2f7760872111605d145d8c0d67b3a54fe019aa54 /src/runtime/sigqueue.go | |
| parent | b23096b514e6290b1ff31183516378fe91e16251 (diff) | |
| download | go-eb97160f46cb18770ccb0bd57a08457c9ff20ccc.tar.xz | |
runtime: don't block signals that will kill the program
Otherwise we may delay the delivery of these signals for an arbitrary
length of time. We are already careful to not block signals that the
program has asked to see.
Also make sure that we don't miss a signal delivery if a thread
decides to stop for a while while executing the signal handler.
Also clean up the TestAtomicStop output a little bit.
Fixes #21433
Change-Id: Ic0c1a4eaf7eba80d1abc1e9537570bf4687c2434
Reviewed-on: https://go-review.googlesource.com/79581
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/sigqueue.go')
| -rw-r--r-- | src/runtime/sigqueue.go | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/src/runtime/sigqueue.go b/src/runtime/sigqueue.go index 236bb29929..94e2b69d92 100644 --- a/src/runtime/sigqueue.go +++ b/src/runtime/sigqueue.go @@ -45,13 +45,14 @@ import ( // as there is no connection between handling a signal and receiving one, // but atomic instructions should minimize it. var sig struct { - note note - mask [(_NSIG + 31) / 32]uint32 - wanted [(_NSIG + 31) / 32]uint32 - ignored [(_NSIG + 31) / 32]uint32 - recv [(_NSIG + 31) / 32]uint32 - state uint32 - inuse bool + note note + mask [(_NSIG + 31) / 32]uint32 + wanted [(_NSIG + 31) / 32]uint32 + ignored [(_NSIG + 31) / 32]uint32 + recv [(_NSIG + 31) / 32]uint32 + state uint32 + delivering uint32 + inuse bool } const ( @@ -68,7 +69,11 @@ func sigsend(s uint32) bool { return false } + atomic.Xadd(&sig.delivering, 1) + // We are running in the signal handler; defer is not available. + if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 { + atomic.Xadd(&sig.delivering, -1) return false } @@ -76,6 +81,7 @@ func sigsend(s uint32) bool { for { mask := sig.mask[s/32] if mask&bit != 0 { + atomic.Xadd(&sig.delivering, -1) return true // signal already in queue } if atomic.Cas(&sig.mask[s/32], mask, mask|bit) { @@ -104,6 +110,7 @@ Send: } } + atomic.Xadd(&sig.delivering, -1) return true } @@ -155,6 +162,15 @@ func signal_recv() uint32 { // by the os/signal package. //go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle func signalWaitUntilIdle() { + // Although the signals we care about have been removed from + // sig.wanted, it is possible that another thread has received + // a signal, has read from sig.wanted, is now updating sig.mask, + // and has not yet woken up the processor thread. We need to wait + // until all current signal deliveries have completed. + for atomic.Load(&sig.delivering) != 0 { + Gosched() + } + // Although WaitUntilIdle seems like the right name for this // function, the state we are looking for is sigReceiving, not // sigIdle. The sigIdle state is really more like sigProcessing. |
