1 # This file is part of NIT (http://www.nitlanguage.org).
3 # Copyright 2011 Alexis Laferrière <alexis.laf@xymus.net>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # ANSI C signal handling
19 # Common usage imply 5 steps:
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`
33 # redef fun receive_signal(signal)
35 # print "received safely {signal}"
36 # if signal == sigalarm then print "Alarm!"
38 # redef fun receive_signal_unsafe( signal ) do print "received unsafely {signal}"
41 # var r = new MyReceiver
43 # # Handle `sigsegv` signal unsafely (the only way for this one)
44 # r.handle_signal(sigsegv, false)
46 # # Handle `sigint` and `sigalarm` safely
47 # r.handle_signal(sigint, true)
48 # r.handle_signal(sigalarm, true)
50 # # Ask system to receive a `sigalarm` signal in 1 second
54 # # Check signals and callback `receive_signal`
55 # var hit = check_signals
64 #define _POSIX_SOURCE 1
71 void (*nit_SignalHandler_receive_signal)(void* self, long signal);
74 Structure to manage each possible signals
75 are used in an array of 32 maximum signals.
76 This array is global to the software.
78 struct nit_signals_ent {
79 char raised; /* !=0 if has been raised */
80 void* handler; /* instance to receive call */
81 char safely; /* if !=0 then manage signal safely, otherwise react when raised */
82 } nit_signals_list[32] = {{0}};
84 /* Receiver to all signals
85 If unsafe, it calls directly the Nit receiver,
86 otherwise it marks the signal as raised and returns.
88 void receiver(int sig)
90 if (sig < 32 && sig >=0)
92 if (nit_signals_list[sig].safely) {
93 nit_signals_list[sig].raised += 1;
95 nit_SignalHandler_receive_signal(nit_signals_list[sig].handler, sig);
101 # Receives the callback from system when a given signal arise
102 interface SignalHandler
103 # Invoked after a call to `check_signals` if a signal has been raised
104 # (should be redefed by subclasses)
106 # Should be used by most signals except `sigkill` and `sigstop` since they
107 # cannot be caught, blocked or ignored.
110 # super SignalHandler
112 # redef fun receive_signal(signal) do print "received safely {signal}"
115 # var r = new MyReceiver
116 # r.handle_signal(sigint, true) # will call back when "check_signals" is called
118 # check_signals # if a signal was received, it will invoke `r.receive_signal`
119 fun receive_signal
(signal
: Int) do end
121 # Called immediatly on receiving an unsafe signal (should be redefed by subclasses)
123 # Should be used for `sigkill` and `sigstop` since they cannot be caught,
124 # blocked or ignored.
126 # You should consider this methods as being fragile. It should be implemented in C
127 # and you should not do too much callbacks to Nit.
130 # super SignalHandler
132 # redef fun receive_signal_unsafe(signal) do print "received unsafely {signal}"
135 # var r = new MyReceiver
136 # r.handle_signal(sigsegv, false) # `r.receive_signal_unsafe` will be invoked on sigsegv
137 fun receive_signal_unsafe
(signal
: Int) do end
139 # Set the receiver as the handler of the signal
141 # If `safely`, receiver will be called when `check_signals` in invoked
142 # otherwise the receiver is invoked when the signal is raised, it may
143 # crash the Nit system but is unavoidable for unstoppable signals.
144 fun handle_signal
(signal
: Int, safely
: Bool) import receive_signal
`{
145 if (signal < 32 && signal >=0) {
146 struct sigaction act;
147 sigemptyset(&act.sa_mask);
149 act.sa_handler = receiver;
151 sigaction(signal, &act, NULL);
153 #ifdef SignalHandler_decr_ref
154 SignalHandler last_handler = (SignalHandler)nit_signals_list[signal].handler;
155 if (last_handler != NULL)
156 SignalHandler_decr_ref(last_handler);
159 nit_signals_list[signal].handler = self;
161 #ifdef SignalHandler_incr_ref
162 SignalHandler_incr_ref(self);
165 nit_signals_list[signal].safely = safely;
167 nit_SignalHandler_receive_signal =
168 (void (*)(void*, long))&SignalHandler_receive_signal;
172 # Set to ignore the signal
173 fun ignore_signal
(signal
: Int) `{
174 if (signal < 32 && signal >=0) {
175 struct sigaction act;
176 sigemptyset(&act.sa_mask);
178 act.sa_handler = SIG_IGN;
179 sigaction(signal, &act, NULL);
181 #ifdef SignalHandler_decr_ref
182 SignalHandler last_handler = (SignalHandler)nit_signals_list[signal].handler;
183 if (last_handler != NULL)
184 SignalHandler_decr_ref(last_handler);
189 # Set default action for the signal
190 fun default_signal
(signal
: Int) `{
191 if (signal < 32 && signal >=0) {
192 struct sigaction act;
193 sigemptyset(&act.sa_mask);
195 act.sa_handler = SIG_DFL;
196 sigaction(signal, &act, NULL);
198 #ifdef SignalHandler_decr_ref
199 SignalHandler last_handler = (SignalHandler)nit_signals_list[signal].handler;
200 if (last_handler != NULL)
201 SignalHandler_decr_ref(last_handler);
207 # Check signals for safe operation
208 # will callback receiver of raised signals
209 # can callback any instance of SignalHandler, not just this one
210 fun check_signals
: Bool is extern import SignalHandler.receive_signal
`{
212 int raised_something = 0;
214 for (sig = 0; sig < 32; sig ++)
215 if (nit_signals_list[sig].raised) {
216 nit_signals_list[sig].raised = 0;
217 raised_something = 1;
218 SignalHandler handler = (SignalHandler)nit_signals_list[sig].handler;
219 SignalHandler_receive_signal(handler, sig);
222 return raised_something;
226 # can callback any instance of SignalHandler, not just this one
227 fun set_alarm
(sec
: Int) `{ alarm(sec); `}
230 # Send a signal to the process
231 fun signal(signal: Int) do native_kill(id, signal)
233 # Send the kill signal to the process
234 fun kill do signal(sigkill)
236 # Native implementation of `signal
`
237 private fun native_kill(pid, signal: Int) `{ kill(pid, signal); `}
240 # Hang up detected on controlling terminal or death of controlling process
241 fun sighup
: Int do return 1
243 # Issued if the user sends an interrupt signal
244 fun sigint
: Int do return 2
246 # Issued if the user sends a quit signal
247 fun sigquit
: Int do return 3
249 # Issued if the user attempts to execute an illegal, malformed, unknown, or privileged instruction
250 fun sigill
: Int do return 4
252 # Issued when an exception occurs: a condition that a debugger has requested to be informed of
253 fun sigtrap
: Int do return 5
255 # This signal is sent to a process to tell it to abort, i. e. to terminate
256 fun sigabrt
: Int do return 6
258 # This signal is sent to a process when it causes a bus error
259 fun sigbus
: Int do return 7
261 # Issued if an illegal mathematical operation is attempted
262 fun sigfpe
: Int do return 8
264 # If a process gets this signal it must quit immediately and will not perform any clean-up operations
265 fun sigkill
: Int do return 9
267 # Sent to a process to indicate user-defined conditions
268 fun sigusr1
: Int do return 10
270 # Sent to a process when it makes an invalid virtual memory reference, or segmentation fault
271 fun sigsegv
: Int do return 11
273 # Sent to a process to indicate user-defined conditions
274 fun sigusr2
: Int do return 12
276 # Sent to a process when it attempts to write to a pipe without a process connected to the other end
277 fun sigpipe
: Int do return 13
280 fun sigalarm
: Int do return 14
282 # Software termination signal
283 fun sigterm
: Int do return 15
285 # Sent to a process when a child process terminates or is interrupted
286 fun sigchild
: Int do return 17
288 # Tell the operating system to continue (restart) a process previously paused by the SIGSTOP or SIGTSTP signal
289 fun sigcont
: Int do return 18
291 # Tell the operating system to stop a process
292 fun sigstop
: Int do return 19
294 # Sent to a process by its terminal to request it to stop temporarily
295 fun sigtstp
: Int do return 20
297 # Sent to a process when a socket has urgent or out-of-band data available to read
298 fun sigurg
: Int do return 23
300 # Sent to a process when it has used the CPU for a duration that exceeds a user-settable value
301 fun sigxcpu
: Int do return 24
303 # Sent to a process when it grows a file larger than the maximum allowed size
304 fun sigxfsz
: Int do return 25
306 # Virtual timer expired
307 fun sigvtalrm
: Int do return 26
309 # Profiling timer expired
310 fun sigprof
: Int do return 27
312 # Sent to a process when its controlling terminal changes its window size
313 fun sigwinch
: Int do return 28
315 # Sent to a process when the system experiences a power failure
316 fun sigpwr
: Int do return 30
318 # Sent to a process when it passes a bad argument to a system call
319 fun sigsys
: Int do return 31