* src/vm/signallocal.h (Signal_THREAD_INTERRUPT): Renamed to
[cacao.git] / src / vm / signal.c
1 /* src/vm/signal.c - machine independent signal functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <signal.h>
30 #include <stdint.h>
31 #include <stdlib.h>
32
33 #if defined(__DARWIN__)
34 /* If we compile with -ansi on darwin, <sys/types.h> is not
35  included. So let's do it here. */
36 # include <sys/types.h>
37 # include <sys/utsname.h>
38 #endif
39
40 #include "arch.h"
41
42 #if defined(ENABLE_GC_BOEHM)
43 # include "mm/memory.h"
44 #endif
45
46 #include "threads/thread.hpp"
47
48 #include "vm/exceptions.hpp"
49 #include "vm/signallocal.h"
50 #include "vm/vm.hpp"
51
52 #include "vmcore/globals.hpp"
53 #include "vmcore/method.h"
54 #include "vmcore/options.h"
55
56 #if defined(ENABLE_STATISTICS)
57 # include "vmcore/statistics.h"
58 #endif
59
60
61 /* function prototypes ********************************************************/
62
63 void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p);
64
65
66 /* signal_init *****************************************************************
67
68    Initializes the signal subsystem and installs the signal handler.
69
70 *******************************************************************************/
71
72 bool signal_init(void)
73 {
74 #if !defined(__CYGWIN__)
75         sigset_t mask;
76
77         TRACESUBSYSTEMINITIALIZATION("signal_init");
78
79 #if defined(__LINUX__) && defined(ENABLE_THREADS)
80         /* XXX Remove for exact-GC. */
81         if (threads_pthreads_implementation_nptl) {
82 #endif
83
84         /* Block the following signals (SIGINT for <ctrl>-c, SIGQUIT for
85            <ctrl>-\).  We enable them later in signal_thread, but only for
86            this thread. */
87
88         if (sigemptyset(&mask) != 0)
89                 vm_abort_errno("signal_init: sigemptyset failed");
90
91 #if !defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
92         /* Let OpenJDK handle SIGINT itself. */
93
94         if (sigaddset(&mask, SIGINT) != 0)
95                 vm_abort_errno("signal_init: sigaddset failed");
96 #endif
97
98 #if !defined(__FREEBSD__)
99         if (sigaddset(&mask, SIGQUIT) != 0)
100                 vm_abort_errno("signal_init: sigaddset failed");
101 #endif
102
103         if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
104                 vm_abort_errno("signal_init: sigprocmask failed");
105
106 #if defined(__LINUX__) && defined(ENABLE_THREADS)
107         /* XXX Remove for exact-GC. */
108         }
109 #endif
110
111 #if defined(ENABLE_GC_BOEHM)
112         /* Allocate something so the garbage collector's signal handlers
113            are installed. */
114
115         (void) GCNEW(int);
116 #endif
117
118         /* Install signal handlers for signals we want to catch in all
119            threads. */
120
121 #if defined(ENABLE_JIT)
122 # if defined(ENABLE_INTRP)
123         if (!opt_intrp) {
124 # endif
125                 /* SIGSEGV handler */
126
127                 signal_register_signal(SIGSEGV, (functionptr) md_signal_handler_sigsegv,
128                                                            SA_NODEFER | SA_SIGINFO);
129
130 #  if defined(SIGBUS)
131                 signal_register_signal(SIGBUS, (functionptr) md_signal_handler_sigsegv,
132                                                            SA_NODEFER | SA_SIGINFO);
133 #  endif
134
135 #  if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
136                 /* SIGFPE handler */
137
138                 signal_register_signal(SIGFPE, (functionptr) md_signal_handler_sigfpe,
139                                                            SA_NODEFER | SA_SIGINFO);
140 #  endif
141
142 #  if defined(__ARM__) || defined(__I386__) || defined(__S390__) || defined(__X86_64__) || defined(__M68K__)
143                 /* XXX use better defines for that (in arch.h) */
144                 /* SIGILL handler */
145
146                 signal_register_signal(SIGILL, (functionptr) md_signal_handler_sigill,
147                                                            SA_NODEFER | SA_SIGINFO);
148 #  endif
149
150 #  if defined(__POWERPC__)
151                 /* XXX use better defines for that (in arch.h) */
152                 /* SIGTRAP handler */
153
154                 signal_register_signal(SIGTRAP, (functionptr) md_signal_handler_sigtrap,
155                                                            SA_NODEFER | SA_SIGINFO);
156 #  endif
157 # if defined(ENABLE_INTRP)
158         }
159 # endif
160
161 #if defined(__DARWIN__)
162         do {
163                 struct utsname name;
164                 kern_return_t kr;
165
166                 /* Check if we're on 10.4 (Tiger/8.x) or earlier */
167                 if (uname(&name) != 0) 
168                         break;
169
170                 /* Make sure the string is large enough */
171                 /* Check the major number (ascii comparison) */
172                 /* Verify that we're not looking at '10.' by checking for a trailing period. */
173                 if (name.release[0] == '\0' || name.release[0] > '8' || name.release[1] != '.')
174                         break;
175
176                 /* Reset CrashReporter's task signal handler */
177                 kr = task_set_exception_ports(mach_task_self(),
178                                                                           EXC_MASK_BAD_ACCESS
179 #  if defined(__I386__)
180                                                                           | EXC_MASK_BAD_INSTRUCTION
181 #endif
182                                                                           , MACH_PORT_NULL,
183                                                                           EXCEPTION_STATE_IDENTITY,
184                                                                           MACHINE_THREAD_STATE);
185
186                 assert(kr == KERN_SUCCESS);
187         } while (false);
188 #endif
189 #endif /* !defined(ENABLE_JIT) */
190
191 #if defined(ENABLE_THREADS)
192         /* SIGHUP handler for threads_thread_interrupt */
193
194         signal_register_signal(Signal_INTERRUPT_SYSTEM_CALL, (functionptr) signal_handler_sighup, 0);
195 #endif
196
197 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
198         /* SIGUSR1 handler for the exact GC to suspend threads */
199
200         signal_register_signal(SIGUSR1, (functionptr) md_signal_handler_sigusr1,
201                                                    SA_SIGINFO);
202 #endif
203
204 #if defined(ENABLE_THREADS) && defined(ENABLE_PROFILING)
205         /* SIGUSR2 handler for profiling sampling */
206
207         signal_register_signal(SIGUSR2, (functionptr) md_signal_handler_sigusr2,
208                                                    SA_SIGINFO);
209 #endif
210
211 #endif /* !defined(__CYGWIN__) */
212
213         return true;
214 }
215
216
217 /* signal_register_signal ******************************************************
218
219    Register the specified handler with the specified signal.
220
221 *******************************************************************************/
222
223 void signal_register_signal(int signum, functionptr handler, int flags)
224 {
225         struct sigaction act;
226
227         void (*function)(int, siginfo_t *, void *);
228
229         function = (void (*)(int, siginfo_t *, void *)) handler;
230
231         if (sigemptyset(&act.sa_mask) != 0)
232                 vm_abort_errno("signal_register_signal: sigemptyset failed");
233
234         act.sa_sigaction = function;
235         act.sa_flags     = flags;
236
237         if (sigaction(signum, &act, NULL) != 0)
238                 vm_abort_errno("signal_register_signal: sigaction failed");
239 }
240
241
242 /* signal_thread ************************************************************
243
244    This thread sets the signal mask to catch the user input signals
245    (SIGINT, SIGQUIT).  We use such a thread, so we don't get the
246    signals on every single thread running.
247
248 *******************************************************************************/
249
250 static void signal_thread(void)
251 {
252         threadobject *t;
253         sigset_t      mask;
254         int           sig;
255         int result;
256
257         t = THREADOBJECT;
258
259         if (sigemptyset(&mask) != 0)
260                 vm_abort_errno("signal_thread: sigemptyset failed");
261
262 #if !defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
263         /* Let OpenJDK handle SIGINT itself. */
264
265         if (sigaddset(&mask, SIGINT) != 0)
266                 vm_abort_errno("signal_thread: sigaddset failed");
267 #endif
268
269 #if !defined(__FREEBSD__)
270         if (sigaddset(&mask, SIGQUIT) != 0)
271                 vm_abort_errno("signal_thread: sigaddset failed");
272 #endif
273
274         for (;;) {
275                 /* just wait for a signal */
276
277 #if defined(ENABLE_THREADS)
278                 thread_set_state_waiting(t);
279 #endif
280
281                 // sigwait can return EINTR (unlike what the Linux man-page
282                 // says).
283                 do {
284                         result = sigwait(&mask, &sig);
285                 } while (result == EINTR);
286
287                 if (result != 0)
288                         vm_abort_errnum(result, "signal_thread: sigwait failed");
289
290 #if defined(ENABLE_THREADS)
291                 thread_set_state_runnable(t);
292 #endif
293
294                 /* Handle the signal. */
295
296                 signal_thread_handler(sig);
297         }
298 }
299
300
301 /* signal_thread_handler *******************************************************
302
303    Handles the signals caught in the signal handler thread.  Also used
304    from sun.misc.Signal with OpenJDK.
305
306 *******************************************************************************/
307
308 void signal_thread_handler(int sig)
309 {
310         switch (sig) {
311         case SIGINT:
312                 /* exit the vm properly */
313
314                 vm_exit(1);
315                 break;
316
317         case SIGQUIT:
318                 /* print a thread dump */
319 #if defined(ENABLE_THREADS)
320                 threads_dump();
321 #endif
322
323 #if defined(ENABLE_STATISTICS)
324                 if (opt_stat)
325                         statistics_print_memory_usage();
326 #endif
327                 break;
328
329 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
330         default: {
331                 // For OpenJDK we dispatch all unknown signals to Java.
332                 methodinfo* m = class_resolvemethod(class_sun_misc_Signal, utf_dispatch, utf_int__void);
333                 (void) vm_call_method(m, NULL, sig);
334
335                 if (exceptions_get_exception()) {
336                         log_println("signal_thread_handler: Java signal handler throw an exception while dispatching signal %d:", sig);
337                         exceptions_print_stacktrace();
338                         vm_abort("signal_thread_handler: Aborting...");
339                 }
340                 break;
341         }
342 #else
343         default:
344                 vm_abort("signal_thread_handler: Unknown signal %d", sig);
345 #endif
346         }
347 }
348
349
350 /* signal_start_thread *********************************************************
351
352    Starts the signal handler thread.
353
354 *******************************************************************************/
355
356 bool signal_start_thread(void)
357 {
358 #if defined(ENABLE_THREADS)
359         utf *name;
360
361         name = utf_new_char("Signal Handler");
362
363         if (!threads_thread_start_internal(name, signal_thread))
364                 return false;
365
366         /* everything's ok */
367
368         return true;
369 #else
370 #warning FIX ME!
371 #endif
372 }
373
374
375 /* signal_handler_sighup *******************************************************
376
377    This handler is required by threads_thread_interrupt and does
378    nothing.
379
380 *******************************************************************************/
381
382 #if defined(ENABLE_THREADS)
383 void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p)
384 {
385         /* do nothing */
386 }
387 #endif
388
389
390 /*
391  * These are local overrides for various environment variables in Emacs.
392  * Please do not remove this and leave it at the end of the file, where
393  * Emacs will automagically detect them.
394  * ---------------------------------------------------------------------
395  * Local variables:
396  * mode: c
397  * indent-tabs-mode: t
398  * c-basic-offset: 4
399  * tab-width: 4
400  * End:
401  */