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