OLD | NEW |
| (Empty) |
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 blocke
d. | |
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 | |
27 package runtime | |
28 #include "runtime.h" | |
29 #include "defs_GOOS_GOARCH.h" | |
30 #include "os_GOOS.h" | |
31 #include "cgocall.h" | |
32 #include "../../cmd/ld/textflag.h" | |
33 | |
34 #pragma textflag NOPTR | |
35 static struct { | |
36 Note; | |
37 uint32 mask[(NSIG+31)/32]; | |
38 uint32 wanted[(NSIG+31)/32]; | |
39 uint32 recv[(NSIG+31)/32]; | |
40 uint32 state; | |
41 bool inuse; | |
42 } sig; | |
43 | |
44 enum { | |
45 HASWAITER = 1, | |
46 HASSIGNAL = 2, | |
47 }; | |
48 | |
49 // Called from sighandler to send a signal back out of the signal handling threa
d. | |
50 bool | |
51 runtime·sigsend(int32 s) | |
52 { | |
53 uint32 bit, mask, old, new; | |
54 | |
55 if(!sig.inuse || s < 0 || s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32
]&(1U<<(s&31)))) | |
56 return false; | |
57 bit = 1 << (s&31); | |
58 for(;;) { | |
59 mask = sig.mask[s/32]; | |
60 if(mask & bit) | |
61 break; // signal already in queue | |
62 if(runtime·cas(&sig.mask[s/32], mask, mask|bit)) { | |
63 // Added to queue. | |
64 // Only send a wakeup if the receiver needs a kick. | |
65 for(;;) { | |
66 old = runtime·atomicload(&sig.state); | |
67 if(old == HASSIGNAL) | |
68 break; | |
69 if(old == HASWAITER) | |
70 new = 0; | |
71 else // if(old == 0) | |
72 new = HASSIGNAL; | |
73 if(runtime·cas(&sig.state, old, new)) { | |
74 if (old == HASWAITER) | |
75 runtime·notewakeup(&sig); | |
76 break; | |
77 } | |
78 } | |
79 break; | |
80 } | |
81 } | |
82 return true; | |
83 } | |
84 | |
85 // Called to receive the next queued signal. | |
86 // Must only be called from a single goroutine at a time. | |
87 func signal_recv() (m uint32) { | |
88 uint32 i, old, new; | |
89 ········ | |
90 for(;;) { | |
91 // Serve from local copy if there are bits left. | |
92 for(i=0; i<NSIG; i++) { | |
93 if(sig.recv[i/32]&(1U<<(i&31))) { | |
94 sig.recv[i/32] ^= 1U<<(i&31); | |
95 m = i; | |
96 goto done; | |
97 } | |
98 } | |
99 | |
100 // Check and update sig.state. | |
101 for(;;) { | |
102 old = runtime·atomicload(&sig.state); | |
103 if(old == HASWAITER) | |
104 runtime·throw("inconsistent state in signal_recv
"); | |
105 if(old == HASSIGNAL) | |
106 new = 0; | |
107 else // if(old == 0) | |
108 new = HASWAITER; | |
109 if(runtime·cas(&sig.state, old, new)) { | |
110 if (new == HASWAITER) { | |
111 runtime·notetsleepg(&sig, -1); | |
112 runtime·noteclear(&sig); | |
113 } | |
114 break; | |
115 } | |
116 } | |
117 | |
118 // Get a new local copy. | |
119 for(i=0; i<nelem(sig.mask); i++) { | |
120 for(;;) { | |
121 m = sig.mask[i]; | |
122 if(runtime·cas(&sig.mask[i], m, 0)) | |
123 break; | |
124 } | |
125 sig.recv[i] = m; | |
126 } | |
127 } | |
128 | |
129 done:; | |
130 // goc requires that we fall off the end of functions | |
131 // that return values instead of using our own return | |
132 // statements. | |
133 } | |
134 | |
135 // Must only be called from a single goroutine at a time. | |
136 func signal_enable(s uint32) { | |
137 if(!sig.inuse) { | |
138 // The first call to signal_enable is for us | |
139 // to use for initialization. It does not pass | |
140 // signal information in m. | |
141 sig.inuse = true; // enable reception of signals; cannot d
isable | |
142 runtime·noteclear(&sig); | |
143 return; | |
144 } | |
145 ········ | |
146 if(s >= nelem(sig.wanted)*32) | |
147 return; | |
148 sig.wanted[s/32] |= 1U<<(s&31); | |
149 runtime·sigenable(s); | |
150 } | |
151 | |
152 // Must only be called from a single goroutine at a time. | |
153 func signal_disable(s uint32) { | |
154 if(s >= nelem(sig.wanted)*32) | |
155 return; | |
156 sig.wanted[s/32] &= ~(1U<<(s&31)); | |
157 runtime·sigdisable(s); | |
158 } | |
159 | |
160 // This runs on a foreign stack, without an m or a g. No stack split. | |
161 #pragma textflag NOSPLIT | |
162 void | |
163 runtime·badsignal(uintptr sig) | |
164 { | |
165 runtime·cgocallback((void (*)(void))runtime·sigsend, &sig, sizeof(sig)); | |
166 } | |
OLD | NEW |