* src/vm/exceptions.c (exceptions_get_exception)
[cacao.git] / src / vm / signal.c
index b3cc69d818cddf55a24ba5f5115ccaaf2f347fa0..9907374092ebb65588927aaed6d3f969ca0c3e31 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/signal.c - machine independent signal functions
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
    J. Wenninger, Institut f. Computersprachen - TU Wien
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Christian Thalinger
-
-   Changes:
-
-   $Id: signal.c 5805 2006-10-19 09:32:29Z twisti $
+   $Id: signal.c 8005 2007-06-04 13:12:56Z twisti $
 
 */
 
 
 #include "config.h"
 
+#include <assert.h>
+#include <errno.h>
 #include <signal.h>
 #include <stdlib.h>
 
+#if defined(__DARWIN__)
+/* If we compile with -ansi on darwin, <sys/types.h> is not
+ included. So let's do it here. */
+# include <sys/types.h>
+#endif
+
 #include "vm/types.h"
 
+#include "arch.h"
+
+#include "mm/memory.h"
+
 #if defined(ENABLE_THREADS)
-# include "threads/native/threads.h"
+# include "threads/threads-common.h"
+#else
+# include "threads/none/threads.h"
 #endif
 
+#include "vm/exceptions.h"
 #include "vm/signallocal.h"
-#include "vm/options.h"
 #include "vm/vm.h"
-#include "vm/jit/stacktrace.h"
+
+#include "vmcore/options.h"
+
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
+#endif
 
 
 /* function prototypes ********************************************************/
 
-void signal_handler_sigquit(int sig, siginfo_t *siginfo, void *_p);
-void signal_handler_sigint(int sig, siginfo_t *siginfo, void *_p);
+void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p);
 
 
 /* signal_init *****************************************************************
@@ -62,114 +74,233 @@ void signal_handler_sigint(int sig, siginfo_t *siginfo, void *_p);
 
 *******************************************************************************/
 
-void signal_init(void)
+bool signal_init(void)
 {
 #if !defined(__CYGWIN__)
+       sigset_t         mask;
        struct sigaction act;
 
-       /* install signal handlers we need to convert to exceptions */
+#if defined(__LINUX__) && defined(ENABLE_THREADS)
+       /* XXX Remove for exact-GC. */
+       if (threads_pthreads_implementation_nptl) {
+#endif
 
-       sigemptyset(&act.sa_mask);
+       /* Block the following signals (SIGINT for <ctrl>-c, SIGQUIT for
+          <ctrl>-\).  We enable them later in signal_thread, but only for
+          this thread. */
 
+       if (sigemptyset(&mask) != 0)
+               vm_abort("signal_init: sigemptyset failed: %s", strerror(errno));
 
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
-       if (!opt_intrp) {
-# endif
-               /* catch NullPointerException/StackOverFlowException */
+       if (sigaddset(&mask, SIGINT) != 0)
+               vm_abort("signal_init: sigaddset failed: %s", strerror(errno));
 
-               if (!checknull) {
-                       act.sa_sigaction = md_signal_handler_sigsegv;
-                       act.sa_flags = SA_NODEFER | SA_SIGINFO;
+#if !defined(__FREEBSD__)
+       if (sigaddset(&mask, SIGQUIT) != 0)
+               vm_abort("signal_init: sigaddset failed: %s", strerror(errno));
+#endif
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0)
+               vm_abort("signal_init: sigprocmask failed: %s", strerror(errno));
 
-#if defined(SIGSEGV)
-                       sigaction(SIGSEGV, &act, NULL);
+#if defined(__LINUX__) && defined(ENABLE_THREADS)
+       /* XXX Remove for exact-GC. */
+       }
 #endif
 
-#if defined(SIGBUS)
-                       sigaction(SIGBUS, &act, NULL);
+#if defined(ENABLE_GC_BOEHM)
+       /* Allocate something so the garbage collector's signal handlers
+          are installed. */
+
+       (void) GCNEW(u1);
 #endif
-               }
 
+       /* Install signal handlers for signals we want to catch in all
+          threads. */
 
-               /* catch ArithmeticException */
+       sigemptyset(&act.sa_mask);
 
-#if defined(__I386__) || defined(__X86_64__)
-               act.sa_sigaction = md_signal_handler_sigfpe;
-               act.sa_flags = SA_NODEFER | SA_SIGINFO;
-               sigaction(SIGFPE, &act, NULL);
-#endif
+#if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
-       }
+       if (!opt_intrp) {
 # endif
-#endif /* !defined(ENABLE_INTRP) */
+               /* SIGSEGV handler */
+
+               act.sa_sigaction = md_signal_handler_sigsegv;
+               act.sa_flags     = SA_NODEFER | SA_SIGINFO;
+
+#  if defined(SIGSEGV)
+               sigaction(SIGSEGV, &act, NULL);
+#  endif
 
+#  if defined(SIGBUS)
+               sigaction(SIGBUS, &act, NULL);
+#  endif
 
-       /* catch SIGINT for exiting properly on <ctrl>-c */
+#  if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+               /* SIGFPE handler */
 
-       act.sa_sigaction = signal_handler_sigint;
-       act.sa_flags = SA_NODEFER | SA_SIGINFO;
-       sigaction(SIGINT, &act, NULL);
+               act.sa_sigaction = md_signal_handler_sigfpe;
+               act.sa_flags     = SA_NODEFER | SA_SIGINFO;
+               sigaction(SIGFPE, &act, NULL);
+#  endif
 
+#  if defined(__ARM__) || defined(__S390__)
+               /* XXX use better defines for that (in arch.h) */
+               /* SIGILL handler */
 
-       /* catch SIGQUIT for thread dump */
+               act.sa_sigaction = md_signal_handler_sigill;
+               act.sa_flags     = SA_NODEFER | SA_SIGINFO;
+               sigaction(SIGILL, &act, NULL);
+#  endif
 
-#if defined(ENABLE_THREADS)
-# if !defined(__FREEBSD__)
-       act.sa_sigaction = signal_handler_sigquit;
-       act.sa_flags = SA_SIGINFO;
-       sigaction(SIGQUIT, &act, NULL);
+#  if defined(__POWERPC__)
+               /* XXX use better defines for that (in arch.h) */
+               /* SIGTRAP handler */
+
+               act.sa_sigaction = md_signal_handler_sigtrap;
+               act.sa_flags     = SA_NODEFER | SA_SIGINFO;
+               sigaction(SIGTRAP, &act, NULL);
+#  endif
+# if defined(ENABLE_INTRP)
+       }
 # endif
+#endif /* !defined(ENABLE_INTRP) */
+
+#if defined(ENABLE_THREADS)
+       /* SIGHUP handler for threads_thread_interrupt */
+
+       act.sa_sigaction = signal_handler_sighup;
+       act.sa_flags     = 0;
+       sigaction(SIGHUP, &act, NULL);
 #endif
 
 #if defined(ENABLE_THREADS) && defined(ENABLE_PROFILING)
-       /* install signal handler for profiling sampling */
+       /* SIGUSR2 handler for profiling sampling */
 
        act.sa_sigaction = md_signal_handler_sigusr2;
-       act.sa_flags = SA_SIGINFO;
+       act.sa_flags     = SA_SIGINFO;
        sigaction(SIGUSR2, &act, NULL);
 #endif
 
 #endif /* !defined(__CYGWIN__) */
+
+       return true;
 }
 
 
-/* signal_handler_sigquit ******************************************************
+/* signal_thread ************************************************************
 
-   XXX
+   This thread sets the signal mask to catch the user input signals
+   (SIGINT, SIGQUIT).  We use such a thread, so we don't get the
+   signals on every single thread running.
 
 *******************************************************************************/
 
-#if defined(ENABLE_THREADS)
-void signal_handler_sigquit(int sig, siginfo_t *siginfo, void *_p)
+static void signal_thread(void)
 {
-       /* do thread dump */
+       threadobject *t;
+       sigset_t      mask;
+       int           sig;
 
-       threads_dump();
-}
+       t = THREADOBJECT;
+
+       if (sigemptyset(&mask) != 0)
+               vm_abort("signal_thread: sigemptyset failed: %s", strerror(errno));
+
+       if (sigaddset(&mask, SIGINT) != 0)
+               vm_abort("signal_thread: sigaddset failed: %s", strerror(errno));
+
+#if !defined(__FREEBSD__)
+       if (sigaddset(&mask, SIGQUIT) != 0)
+               vm_abort("signal_thread: sigaddset failed: %s", strerror(errno));
 #endif
 
+       while (true) {
+               /* just wait for a signal */
 
-/* signal_handler_sigint *******************************************************
+               /* XXX We don't check for an error here, although the man-page
+                  states sigwait does not return an error (which is wrong!),
+                  but it seems to make problems with Boehm-GC.  We should
+                  revisit this code with our new exact-GC. */
 
-   Handler for SIGINT (<ctrl>-c) which shuts down CACAO properly with
-   Runtime.exit(I)V.
+#if defined(ENABLE_THREADS)
+               threads_thread_state_waiting(t);
+#endif
+
+/*             if (sigwait(&mask, &sig) != 0) */
+/*                     vm_abort("signal_thread: sigwait failed: %s", strerror(errno)); */
+               (void) sigwait(&mask, &sig);
+
+#if defined(ENABLE_THREADS)
+               threads_thread_state_runnable(t);
+#endif
+
+               switch (sig) {
+               case SIGINT:
+                       /* exit the vm properly */
+
+                       vm_exit(0);
+                       break;
+
+               case SIGQUIT:
+                       /* print a thread dump */
+#if defined(ENABLE_THREADS)
+                       threads_dump();
+#endif
+
+#if defined(ENABLE_STATISTICS)
+                       if (opt_stat)
+                               statistics_print_memory_usage();
+#endif
+                       break;
+               }
+       }
+
+       /* this should not happen */
+
+       vm_abort("signal_thread: this thread should not exit!");
+}
+
+
+/* signal_start_thread *********************************************************
+
+   Starts the signal handler thread.
 
 *******************************************************************************/
 
-void signal_handler_sigint(int sig, siginfo_t *siginfo, void *_p)
+bool signal_start_thread(void)
 {
-       /* if we are already in Runtime.exit(), just do it hardcore */
+#if defined(ENABLE_THREADS)
+       utf *name;
 
-       if (vm_exiting) {
-               fprintf(stderr, "Caught SIGINT while already shutting down. Shutdown aborted...\n");
-               exit(0);
-       }
+       name = utf_new_char("Signal Handler");
+
+       if (!threads_thread_start_internal(name, signal_thread))
+               return false;
+
+       /* everything's ok */
 
-       /* exit the vm properly */
+       return true;
+#else
+#warning FIX ME!
+#endif
+}
+
+
+/* signal_handler_sighup *******************************************************
+
+   This handler is required by threads_thread_interrupt and does
+   nothing.
 
-       vm_exit(0);
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p)
+{
+       /* do nothing */
 }
+#endif
 
 
 /*