Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 1 | // Copyright 2009 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | // This file implements runtime support for signal handling. |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 6 | // |
| 7 | // Most synchronization primitives are not available from |
| 8 | // the signal handler (it cannot block, allocate memory, or use locks) |
| 9 | // so the handler communicates with a processing goroutine |
| 10 | // via struct sig, below. |
| 11 | // |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 12 | // sigsend is called by the signal handler to queue a new signal. |
| 13 | // signal_recv is called by the Go program to receive a newly queued signal. |
| 14 | // Synchronization between sigsend and signal_recv is based on the sig.state |
| 15 | // variable. It can be in 3 states: sigIdle, sigReceiving and sigSending. |
| 16 | // sigReceiving means that signal_recv is blocked on sig.Note and there are no |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 17 | // new pending signals. |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 18 | // sigSending means that sig.mask *may* contain new pending signals, |
| 19 | // signal_recv can't be blocked in this state. |
| 20 | // sigIdle means that there are no new pending signals and signal_recv is not blocked. |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 21 | // Transitions between states are done atomically with CAS. |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 22 | // When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask. |
| 23 | // If several sigsends and signal_recv execute concurrently, it can lead to |
| 24 | // unnecessary rechecks of sig.mask, but it cannot lead to missed signals |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 25 | // nor deadlocks. |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 26 | |
David du Colombier | d5d4ab7 | 2015-01-22 23:38:29 +0100 | [diff] [blame] | 27 | // +build !plan9 |
| 28 | |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 29 | package runtime |
| 30 | |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 31 | import "unsafe" |
| 32 | |
| 33 | var sig struct { |
| 34 | note note |
| 35 | mask [(_NSIG + 31) / 32]uint32 |
| 36 | wanted [(_NSIG + 31) / 32]uint32 |
| 37 | recv [(_NSIG + 31) / 32]uint32 |
| 38 | state uint32 |
| 39 | inuse bool |
| 40 | } |
| 41 | |
| 42 | const ( |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 43 | sigIdle = iota |
| 44 | sigReceiving |
| 45 | sigSending |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 46 | ) |
| 47 | |
| 48 | // Called from sighandler to send a signal back out of the signal handling thread. |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 49 | // Reports whether the signal was sent. If not, the caller typically crashes the program. |
Russ Cox | 2d917c0 | 2014-11-11 17:05:55 -0500 | [diff] [blame] | 50 | func sigsend(s uint32) bool { |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 51 | bit := uint32(1) << uint(s&31) |
Todd Neal | a94e906 | 2015-08-25 18:25:42 -0500 | [diff] [blame] | 52 | if !sig.inuse || s >= uint32(32*len(sig.wanted)) || sig.wanted[s/32]&bit == 0 { |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 53 | return false |
| 54 | } |
| 55 | |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 56 | // Add signal to outgoing queue. |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 57 | for { |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 58 | mask := sig.mask[s/32] |
| 59 | if mask&bit != 0 { |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 60 | return true // signal already in queue |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 61 | } |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 62 | if cas(&sig.mask[s/32], mask, mask|bit) { |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 63 | break |
| 64 | } |
| 65 | } |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 66 | |
| 67 | // Notify receiver that queue has new bit. |
| 68 | Send: |
| 69 | for { |
| 70 | switch atomicload(&sig.state) { |
| 71 | default: |
Keith Randall | b2a950b | 2014-12-27 20:58:00 -0800 | [diff] [blame] | 72 | throw("sigsend: inconsistent state") |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 73 | case sigIdle: |
| 74 | if cas(&sig.state, sigIdle, sigSending) { |
| 75 | break Send |
| 76 | } |
| 77 | case sigSending: |
| 78 | // notification already pending |
| 79 | break Send |
| 80 | case sigReceiving: |
| 81 | if cas(&sig.state, sigReceiving, sigIdle) { |
| 82 | notewakeup(&sig.note) |
| 83 | break Send |
| 84 | } |
| 85 | } |
| 86 | } |
| 87 | |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 88 | return true |
| 89 | } |
| 90 | |
| 91 | // Called to receive the next queued signal. |
| 92 | // Must only be called from a single goroutine at a time. |
| 93 | func signal_recv() uint32 { |
| 94 | for { |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 95 | // Serve any signals from local copy. |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 96 | for i := uint32(0); i < _NSIG; i++ { |
| 97 | if sig.recv[i/32]&(1<<(i&31)) != 0 { |
| 98 | sig.recv[i/32] &^= 1 << (i & 31) |
| 99 | return i |
| 100 | } |
| 101 | } |
| 102 | |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 103 | // Wait for updates to be available from signal sender. |
| 104 | Receive: |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 105 | for { |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 106 | switch atomicload(&sig.state) { |
| 107 | default: |
Keith Randall | b2a950b | 2014-12-27 20:58:00 -0800 | [diff] [blame] | 108 | throw("signal_recv: inconsistent state") |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 109 | case sigIdle: |
| 110 | if cas(&sig.state, sigIdle, sigReceiving) { |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 111 | notetsleepg(&sig.note, -1) |
| 112 | noteclear(&sig.note) |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 113 | break Receive |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 114 | } |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 115 | case sigSending: |
| 116 | if cas(&sig.state, sigSending, sigIdle) { |
| 117 | break Receive |
| 118 | } |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 119 | } |
| 120 | } |
| 121 | |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 122 | // Incorporate updates from sender into local copy. |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 123 | for i := range sig.mask { |
Russ Cox | f93e21a | 2014-09-05 14:38:29 -0400 | [diff] [blame] | 124 | sig.recv[i] = xchg(&sig.mask[i], 0) |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 125 | } |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 126 | } |
| 127 | } |
| 128 | |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 129 | // Must only be called from a single goroutine at a time. |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 130 | func signal_enable(s uint32) { |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 131 | if !sig.inuse { |
| 132 | // The first call to signal_enable is for us |
| 133 | // to use for initialization. It does not pass |
| 134 | // signal information in m. |
| 135 | sig.inuse = true // enable reception of signals; cannot disable |
| 136 | noteclear(&sig.note) |
| 137 | return |
| 138 | } |
| 139 | |
Todd Neal | a94e906 | 2015-08-25 18:25:42 -0500 | [diff] [blame] | 140 | if s >= uint32(len(sig.wanted)*32) { |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 141 | return |
| 142 | } |
| 143 | sig.wanted[s/32] |= 1 << (s & 31) |
Russ Cox | 656be31 | 2014-11-12 14:54:31 -0500 | [diff] [blame] | 144 | sigenable(s) |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 145 | } |
| 146 | |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 147 | // Must only be called from a single goroutine at a time. |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 148 | func signal_disable(s uint32) { |
Todd Neal | a94e906 | 2015-08-25 18:25:42 -0500 | [diff] [blame] | 149 | if s >= uint32(len(sig.wanted)*32) { |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 150 | return |
| 151 | } |
| 152 | sig.wanted[s/32] &^= 1 << (s & 31) |
Russ Cox | 656be31 | 2014-11-12 14:54:31 -0500 | [diff] [blame] | 153 | sigdisable(s) |
Dmitriy Vyukov | 651d0cf | 2014-08-24 11:50:37 +0400 | [diff] [blame] | 154 | } |
| 155 | |
Michael MacInnis | 194ad16 | 2015-01-29 22:37:41 -0500 | [diff] [blame] | 156 | // Must only be called from a single goroutine at a time. |
| 157 | func signal_ignore(s uint32) { |
Todd Neal | a94e906 | 2015-08-25 18:25:42 -0500 | [diff] [blame] | 158 | if s >= uint32(len(sig.wanted)*32) { |
Michael MacInnis | 194ad16 | 2015-01-29 22:37:41 -0500 | [diff] [blame] | 159 | return |
| 160 | } |
| 161 | sig.wanted[s/32] &^= 1 << (s & 31) |
| 162 | sigignore(s) |
| 163 | } |
| 164 | |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 165 | // This runs on a foreign stack, without an m or a g. No stack split. |
| 166 | //go:nosplit |
Russ Cox | 75d7795 | 2015-07-22 15:31:54 -0400 | [diff] [blame] | 167 | //go:norace |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 168 | func badsignal(sig uintptr) { |
Ian Lance Taylor | 872b168 | 2015-07-21 22:34:48 -0700 | [diff] [blame] | 169 | cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) |
| 170 | } |
| 171 | |
| 172 | func badsignalgo(sig uintptr) { |
| 173 | if !sigsend(uint32(sig)) { |
| 174 | // A foreign thread received the signal sig, and the |
| 175 | // Go code does not want to handle it. |
| 176 | raisebadsignal(int32(sig)) |
| 177 | } |
Russ Cox | 81ed684 | 2014-09-04 13:51:12 -0400 | [diff] [blame] | 178 | } |