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: 0, HASWAITER and HASSIGNAL.
16// HASWAITER means that signal_recv() is blocked on sig.Note and there are no
17// new pending signals.
18// HASSIGNAL means that sig.mask *may* contain new pending signals,
19// signal_recv() can't be blocked in this state.
20// 0 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 sigsend()'s and signal_recv() execute concurrently, it can lead to
24// unnecessary rechecks of sig.mask, but must not lead to missed signals
25// nor deadlocks.
26
27package signal
28#include "config.h"
29#include "runtime.h"
30#include "arch.h"
31#include "malloc.h"
32#include "defs.h"
33
34static struct {
35	Note;
36	uint32 mask[(NSIG+31)/32];
37	uint32 wanted[(NSIG+31)/32];
38	uint32 state;
39	bool inuse;
40} sig;
41
42enum {
43	HASWAITER = 1,
44	HASSIGNAL = 2,
45};
46
47// Called from sighandler to send a signal back out of the signal handling thread.
48bool
49__go_sigsend(int32 s)
50{
51	uint32 bit, mask, old, new;
52
53	if(!sig.inuse || s < 0 || (size_t)s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31))))
54		return false;
55	bit = 1 << (s&31);
56	for(;;) {
57		mask = sig.mask[s/32];
58		if(mask & bit)
59			break;		// signal already in queue
60		if(runtime_cas(&sig.mask[s/32], mask, mask|bit)) {
61			// Added to queue.
62			// Only send a wakeup if the receiver needs a kick.
63			for(;;) {
64				old = runtime_atomicload(&sig.state);
65				if(old == HASSIGNAL)
66					break;
67				if(old == HASWAITER)
68					new = 0;
69				else  // if(old == 0)
70					new = HASSIGNAL;
71				if(runtime_cas(&sig.state, old, new)) {
72					if (old == HASWAITER)
73						runtime_notewakeup(&sig);
74					break;
75				}
76			}
77			break;
78		}
79	}
80	return true;
81}
82
83// Called to receive the next queued signal.
84// Must only be called from a single goroutine at a time.
85func signal_recv() (m uint32) {
86	static uint32 recv[nelem(sig.mask)];
87	uint32 i, old, new;
88
89	for(;;) {
90		// Serve from local copy if there are bits left.
91		for(i=0; i<NSIG; i++) {
92			if(recv[i/32]&(1U<<(i&31))) {
93				recv[i/32] ^= 1U<<(i&31);
94				m = i;
95				goto done;
96			}
97		}
98
99		// Check and update sig.state.
100		for(;;) {
101			old = runtime_atomicload(&sig.state);
102			if(old == HASWAITER)
103				runtime_throw("inconsistent state in signal_recv");
104			if(old == HASSIGNAL)
105				new = 0;
106			else  // if(old == 0)
107				new = HASWAITER;
108			if(runtime_cas(&sig.state, old, new)) {
109				if (new == HASWAITER) {
110					runtime_notetsleepg(&sig, -1);
111					runtime_noteclear(&sig);
112				}
113				break;
114			}
115		}
116
117		// Get a new local copy.
118		for(i=0; (size_t)i<nelem(sig.mask); i++) {
119			for(;;) {
120				m = sig.mask[i];
121				if(runtime_cas(&sig.mask[i], m, 0))
122					break;
123			}
124			recv[i] = m;
125		}
126	}
127
128done:;
129	// goc requires that we fall off the end of functions
130	// that return values instead of using our own return
131	// statements.
132}
133
134// Must only be called from a single goroutine at a time.
135func signal_enable(s uint32) {
136	if(!sig.inuse) {
137		// The first call to signal_enable is for us
138		// to use for initialization.  It does not pass
139		// signal information in m.
140		sig.inuse = true;	// enable reception of signals; cannot disable
141		runtime_noteclear(&sig);
142		return;
143	}
144
145	if(s >= nelem(sig.wanted)*32)
146		return;
147	sig.wanted[s/32] |= 1U<<(s&31);
148	runtime_sigenable(s);
149}
150
151// Must only be called from a single goroutine at a time.
152func signal_disable(s uint32) {
153	if(s >= nelem(sig.wanted)*32)
154		return;
155	sig.wanted[s/32] &= ~(1U<<(s&31));
156	runtime_sigdisable(s);
157}
158
159// Must only be called from a single goroutine at a time.
160func signal_ignore(s uint32) {
161	if (s >= nelem(sig.wanted)*32)
162		return;
163	sig.wanted[s/32] &= ~(1U<<(s&31));
164	runtime_sigignore(s);
165}
166
167// This runs on a foreign stack, without an m or a g.  No stack split.
168void
169runtime_badsignal(int sig)
170{
171	__go_sigsend(sig);
172}
173