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