github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/runtime/sigqueue.go (about) 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. 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 // 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 17 // new pending signals. 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. 21 // Transitions between states are done atomically with CAS. 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 25 // nor deadlocks. 26 27 package runtime 28 29 import "unsafe" 30 31 var sig struct { 32 note note 33 mask [(_NSIG + 31) / 32]uint32 34 wanted [(_NSIG + 31) / 32]uint32 35 recv [(_NSIG + 31) / 32]uint32 36 state uint32 37 inuse bool 38 } 39 40 const ( 41 sigIdle = iota 42 sigReceiving 43 sigSending 44 ) 45 46 // Called from sighandler to send a signal back out of the signal handling thread. 47 // Reports whether the signal was sent. If not, the caller typically crashes the program. 48 func sigsend(s uint32) bool { 49 bit := uint32(1) << uint(s&31) 50 if !sig.inuse || s < 0 || int(s) >= 32*len(sig.wanted) || sig.wanted[s/32]&bit == 0 { 51 return false 52 } 53 54 // Add signal to outgoing queue. 55 for { 56 mask := sig.mask[s/32] 57 if mask&bit != 0 { 58 return true // signal already in queue 59 } 60 if cas(&sig.mask[s/32], mask, mask|bit) { 61 break 62 } 63 } 64 65 // Notify receiver that queue has new bit. 66 Send: 67 for { 68 switch atomicload(&sig.state) { 69 default: 70 gothrow("sigsend: inconsistent state") 71 case sigIdle: 72 if cas(&sig.state, sigIdle, sigSending) { 73 break Send 74 } 75 case sigSending: 76 // notification already pending 77 break Send 78 case sigReceiving: 79 if cas(&sig.state, sigReceiving, sigIdle) { 80 notewakeup(&sig.note) 81 break Send 82 } 83 } 84 } 85 86 return true 87 } 88 89 // Called to receive the next queued signal. 90 // Must only be called from a single goroutine at a time. 91 func signal_recv() uint32 { 92 for { 93 // Serve any signals from local copy. 94 for i := uint32(0); i < _NSIG; i++ { 95 if sig.recv[i/32]&(1<<(i&31)) != 0 { 96 sig.recv[i/32] &^= 1 << (i & 31) 97 return i 98 } 99 } 100 101 // Wait for updates to be available from signal sender. 102 Receive: 103 for { 104 switch atomicload(&sig.state) { 105 default: 106 gothrow("signal_recv: inconsistent state") 107 case sigIdle: 108 if cas(&sig.state, sigIdle, sigReceiving) { 109 notetsleepg(&sig.note, -1) 110 noteclear(&sig.note) 111 break Receive 112 } 113 case sigSending: 114 if cas(&sig.state, sigSending, sigIdle) { 115 break Receive 116 } 117 } 118 } 119 120 // Incorporate updates from sender into local copy. 121 for i := range sig.mask { 122 sig.recv[i] = xchg(&sig.mask[i], 0) 123 } 124 } 125 } 126 127 // Must only be called from a single goroutine at a time. 128 func signal_enable(s uint32) { 129 if !sig.inuse { 130 // The first call to signal_enable is for us 131 // to use for initialization. It does not pass 132 // signal information in m. 133 sig.inuse = true // enable reception of signals; cannot disable 134 noteclear(&sig.note) 135 return 136 } 137 138 if int(s) >= len(sig.wanted)*32 { 139 return 140 } 141 sig.wanted[s/32] |= 1 << (s & 31) 142 sigenable(s) 143 } 144 145 // Must only be called from a single goroutine at a time. 146 func signal_disable(s uint32) { 147 if int(s) >= len(sig.wanted)*32 { 148 return 149 } 150 sig.wanted[s/32] &^= 1 << (s & 31) 151 sigdisable(s) 152 } 153 154 // This runs on a foreign stack, without an m or a g. No stack split. 155 //go:nosplit 156 func badsignal(sig uintptr) { 157 cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) 158 }