Line data Source code
1 : /* src/vm/signal.cpp - machine independent signal functions
2 :
3 : Copyright (C) 1996-2013
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 : #include <errno.h> // for EINTR
26 : #include <signal.h> // for sigaction, sigemptyset, etc
27 : #include <cstdlib> // for NULL
28 : #include "arch.hpp"
29 : #include "class.hpp" // for class_resolvemethod
30 : #include "config.h"
31 : #include "global.hpp" // for functionptr
32 : #include "mm/gc.hpp" // for heap_alloc
33 : #include "mm/memory.hpp" // for GCNEW
34 : #include "threads/thread.hpp" // for thread_set_state_runnable, etc
35 : #include "threads/threadlist.hpp" // for ThreadList
36 : #include "toolbox/logging.hpp" // for log_println
37 : #include "utf8.hpp" // for Utf8String
38 : #include "vm/exceptions.hpp" // for exceptions_get_exception, etc
39 : #include "vm/globals.hpp" // for class_sun_misc_Signal
40 : #include "vm/options.hpp"
41 : #include "vm/os.hpp" // for os
42 : #include "vm/signallocal.hpp" // for md_signal_handler_sigsegv, etc
43 : #include "vm/vm.hpp" // for vm_abort, vm_call_method, etc
44 :
45 : struct methodinfo;
46 :
47 : /* function prototypes ********************************************************/
48 :
49 : void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p);
50 : void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p);
51 :
52 :
53 : /* signal_init *****************************************************************
54 :
55 : Initializes the signal subsystem and installs the signal handler.
56 :
57 : *******************************************************************************/
58 :
59 163 : bool signal_init(void)
60 : {
61 : #if !defined(__CYGWIN__)
62 : sigset_t mask;
63 :
64 163 : TRACESUBSYSTEMINITIALIZATION("signal_init");
65 :
66 : #if defined(__LINUX__)
67 : /* XXX Remove for exact-GC. */
68 163 : if (threads_pthreads_implementation_nptl) {
69 : #endif
70 :
71 : /* Block the following signals (SIGINT for <ctrl>-c, SIGQUIT for
72 : <ctrl>-\). We enable them later in signal_thread, but only for
73 : this thread. */
74 :
75 163 : if (sigemptyset(&mask) != 0)
76 0 : os::abort_errno("signal_init: sigemptyset failed");
77 :
78 : #if !defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
79 : /* Let OpenJDK handle SIGINT itself. */
80 :
81 163 : if (sigaddset(&mask, SIGINT) != 0)
82 0 : os::abort_errno("signal_init: sigaddset failed");
83 : #endif
84 :
85 : #if !defined(__FREEBSD__)
86 163 : if (sigaddset(&mask, SIGQUIT) != 0)
87 0 : os::abort_errno("signal_init: sigaddset failed");
88 : #endif
89 :
90 163 : if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
91 0 : os::abort_errno("signal_init: sigprocmask failed");
92 :
93 : #if defined(__LINUX__)
94 : /* XXX Remove for exact-GC. */
95 : }
96 : #endif
97 :
98 : #if defined(ENABLE_GC_BOEHM)
99 : /* Allocate something so the garbage collector's signal handlers
100 : are installed. */
101 :
102 163 : (void) GCNEW(int);
103 : #endif
104 :
105 : /* Install signal handlers for signals we want to catch in all
106 : threads. */
107 :
108 : #if defined(ENABLE_JIT)
109 : # if defined(ENABLE_INTRP)
110 : if (!opt_intrp) {
111 : # endif
112 : /* SIGSEGV handler */
113 :
114 : signal_register_signal(SIGSEGV, (functionptr) md_signal_handler_sigsegv,
115 163 : SA_NODEFER | SA_SIGINFO);
116 :
117 : # if defined(SIGBUS)
118 : signal_register_signal(SIGBUS, (functionptr) md_signal_handler_sigsegv,
119 163 : SA_NODEFER | SA_SIGINFO);
120 : # endif
121 :
122 : # if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
123 : /* SIGFPE handler */
124 :
125 : signal_register_signal(SIGFPE, (functionptr) md_signal_handler_sigfpe,
126 163 : SA_NODEFER | SA_SIGINFO);
127 : # endif
128 :
129 : # if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
130 : /* XXX use better defines for that (in arch.h) */
131 : /* SIGILL handler */
132 :
133 : signal_register_signal(SIGILL, (functionptr) md_signal_handler_sigill,
134 163 : SA_NODEFER | SA_SIGINFO);
135 : # endif
136 :
137 : # if defined(__POWERPC__)
138 : /* XXX use better defines for that (in arch.h) */
139 : /* SIGTRAP handler */
140 :
141 : signal_register_signal(SIGTRAP, (functionptr) md_signal_handler_sigtrap,
142 : SA_NODEFER | SA_SIGINFO);
143 : # endif
144 : # if defined(ENABLE_INTRP)
145 : }
146 : # endif
147 :
148 : #if defined(__DARWIN__)
149 : do {
150 : struct utsname name;
151 : kern_return_t kr;
152 :
153 : /* Check if we're on 10.4 (Tiger/8.x) or earlier */
154 : if (uname(&name) != 0)
155 : break;
156 :
157 : /* Make sure the string is large enough */
158 : /* Check the major number (ascii comparison) */
159 : /* Verify that we're not looking at '10.' by checking for a trailing period. */
160 : if (name.release[0] == '\0' || name.release[0] > '8' || name.release[1] != '.')
161 : break;
162 :
163 : /* Reset CrashReporter's task signal handler */
164 : kr = task_set_exception_ports(mach_task_self(),
165 : EXC_MASK_BAD_ACCESS
166 : # if defined(__I386__) || defined(__X86_64__)
167 : | EXC_MASK_BAD_INSTRUCTION
168 : #endif
169 : , MACH_PORT_NULL,
170 : EXCEPTION_STATE_IDENTITY,
171 : MACHINE_THREAD_STATE);
172 :
173 : assert(kr == KERN_SUCCESS);
174 : } while (false);
175 : #endif
176 : #endif /* !defined(ENABLE_JIT) */
177 :
178 : /* SIGHUP handler for threads_thread_interrupt */
179 :
180 163 : signal_register_signal(Signal_INTERRUPT_SYSTEM_CALL, (functionptr) signal_handler_sighup, 0);
181 :
182 : /* SIGUSR1 handler for thread suspension */
183 :
184 163 : signal_register_signal(SIGUSR1, (functionptr) signal_handler_sigusr1, SA_SIGINFO);
185 :
186 : #ifdef ENABLE_PROFILING
187 : /* SIGUSR2 handler for profiling sampling */
188 :
189 : signal_register_signal(SIGUSR2, (functionptr) md_signal_handler_sigusr2, SA_SIGINFO);
190 : #endif
191 :
192 : #endif /* !defined(__CYGWIN__) */
193 :
194 163 : return true;
195 : }
196 :
197 :
198 : /* signal_register_signal ******************************************************
199 :
200 : Register the specified handler with the specified signal.
201 :
202 : *******************************************************************************/
203 :
204 978 : void signal_register_signal(int signum, functionptr handler, int flags)
205 : {
206 : struct sigaction act;
207 :
208 : void (*function)(int, siginfo_t *, void *);
209 :
210 978 : function = (void (*)(int, siginfo_t *, void *)) handler;
211 :
212 978 : if (sigemptyset(&act.sa_mask) != 0)
213 0 : os::abort_errno("signal_register_signal: sigemptyset failed");
214 :
215 978 : act.sa_sigaction = function;
216 978 : act.sa_flags = flags;
217 :
218 978 : if (sigaction(signum, &act, NULL) != 0)
219 0 : os::abort_errno("signal_register_signal: sigaction failed");
220 978 : }
221 :
222 :
223 : /* signal_thread ************************************************************
224 :
225 : This thread sets the signal mask to catch the user input signals
226 : (SIGINT, SIGQUIT). We use such a thread, so we don't get the
227 : signals on every single thread running.
228 :
229 : *******************************************************************************/
230 :
231 163 : static void signal_thread(void)
232 : {
233 : threadobject *t;
234 : sigset_t mask;
235 : int sig;
236 : int result;
237 :
238 163 : t = THREADOBJECT;
239 :
240 163 : if (sigemptyset(&mask) != 0)
241 0 : os::abort_errno("signal_thread: sigemptyset failed");
242 :
243 : #if !defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
244 : /* Let OpenJDK handle SIGINT itself. */
245 :
246 163 : if (sigaddset(&mask, SIGINT) != 0)
247 0 : os::abort_errno("signal_thread: sigaddset failed");
248 : #endif
249 :
250 : #if !defined(__FREEBSD__)
251 163 : if (sigaddset(&mask, SIGQUIT) != 0)
252 0 : os::abort_errno("signal_thread: sigaddset failed");
253 : #endif
254 :
255 0 : for (;;) {
256 : /* just wait for a signal */
257 :
258 163 : thread_set_state_waiting(t);
259 :
260 : // sigwait can return EINTR (unlike what the Linux man-page
261 : // says).
262 0 : do {
263 163 : result = sigwait(&mask, &sig);
264 : } while (result == EINTR);
265 :
266 0 : if (result != 0)
267 0 : os::abort_errnum(result, "signal_thread: sigwait failed");
268 :
269 0 : thread_set_state_runnable(t);
270 :
271 : /* Handle the signal. */
272 :
273 0 : signal_thread_handler(sig);
274 : }
275 : }
276 :
277 :
278 : /* signal_thread_handler *******************************************************
279 :
280 : Handles the signals caught in the signal handler thread. Also used
281 : from sun.misc.Signal with OpenJDK.
282 :
283 : *******************************************************************************/
284 :
285 0 : void signal_thread_handler(int sig)
286 : {
287 0 : switch (sig) {
288 : case SIGINT:
289 : /* exit the vm properly */
290 :
291 0 : vm_exit(1);
292 0 : break;
293 :
294 : case SIGQUIT:
295 : /* print a thread dump */
296 0 : ThreadList::get()->dump_threads();
297 :
298 : #if 0 && defined(ENABLE_STATISTICS)
299 : if (opt_stat)
300 : statistics_print_memory_usage();
301 : #endif
302 0 : break;
303 :
304 : #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
305 : default: {
306 : // For OpenJDK we dispatch all unknown signals to Java.
307 : methodinfo* m = class_resolvemethod(class_sun_misc_Signal, utf8::dispatch, utf8::int__void);
308 : (void) vm_call_method(m, NULL, sig);
309 :
310 : if (exceptions_get_exception()) {
311 : log_println("signal_thread_handler: Java signal handler throw an exception while dispatching signal %d:", sig);
312 : exceptions_print_stacktrace();
313 : vm_abort("signal_thread_handler: Aborting...");
314 : }
315 : break;
316 : }
317 : #else
318 : default:
319 0 : vm_abort("signal_thread_handler: Unknown signal %d", sig);
320 : #endif
321 : }
322 0 : }
323 :
324 :
325 : /* signal_start_thread *********************************************************
326 :
327 : Starts the signal handler thread.
328 :
329 : *******************************************************************************/
330 :
331 163 : bool signal_start_thread(void)
332 : {
333 163 : Utf8String name = Utf8String::from_utf8("Signal Handler");
334 :
335 163 : if (!threads_thread_start_internal(name, signal_thread))
336 0 : return false;
337 :
338 : /* everything's ok */
339 :
340 163 : return true;
341 : }
342 :
343 :
344 : /* signal_handler_sighup *******************************************************
345 :
346 : This handler is required by threads_thread_interrupt and does
347 : nothing.
348 :
349 : *******************************************************************************/
350 :
351 20000 : void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p)
352 : {
353 : /* do nothing */
354 20000 : }
355 :
356 :
357 : /* signal_handler_sigusr1 ******************************************************
358 :
359 : Signal handler for suspending threads.
360 :
361 : *******************************************************************************/
362 :
363 0 : void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
364 : {
365 : // Really suspend ourselves by acknowledging the suspension.
366 0 : threads_suspend_ack();
367 0 : }
368 :
369 : /*
370 : * These are local overrides for various environment variables in Emacs.
371 : * Please do not remove this and leave it at the end of the file, where
372 : * Emacs will automagically detect them.
373 : * ---------------------------------------------------------------------
374 : * Local variables:
375 : * mode: c++
376 : * indent-tabs-mode: t
377 : * c-basic-offset: 4
378 : * tab-width: 4
379 : * End:
380 : * vim:noexpandtab:sw=4:ts=4:
381 : */
|