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
7package runtime
8
9import _ "unsafe"
10
11const qsize = 64
12
13var sig struct {
14	q     noteQueue
15	inuse bool
16
17	lock     mutex
18	note     note
19	sleeping bool
20}
21
22type noteData struct {
23	s [_ERRMAX]byte
24	n int // n bytes of s are valid
25}
26
27type noteQueue struct {
28	lock mutex
29	data [qsize]noteData
30	ri   int
31	wi   int
32	full bool
33}
34
35// It is not allowed to allocate memory in the signal handler.
36func (q *noteQueue) push(item *byte) bool {
37	lock(&q.lock)
38	if q.full {
39		unlock(&q.lock)
40		return false
41	}
42	s := gostringnocopy(item)
43	copy(q.data[q.wi].s[:], s)
44	q.data[q.wi].n = len(s)
45	q.wi++
46	if q.wi == qsize {
47		q.wi = 0
48	}
49	if q.wi == q.ri {
50		q.full = true
51	}
52	unlock(&q.lock)
53	return true
54}
55
56func (q *noteQueue) pop() string {
57	lock(&q.lock)
58	q.full = false
59	if q.ri == q.wi {
60		unlock(&q.lock)
61		return ""
62	}
63	note := &q.data[q.ri]
64	item := string(note.s[:note.n])
65	q.ri++
66	if q.ri == qsize {
67		q.ri = 0
68	}
69	unlock(&q.lock)
70	return item
71}
72
73// Called from sighandler to send a signal back out of the signal handling thread.
74// Reports whether the signal was sent. If not, the caller typically crashes the program.
75func sendNote(s *byte) bool {
76	if !sig.inuse {
77		return false
78	}
79
80	// Add signal to outgoing queue.
81	if !sig.q.push(s) {
82		return false
83	}
84
85	lock(&sig.lock)
86	if sig.sleeping {
87		sig.sleeping = false
88		notewakeup(&sig.note)
89	}
90	unlock(&sig.lock)
91
92	return true
93}
94
95// Called to receive the next queued signal.
96// Must only be called from a single goroutine at a time.
97//
98//go:linkname signal_recv os/signal.signal_recv
99func signal_recv() string {
100	for {
101		note := sig.q.pop()
102		if note != "" {
103			return note
104		}
105
106		lock(&sig.lock)
107		sig.sleeping = true
108		noteclear(&sig.note)
109		unlock(&sig.lock)
110		notetsleepg(&sig.note, -1)
111	}
112}
113
114// signalWaitUntilIdle waits until the signal delivery mechanism is idle.
115// This is used to ensure that we do not drop a signal notification due
116// to a race between disabling a signal and receiving a signal.
117// This assumes that signal delivery has already been disabled for
118// the signal(s) in question, and here we are just waiting to make sure
119// that all the signals have been delivered to the user channels
120// by the os/signal package.
121//
122//go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle
123func signalWaitUntilIdle() {
124	for {
125		lock(&sig.lock)
126		sleeping := sig.sleeping
127		unlock(&sig.lock)
128		if sleeping {
129			return
130		}
131		Gosched()
132	}
133}
134
135// Must only be called from a single goroutine at a time.
136//
137//go:linkname signal_enable os/signal.signal_enable
138func signal_enable(s uint32) {
139	if !sig.inuse {
140		// This is the first call to signal_enable. Initialize.
141		sig.inuse = true // enable reception of signals; cannot disable
142		noteclear(&sig.note)
143	}
144}
145
146// Must only be called from a single goroutine at a time.
147//
148//go:linkname signal_disable os/signal.signal_disable
149func signal_disable(s uint32) {
150}
151
152// Must only be called from a single goroutine at a time.
153//
154//go:linkname signal_ignore os/signal.signal_ignore
155func signal_ignore(s uint32) {
156}
157
158//go:linkname signal_ignored os/signal.signal_ignored
159func signal_ignored(s uint32) bool {
160	return false
161}
162