Home | History | Annotate | Download | only in runtime
      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 // +build !plan9
     28 
     29 package runtime
     30 
     31 import (
     32 	"runtime/internal/atomic"
     33 	_ "unsafe" // for go:linkname
     34 )
     35 
     36 // sig handles communication between the signal handler and os/signal.
     37 // Other than the inuse and recv fields, the fields are accessed atomically.
     38 //
     39 // The wanted and ignored fields are only written by one goroutine at
     40 // a time; access is controlled by the handlers Mutex in os/signal.
     41 // The fields are only read by that one goroutine and by the signal handler.
     42 // We access them atomically to minimize the race between setting them
     43 // in the goroutine calling os/signal and the signal handler,
     44 // which may be running in a different thread. That race is unavoidable,
     45 // as there is no connection between handling a signal and receiving one,
     46 // but atomic instructions should minimize it.
     47 var sig struct {
     48 	note       note
     49 	mask       [(_NSIG + 31) / 32]uint32
     50 	wanted     [(_NSIG + 31) / 32]uint32
     51 	ignored    [(_NSIG + 31) / 32]uint32
     52 	recv       [(_NSIG + 31) / 32]uint32
     53 	state      uint32
     54 	delivering uint32
     55 	inuse      bool
     56 }
     57 
     58 const (
     59 	sigIdle = iota
     60 	sigReceiving
     61 	sigSending
     62 )
     63 
     64 // sigsend delivers a signal from sighandler to the internal signal delivery queue.
     65 // It reports whether the signal was sent. If not, the caller typically crashes the program.
     66 // It runs from the signal handler, so it's limited in what it can do.
     67 func sigsend(s uint32) bool {
     68 	bit := uint32(1) << uint(s&31)
     69 	if !sig.inuse || s >= uint32(32*len(sig.wanted)) {
     70 		return false
     71 	}
     72 
     73 	atomic.Xadd(&sig.delivering, 1)
     74 	// We are running in the signal handler; defer is not available.
     75 
     76 	if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 {
     77 		atomic.Xadd(&sig.delivering, -1)
     78 		return false
     79 	}
     80 
     81 	// Add signal to outgoing queue.
     82 	for {
     83 		mask := sig.mask[s/32]
     84 		if mask&bit != 0 {
     85 			atomic.Xadd(&sig.delivering, -1)
     86 			return true // signal already in queue
     87 		}
     88 		if atomic.Cas(&sig.mask[s/32], mask, mask|bit) {
     89 			break
     90 		}
     91 	}
     92 
     93 	// Notify receiver that queue has new bit.
     94 Send:
     95 	for {
     96 		switch atomic.Load(&sig.state) {
     97 		default:
     98 			throw("sigsend: inconsistent state")
     99 		case sigIdle:
    100 			if atomic.Cas(&sig.state, sigIdle, sigSending) {
    101 				break Send
    102 			}
    103 		case sigSending:
    104 			// notification already pending
    105 			break Send
    106 		case sigReceiving:
    107 			if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
    108 				notewakeup(&sig.note)
    109 				break Send
    110 			}
    111 		}
    112 	}
    113 
    114 	atomic.Xadd(&sig.delivering, -1)
    115 	return true
    116 }
    117 
    118 // Called to receive the next queued signal.
    119 // Must only be called from a single goroutine at a time.
    120 //go:linkname signal_recv os/signal.signal_recv
    121 func signal_recv() uint32 {
    122 	for {
    123 		// Serve any signals from local copy.
    124 		for i := uint32(0); i < _NSIG; i++ {
    125 			if sig.recv[i/32]&(1<<(i&31)) != 0 {
    126 				sig.recv[i/32] &^= 1 << (i & 31)
    127 				return i
    128 			}
    129 		}
    130 
    131 		// Wait for updates to be available from signal sender.
    132 	Receive:
    133 		for {
    134 			switch atomic.Load(&sig.state) {
    135 			default:
    136 				throw("signal_recv: inconsistent state")
    137 			case sigIdle:
    138 				if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
    139 					notetsleepg(&sig.note, -1)
    140 					noteclear(&sig.note)
    141 					break Receive
    142 				}
    143 			case sigSending:
    144 				if atomic.Cas(&sig.state, sigSending, sigIdle) {
    145 					break Receive
    146 				}
    147 			}
    148 		}
    149 
    150 		// Incorporate updates from sender into local copy.
    151 		for i := range sig.mask {
    152 			sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
    153 		}
    154 	}
    155 }
    156 
    157 // signalWaitUntilIdle waits until the signal delivery mechanism is idle.
    158 // This is used to ensure that we do not drop a signal notification due
    159 // to a race between disabling a signal and receiving a signal.
    160 // This assumes that signal delivery has already been disabled for
    161 // the signal(s) in question, and here we are just waiting to make sure
    162 // that all the signals have been delivered to the user channels
    163 // by the os/signal package.
    164 //go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle
    165 func signalWaitUntilIdle() {
    166 	// Although the signals we care about have been removed from
    167 	// sig.wanted, it is possible that another thread has received
    168 	// a signal, has read from sig.wanted, is now updating sig.mask,
    169 	// and has not yet woken up the processor thread. We need to wait
    170 	// until all current signal deliveries have completed.
    171 	for atomic.Load(&sig.delivering) != 0 {
    172 		Gosched()
    173 	}
    174 
    175 	// Although WaitUntilIdle seems like the right name for this
    176 	// function, the state we are looking for is sigReceiving, not
    177 	// sigIdle.  The sigIdle state is really more like sigProcessing.
    178 	for atomic.Load(&sig.state) != sigReceiving {
    179 		Gosched()
    180 	}
    181 }
    182 
    183 // Must only be called from a single goroutine at a time.
    184 //go:linkname signal_enable os/signal.signal_enable
    185 func signal_enable(s uint32) {
    186 	if !sig.inuse {
    187 		// The first call to signal_enable is for us
    188 		// to use for initialization. It does not pass
    189 		// signal information in m.
    190 		sig.inuse = true // enable reception of signals; cannot disable
    191 		noteclear(&sig.note)
    192 		return
    193 	}
    194 
    195 	if s >= uint32(len(sig.wanted)*32) {
    196 		return
    197 	}
    198 
    199 	w := sig.wanted[s/32]
    200 	w |= 1 << (s & 31)
    201 	atomic.Store(&sig.wanted[s/32], w)
    202 
    203 	i := sig.ignored[s/32]
    204 	i &^= 1 << (s & 31)
    205 	atomic.Store(&sig.ignored[s/32], i)
    206 
    207 	sigenable(s)
    208 }
    209 
    210 // Must only be called from a single goroutine at a time.
    211 //go:linkname signal_disable os/signal.signal_disable
    212 func signal_disable(s uint32) {
    213 	if s >= uint32(len(sig.wanted)*32) {
    214 		return
    215 	}
    216 	sigdisable(s)
    217 
    218 	w := sig.wanted[s/32]
    219 	w &^= 1 << (s & 31)
    220 	atomic.Store(&sig.wanted[s/32], w)
    221 }
    222 
    223 // Must only be called from a single goroutine at a time.
    224 //go:linkname signal_ignore os/signal.signal_ignore
    225 func signal_ignore(s uint32) {
    226 	if s >= uint32(len(sig.wanted)*32) {
    227 		return
    228 	}
    229 	sigignore(s)
    230 
    231 	w := sig.wanted[s/32]
    232 	w &^= 1 << (s & 31)
    233 	atomic.Store(&sig.wanted[s/32], w)
    234 
    235 	i := sig.ignored[s/32]
    236 	i |= 1 << (s & 31)
    237 	atomic.Store(&sig.ignored[s/32], i)
    238 }
    239 
    240 // Checked by signal handlers.
    241 func signal_ignored(s uint32) bool {
    242 	i := atomic.Load(&sig.ignored[s/32])
    243 	return i&(1<<(s&31)) != 0
    244 }
    245