misc/vim: inform the user when no results are found
[nit.git] / lib / signals.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Copyright 2011 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Module to manage standard C signals
18 #
19 # Common usage imply 5 steps:
20 #
21 # 1. Implement the `SignalHandler` interface
22 # 2. `redef receive_signal_unsafe` to handle `sigsegv`
23 # 3. `redef receive_signal` to handle other signals safely
24 # 4, Notify what signals to handle with `handle_signal`
25 # 5. If using the safe handler method, routinely call `check_signals`
26 #
27 # Usage example:
28 #
29 # ~~~~
30 # class MyReceiver
31 # super SignalHandler
32 #
33 # redef fun receive_signal(signal)
34 # do
35 # print "received safely {signal}"
36 # if signal == sigalarm then print "Alarm!"
37 # end
38 # redef fun receive_signal_unsafe( signal ) do print "received unsafely {signal}"
39 # end
40 #
41 # var r = new MyReceiver
42 #
43 # # Handle `sigsegv` signal unsafely (the only way for this one)
44 # r.handle_signal(sigsegv, false)
45 #
46 # # Handle `sigint` and `sigalarm` safely
47 # r.handle_signal(sigint, true)
48 # r.handle_signal(sigalarm, true)
49 #
50 # # Ask system to receive a `sigalarm` signal in 1 second
51 # set_alarm(1)
52 #
53 # loop
54 # # Check signals and callback `receive_signal`
55 # var hit = check_signals
56 #
57 # if hit then break
58 # end
59 # ~~~~
60 module signals
61
62 `{
63 #undef _POSIX_SOURCE
64 #define _POSIX_SOURCE 1
65 #include <signal.h>
66 #include <stdio.h>
67
68 /*
69 This guard prevents errors by the C compiler when the Nit code imports this
70 module but do not use handle_signal. When it is _not_ used, the C type
71 SignalHandler and C function SignalHandler_receive_signal are not generated.
72 Which does not please the C compiler. This guard ensure that we compile this
73 code only if the type SignalHandler has been defined.
74
75 This is a HACK, FIXME by:
76 * Adding the macro to the FFI spec, or
77 * Attach the callbacks to this code block (or the module itself)
78 * Avoid using Nit types and callbacks or use them only in the C implementation
79 of Nit method.
80 */
81 #ifdef NIT_TYPE_SignalHandler
82
83 /*
84 Structure to manage each possible signals
85 are used in an array of 32 maximum signals.
86 This array is global to the software.
87 */
88 struct nit_signals_ent {
89 char raised; /* !=0 if has been raised */
90 SignalHandler handler; /* instance to receive call */
91 char safely; /* if !=0 then manage signal safely, otherwise react when raised */
92 } nit_signals_list[32] = {0x0};
93
94 /* Receiver to all signals
95 If unsafe, it calls directly the Nit receiver,
96 otherwise it marks the signal as raised and returns.
97 */
98 void receiver(int sig)
99 {
100 if (sig < 32 && sig >=0)
101 {
102 if (nit_signals_list[sig].safely) {
103 nit_signals_list[sig].raised += 1;
104 } else {
105 SignalHandler_receive_signal(nit_signals_list[sig].handler, sig);
106 }
107 }
108 }
109
110 #endif
111 `}
112
113 # Receives the callback from system when a given signal arise
114 interface SignalHandler
115 # Invoked after a call to `check_signals` if a signal has been raised
116 # (should be redefed by subclasses)
117 #
118 # Should be used by most signals except `sigkill` and `sigstop` since they
119 # cannot be caught, blocked or ignored.
120 #
121 # class MyReceiver
122 # super SignalHandler
123 #
124 # redef fun receive_signal(signal) do print "received safely {signal}"
125 # end
126 #
127 # var r = new MyReceiver
128 # r.handle_signal(sigint, true) # will call back when "check_signals" is called
129 # # ...
130 # check_signals # if a signal was received, it will invoke `r.receive_signal`
131 fun receive_signal(signal: Int) do end
132
133 # Called immediatly on receiving an unsafe signal (should be redefed by subclasses)
134 #
135 # Should be used for `sigkill` and `sigstop` since they cannot be caught,
136 # blocked or ignored.
137 #
138 # You should consider this methods as being fragile. It should be implemented in C
139 # and you should not do too much callbacks to Nit.
140 #
141 # class MyReceiver
142 # super SignalHandler
143 #
144 # redef fun receive_signal_unsafe(signal) do print "received unsafely {signal}"
145 # end
146 #
147 # var r = new MyReceiver
148 # r.handle_signal(sigsegv, false) # `r.receive_signal_unsafe` will be invoked on sigsegv
149 fun receive_signal_unsafe(signal: Int) do end
150
151 # Set the receiver as the handler of the signal
152 #
153 # If `safely`, receiver will be called when `check_signals` in invoked
154 # otherwise the receiver is invoked when the signal is raised, it may
155 # crash the Nit system but is unavoidable for unstoppable signals.
156 fun handle_signal(signal: Int, safely: Bool) import
157 receive_signal `{
158 SignalHandler last_handler;
159 if (signal < 32 && signal >=0) {
160 struct sigaction act;
161 sigemptyset(&act.sa_mask);
162 act.sa_flags = 0;
163 act.sa_handler = receiver;
164
165 sigaction(signal, &act, NULL);
166
167 last_handler = nit_signals_list[signal].handler;
168 if (last_handler != NULL)
169 SignalHandler_decr_ref(last_handler);
170
171 nit_signals_list[signal].handler = recv;
172 SignalHandler_incr_ref(recv);
173
174 nit_signals_list[signal].safely = safely;
175 }
176 `}
177
178 # Set to ignore the signal
179 fun ignore_signal(signal: Int) `{
180 SignalHandler last_handler;
181 if (signal < 32 && signal >=0) {
182 struct sigaction act;
183 sigemptyset(&act.sa_mask);
184 act.sa_flags = 0;
185 act.sa_handler = SIG_IGN;
186 sigaction(signal, &act, NULL);
187
188 last_handler = nit_signals_list[signal].handler;
189 if (last_handler != NULL)
190 SignalHandler_decr_ref(last_handler);
191 }
192 `}
193
194 # Set default action for the signal
195 fun default_signal(signal: Int) `{
196 SignalHandler last_handler;
197 if (signal < 32 && signal >=0) {
198 struct sigaction act;
199 sigemptyset(&act.sa_mask);
200 act.sa_flags = 0;
201 act.sa_handler = SIG_DFL;
202 sigaction(signal, &act, NULL);
203
204 last_handler = nit_signals_list[signal].handler;
205 if (last_handler != NULL)
206 SignalHandler_decr_ref(last_handler);
207 }
208 `}
209 end
210
211 redef interface Object
212
213 # Check signals for safe operation
214 # will callback receiver of raised signals
215 # can callback any instance of SignalHandler, not just this one
216 protected fun check_signals: Bool is extern import SignalHandler.receive_signal `{
217 int sig;
218 int raised_something = 0;
219
220 for (sig = 0; sig < 32; sig ++)
221 if (nit_signals_list[sig].raised) {
222 nit_signals_list[sig].raised = 0;
223 raised_something = 1;
224 SignalHandler_receive_signal(nit_signals_list[sig].handler, sig);
225 }
226
227 return raised_something;
228 `}
229
230 # Set alarm signal
231 # can callback any instance of SignalHandler, not just this one
232 protected fun set_alarm(sec: Int) `{ alarm(sec); `}
233 end
234
235 redef class Process
236 # Send a signal to the process
237 fun signal(signal: Int) do native_kill(id, signal)
238
239 # Send the kill signal to the process
240 fun kill do signal(sigkill)
241
242 # Native implementation of `signal`
243 private fun native_kill(pid, signal: Int) `{ kill(pid, signal); `}
244 end
245
246 # Hang up detected on controlling terminal or death of controlling process
247 fun sighup: Int do return 1
248
249 # Issued if the user sends an interrupt signal
250 fun sigint: Int do return 2
251
252 # Issued if the user sends a quit signal
253 fun sigquit: Int do return 3
254
255 # Issued if the user attempts to execute an illegal, malformed, unknown, or privileged instruction
256 fun sigill: Int do return 4
257
258 # Issued when an exception occurs: a condition that a debugger has requested to be informed of
259 fun sigtrap: Int do return 5
260
261 # This signal is sent to a process to tell it to abort, i. e. to terminate
262 fun sigabrt: Int do return 6
263
264 # This signal is sent to a process when it causes a bus error
265 fun sigbus: Int do return 7
266
267 # Issued if an illegal mathematical operation is attempted
268 fun sigfpe: Int do return 8
269
270 # If a process gets this signal it must quit immediately and will not perform any clean-up operations
271 fun sigkill: Int do return 9
272
273 # Sent to a process to indicate user-defined conditions
274 fun sigusr1: Int do return 10
275
276 # Sent to a process when it makes an invalid virtual memory reference, or segmentation fault
277 fun sigsegv: Int do return 11
278
279 # Sent to a process to indicate user-defined conditions
280 fun sigusr2: Int do return 12
281
282 # Sent to a process when it attempts to write to a pipe without a process connected to the other end
283 fun sigpipe: Int do return 13
284
285 # Alarm Clock signal
286 fun sigalarm: Int do return 14
287
288 # Software termination signal
289 fun sigterm: Int do return 15
290
291 # Sent to a process when a child process terminates or is interrupted
292 fun sigchild: Int do return 17
293
294 # Tell the operating system to continue (restart) a process previously paused by the SIGSTOP or SIGTSTP signal
295 fun sigcont: Int do return 18
296
297 # Tell the operating system to stop a process
298 fun sigstop: Int do return 19
299
300 # Sent to a process by its terminal to request it to stop temporarily
301 fun sigtstp: Int do return 20
302
303 # Sent to a process when a socket has urgent or out-of-band data available to read
304 fun sigurg: Int do return 23
305
306 # Sent to a process when it has used the CPU for a duration that exceeds a user-settable value
307 fun sigxcpu: Int do return 24
308
309 # Sent to a process when it grows a file larger than the maximum allowed size
310 fun sigxfsz: Int do return 25
311
312 # Virtual timer expired
313 fun sigvtalrm: Int do return 26
314
315 # Profiling timer expired
316 fun sigprof: Int do return 27
317
318 # Sent to a process when its controlling terminal changes its window size
319 fun sigwinch: Int do return 28
320
321 # Sent to a process when the system experiences a power failure
322 fun sigpwr: Int do return 30
323
324 # Sent to a process when it passes a bad argument to a system call
325 fun sigsys: Int do return 31