]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/go/runtime/sigqueue.go
libgo: Upgrade to Go 1.4.2 release.
[thirdparty/gcc.git] / libgo / go / runtime / sigqueue.go
CommitLineData
f8d9fa9e
ILT
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
27package runtime
28
29import "unsafe"
30
31var sig struct {
32 note note
33 mask [(_NSIG + 31) / 32]uint32
34 wanted [(_NSIG + 31) / 32]uint32
35 recv [(_NSIG + 31) / 32]uint32
36 state uint32
37 inuse bool
38}
39
40const (
41 sigIdle = iota
42 sigReceiving
43 sigSending
44)
45
46// Called from sighandler to send a signal back out of the signal handling thread.
47// Reports whether the signal was sent. If not, the caller typically crashes the program.
48func sigsend(s int32) bool {
49 bit := uint32(1) << uint(s&31)
50 if !sig.inuse || s < 0 || int(s) >= 32*len(sig.wanted) || sig.wanted[s/32]&bit == 0 {
51 return false
52 }
53
54 // Add signal to outgoing queue.
55 for {
56 mask := sig.mask[s/32]
57 if mask&bit != 0 {
58 return true // signal already in queue
59 }
60 if cas(&sig.mask[s/32], mask, mask|bit) {
61 break
62 }
63 }
64
65 // Notify receiver that queue has new bit.
66Send:
67 for {
68 switch atomicload(&sig.state) {
69 default:
70 gothrow("sigsend: inconsistent state")
71 case sigIdle:
72 if cas(&sig.state, sigIdle, sigSending) {
73 break Send
74 }
75 case sigSending:
76 // notification already pending
77 break Send
78 case sigReceiving:
79 if cas(&sig.state, sigReceiving, sigIdle) {
80 notewakeup(&sig.note)
81 break Send
82 }
83 }
84 }
85
86 return true
87}
88
89// Called to receive the next queued signal.
90// Must only be called from a single goroutine at a time.
91func signal_recv() uint32 {
92 for {
93 // Serve any signals from local copy.
94 for i := uint32(0); i < _NSIG; i++ {
95 if sig.recv[i/32]&(1<<(i&31)) != 0 {
96 sig.recv[i/32] &^= 1 << (i & 31)
97 return i
98 }
99 }
100
101 // Wait for updates to be available from signal sender.
102 Receive:
103 for {
104 switch atomicload(&sig.state) {
105 default:
106 gothrow("signal_recv: inconsistent state")
107 case sigIdle:
108 if cas(&sig.state, sigIdle, sigReceiving) {
109 notetsleepg(&sig.note, -1)
110 noteclear(&sig.note)
111 break Receive
112 }
113 case sigSending:
114 if cas(&sig.state, sigSending, sigIdle) {
115 break Receive
116 }
117 }
118 }
119
120 // Incorporate updates from sender into local copy.
121 for i := range sig.mask {
122 sig.recv[i] = xchg(&sig.mask[i], 0)
123 }
124 }
125}
126
127// Must only be called from a single goroutine at a time.
128func signal_enable(s uint32) {
129 if !sig.inuse {
130 // The first call to signal_enable is for us
131 // to use for initialization. It does not pass
132 // signal information in m.
133 sig.inuse = true // enable reception of signals; cannot disable
134 noteclear(&sig.note)
135 return
136 }
137
138 if int(s) >= len(sig.wanted)*32 {
139 return
140 }
141 sig.wanted[s/32] |= 1 << (s & 31)
142 sigenable_go(s)
143}
144
145// Must only be called from a single goroutine at a time.
146func signal_disable(s uint32) {
147 if int(s) >= len(sig.wanted)*32 {
148 return
149 }
150 sig.wanted[s/32] &^= 1 << (s & 31)
151 sigdisable_go(s)
152}
153
154// This runs on a foreign stack, without an m or a g. No stack split.
155//go:nosplit
156func badsignal(sig uintptr) {
c271e224
ILT
157 // Some external libraries, for example, OpenBLAS, create worker threads in
158 // a global constructor. If we're doing cpu profiling, and the SIGPROF signal
159 // comes to one of the foreign threads before we make our first cgo call, the
160 // call to cgocallback below will bring down the whole process.
161 // It's better to miss a few SIGPROF signals than to abort in this case.
162 // See http://golang.org/issue/9456.
163 if _SIGPROF != 0 && sig == _SIGPROF && needextram != 0 {
164 return
165 }
f8d9fa9e
ILT
166 cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
167}
168
169func sigenable_m()
170func sigdisable_m()
171
172func sigenable_go(s uint32) {
173 g := getg()
174 g.m.scalararg[0] = uintptr(s)
175 onM(sigenable_m)
176}
177
178func sigdisable_go(s uint32) {
179 g := getg()
180 g.m.scalararg[0] = uintptr(s)
181 onM(sigdisable_m)
182}