CACAO
signal.cpp
Go to the documentation of this file.
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 bool signal_init(void)
60 {
61 #if !defined(__CYGWIN__)
62  sigset_t mask;
63 
64  TRACESUBSYSTEMINITIALIZATION("signal_init");
65 
66 #if defined(__LINUX__)
67  /* XXX Remove for exact-GC. */
68  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  if (sigemptyset(&mask) != 0)
76  os::abort_errno("signal_init: sigemptyset failed");
77 
78 #if !defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
79  /* Let OpenJDK handle SIGINT itself. */
80 
81  if (sigaddset(&mask, SIGINT) != 0)
82  os::abort_errno("signal_init: sigaddset failed");
83 #endif
84 
85 #if !defined(__FREEBSD__)
86  if (sigaddset(&mask, SIGQUIT) != 0)
87  os::abort_errno("signal_init: sigaddset failed");
88 #endif
89 
90  if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
91  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  (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 
115  SA_NODEFER | SA_SIGINFO);
116 
117 # if defined(SIGBUS)
118  signal_register_signal(SIGBUS, (functionptr) md_signal_handler_sigsegv,
119  SA_NODEFER | SA_SIGINFO);
120 # endif
121 
122 # if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
123  /* SIGFPE handler */
124 
126  SA_NODEFER | SA_SIGINFO);
127 # endif
128 
129 # if defined(__AARCH64__) || 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 
134  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 
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 
181 
182  /* SIGUSR1 handler for thread suspension */
183 
185 
186 #ifdef ENABLE_PROFILING
187  /* SIGUSR2 handler for profiling sampling */
188 
190 #endif
191 
192 #endif /* !defined(__CYGWIN__) */
193 
194  return true;
195 }
196 
197 
198 /* signal_register_signal ******************************************************
199 
200  Register the specified handler with the specified signal.
201 
202 *******************************************************************************/
203 
204 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  function = (void (*)(int, siginfo_t *, void *)) handler;
211 
212  if (sigemptyset(&act.sa_mask) != 0)
213  os::abort_errno("signal_register_signal: sigemptyset failed");
214 
215  act.sa_sigaction = function;
216  act.sa_flags = flags;
217 
218  if (sigaction(signum, &act, NULL) != 0)
219  os::abort_errno("signal_register_signal: sigaction failed");
220 }
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 static void signal_thread(void)
232 {
233  threadobject *t;
234  sigset_t mask;
235  int sig;
236  int result;
237 
238  t = THREADOBJECT;
239 
240  if (sigemptyset(&mask) != 0)
241  os::abort_errno("signal_thread: sigemptyset failed");
242 
243 #if !defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
244  /* Let OpenJDK handle SIGINT itself. */
245 
246  if (sigaddset(&mask, SIGINT) != 0)
247  os::abort_errno("signal_thread: sigaddset failed");
248 #endif
249 
250 #if !defined(__FREEBSD__)
251  if (sigaddset(&mask, SIGQUIT) != 0)
252  os::abort_errno("signal_thread: sigaddset failed");
253 #endif
254 
255  for (;;) {
256  /* just wait for a signal */
257 
259 
260  // sigwait can return EINTR (unlike what the Linux man-page
261  // says).
262  do {
263  result = sigwait(&mask, &sig);
264  } while (result == EINTR);
265 
266  if (result != 0)
267  os::abort_errnum(result, "signal_thread: sigwait failed");
268 
270 
271  /* Handle the signal. */
272 
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 
286 {
287  switch (sig) {
288  case SIGINT:
289  /* exit the vm properly */
290 
291  vm_exit(1);
292  break;
293 
294  case SIGQUIT:
295  /* print a thread dump */
297 
298 #if 0 && defined(ENABLE_STATISTICS)
299  if (opt_stat)
300  statistics_print_memory_usage();
301 #endif
302  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);
313  vm_abort("signal_thread_handler: Aborting...");
314  }
315  break;
316  }
317 #else
318  default:
319  vm_abort("signal_thread_handler: Unknown signal %d", sig);
320 #endif
321  }
322 }
323 
324 
325 /* signal_start_thread *********************************************************
326 
327  Starts the signal handler thread.
328 
329 *******************************************************************************/
330 
332 {
333  Utf8String name = Utf8String::from_utf8("Signal Handler");
334 
336  return false;
337 
338  /* everything's ok */
339 
340  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 void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p)
352 {
353  /* do nothing */
354 }
355 
356 
357 /* signal_handler_sigusr1 ******************************************************
358 
359  Signal handler for suspending threads.
360 
361 *******************************************************************************/
362 
363 void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
364 {
365  // Really suspend ourselves by acknowledging the suspension.
367 }
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  */
void dump_threads()
Dumps info for all threads running in the VM.
Definition: threadlist.cpp:47
void exceptions_print_stacktrace(void)
#define GCNEW(type)
Definition: memory.hpp:117
static void signal_thread(void)
Definition: signal.cpp:231
static void abort_errno(const char *text,...)
Equal to abort_errnum, but uses errno to get the error number.
Definition: os.cpp:165
void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
NullPointerException signal handler for hardware null pointer check.
Definition: md-os.cpp:50
void thread_set_state_runnable(threadobject *t)
Definition: thread.cpp:754
void signal_register_signal(int signum, functionptr handler, int flags)
Definition: signal.cpp:204
bool signal_init(void)
Definition: signal.cpp:59
void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
Illegal Instruction signal handler for hardware exception checks.
Definition: md-os.cpp:65
bool opt_intrp
Definition: options.cpp:55
bool threads_thread_start_internal(Utf8String name, functionptr f)
Definition: thread.cpp:402
typedef void(JNICALL *jvmtiEventSingleStep)(jvmtiEnv *jvmti_env
java_handle_t * vm_call_method(methodinfo *m, java_handle_t *o,...)
JNIEnv jclass jobject const char * name
Definition: jvmti.h:312
void md_signal_handler_sigtrap(int sig, siginfo_t *siginfo, void *_p)
Signal handler for hardware-traps.
Definition: md-os.cpp:72
void log_println(const char *text,...)
Definition: logging.cpp:193
#define TRACESUBSYSTEMINITIALIZATION(text)
Definition: options.hpp:258
void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
Definition: md-os.cpp:59
static void abort_errnum(int errnum, const char *text,...)
Prints an error message, appends &quot;:&quot; plus the strerror-message of errnum and aborts the VM...
Definition: os.cpp:150
void vm_abort(const char *text,...)
Definition: vm.cpp:2586
void(* functionptr)(void)
Definition: global.hpp:39
void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
Definition: md-os.cpp:83
void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
Definition: signal.cpp:363
static ThreadList * get()
Provides access to singleton.
Definition: threadlist.hpp:62
methodinfo * class_resolvemethod(classinfo *c, Utf8String name, Utf8String desc)
Definition: class.cpp:1145
void vm_exit(s4 status)
Definition: vm.cpp:1807
static Utf8String from_utf8(const char *, size_t)
Definition: utf8.cpp:335
void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p)
Definition: signal.cpp:351
void threads_suspend_ack()
java_handle_t * exceptions_get_exception(void)
Definition: exceptions.cpp:76
#define Signal_INTERRUPT_SYSTEM_CALL
Definition: signallocal.hpp:43
void thread_set_state_waiting(threadobject *t)
Definition: thread.cpp:773
bool signal_start_thread(void)
Definition: signal.cpp:331
#define THREADOBJECT
Definition: thread-none.hpp:47
void signal_thread_handler(int sig)
Definition: signal.cpp:285