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