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
29package runtime
30
31import (
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.
47var 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
58const (
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.
67func 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.
94Send:
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				if GOOS == "darwin" {
109					sigNoteWakeup(&sig.note)
110					break Send
111				}
112				notewakeup(&sig.note)
113				break Send
114			}
115		}
116	}
117
118	atomic.Xadd(&sig.delivering, -1)
119	return true
120}
121
122// Called to receive the next queued signal.
123// Must only be called from a single goroutine at a time.
124//go:linkname signal_recv os..z2fsignal.signal_recv
125func signal_recv() uint32 {
126	for {
127		// Serve any signals from local copy.
128		for i := uint32(0); i < _NSIG; i++ {
129			if sig.recv[i/32]&(1<<(i&31)) != 0 {
130				sig.recv[i/32] &^= 1 << (i & 31)
131				return i
132			}
133		}
134
135		// Wait for updates to be available from signal sender.
136	Receive:
137		for {
138			switch atomic.Load(&sig.state) {
139			default:
140				throw("signal_recv: inconsistent state")
141			case sigIdle:
142				if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
143					if GOOS == "darwin" {
144						sigNoteSleep(&sig.note)
145						break Receive
146					}
147					notetsleepg(&sig.note, -1)
148					noteclear(&sig.note)
149					break Receive
150				}
151			case sigSending:
152				if atomic.Cas(&sig.state, sigSending, sigIdle) {
153					break Receive
154				}
155			}
156		}
157
158		// Incorporate updates from sender into local copy.
159		for i := range sig.mask {
160			sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
161		}
162	}
163}
164
165// signalWaitUntilIdle waits until the signal delivery mechanism is idle.
166// This is used to ensure that we do not drop a signal notification due
167// to a race between disabling a signal and receiving a signal.
168// This assumes that signal delivery has already been disabled for
169// the signal(s) in question, and here we are just waiting to make sure
170// that all the signals have been delivered to the user channels
171// by the os/signal package.
172//go:linkname signalWaitUntilIdle os..z2fsignal.signalWaitUntilIdle
173func signalWaitUntilIdle() {
174	// Although the signals we care about have been removed from
175	// sig.wanted, it is possible that another thread has received
176	// a signal, has read from sig.wanted, is now updating sig.mask,
177	// and has not yet woken up the processor thread. We need to wait
178	// until all current signal deliveries have completed.
179	for atomic.Load(&sig.delivering) != 0 {
180		Gosched()
181	}
182
183	// Although WaitUntilIdle seems like the right name for this
184	// function, the state we are looking for is sigReceiving, not
185	// sigIdle.  The sigIdle state is really more like sigProcessing.
186	for atomic.Load(&sig.state) != sigReceiving {
187		Gosched()
188	}
189}
190
191// Must only be called from a single goroutine at a time.
192//go:linkname signal_enable os..z2fsignal.signal_enable
193func signal_enable(s uint32) {
194	if !sig.inuse {
195		// The first call to signal_enable is for us
196		// to use for initialization. It does not pass
197		// signal information in m.
198		sig.inuse = true // enable reception of signals; cannot disable
199		if GOOS == "darwin" {
200			sigNoteSetup(&sig.note)
201			return
202		}
203		noteclear(&sig.note)
204		return
205	}
206
207	if s >= uint32(len(sig.wanted)*32) {
208		return
209	}
210
211	w := sig.wanted[s/32]
212	w |= 1 << (s & 31)
213	atomic.Store(&sig.wanted[s/32], w)
214
215	i := sig.ignored[s/32]
216	i &^= 1 << (s & 31)
217	atomic.Store(&sig.ignored[s/32], i)
218
219	sigenable(s)
220}
221
222// Must only be called from a single goroutine at a time.
223//go:linkname signal_disable os..z2fsignal.signal_disable
224func signal_disable(s uint32) {
225	if s >= uint32(len(sig.wanted)*32) {
226		return
227	}
228	sigdisable(s)
229
230	w := sig.wanted[s/32]
231	w &^= 1 << (s & 31)
232	atomic.Store(&sig.wanted[s/32], w)
233}
234
235// Must only be called from a single goroutine at a time.
236//go:linkname signal_ignore os..z2fsignal.signal_ignore
237func signal_ignore(s uint32) {
238	if s >= uint32(len(sig.wanted)*32) {
239		return
240	}
241	sigignore(s)
242
243	w := sig.wanted[s/32]
244	w &^= 1 << (s & 31)
245	atomic.Store(&sig.wanted[s/32], w)
246
247	i := sig.ignored[s/32]
248	i |= 1 << (s & 31)
249	atomic.Store(&sig.ignored[s/32], i)
250}
251
252// sigInitIgnored marks the signal as already ignored. This is called at
253// program start by initsig. In a shared library initsig is called by
254// libpreinit, so the runtime may not be initialized yet.
255//go:nosplit
256func sigInitIgnored(s uint32) {
257	i := sig.ignored[s/32]
258	i |= 1 << (s & 31)
259	atomic.Store(&sig.ignored[s/32], i)
260}
261
262// Checked by signal handlers.
263//go:linkname signal_ignored os..z2fsignal.signal_ignored
264func signal_ignored(s uint32) bool {
265	i := atomic.Load(&sig.ignored[s/32])
266	return i&(1<<(s&31)) != 0
267}
268