* Merged in twisti-branch.
[cacao.git] / src / vm / signal.c
index 4529ea3865a3be373ef2762a397ac1ab58915322..f9cc702ec2b8d950736ee0c76189ce43ccef4f7d 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 4530 2006-02-21 09:11:53Z twisti $
+   $Id: signal.c 7592 2007-03-28 20:12:33Z twisti $
 
 */
 
 
 #include "config.h"
 
+#include <errno.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.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"
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-# include "threads/native/threads.h"
+#include "arch.h"
+
+#include "mm/memory.h"
+
+#if defined(ENABLE_THREADS)
+# include "threads/threads-common.h"
 #endif
 
 #include "vm/signallocal.h"
-#include "vm/options.h"
 #include "vm/vm.h"
-#include "vm/jit/stacktrace.h"
+
+#include "vmcore/options.h"
+
+
+/* global variables ***********************************************************/
+
+#if defined(ENABLE_THREADS)
+static threadobject *thread_signal;
+#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_sigusr1(int sig, siginfo_t *siginfo, void *_p);
+void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p);
 
 
 /* signal_init *****************************************************************
@@ -65,122 +77,211 @@ void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p);
 
 void signal_init(void)
 {
+#if !defined(__CYGWIN__)
+       int              pagesize;
+       sigset_t         mask;
        struct sigaction act;
 
-       /* install signal handlers we need to convert to exceptions */
+       /* mmap a memory page at address 0x0, so our hardware-exceptions
+          work. */
 
-       sigemptyset(&act.sa_mask);
+       pagesize = getpagesize();
+
+       (void) memory_mmap_anon(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
+
+       /* 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 (sigaddset(&mask, SIGINT) != 0)
+               vm_abort("signal_init: sigaddset failed: %s", strerror(errno));
+
+#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(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. */
+
+       sigemptyset(&act.sa_mask);
 
 #if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
        if (!opt_intrp) {
 # endif
-               /* catch NullPointerException/StackOverFlowException */
+               /* SIGSEGV handler */
 
-               if (!checknull) {
-                       act.sa_sigaction = md_signal_handler_sigsegv;
-                       act.sa_flags = SA_NODEFER | SA_SIGINFO;
-
-#if defined(SIGSEGV)
-                       sigaction(SIGSEGV, &act, NULL);
-#endif
+               act.sa_sigaction = md_signal_handler_sigsegv;
+               act.sa_flags     = SA_NODEFER | SA_SIGINFO;
 
-#if defined(SIGBUS)
-                       sigaction(SIGBUS, &act, NULL);
-#endif
-               }
+#  if defined(SIGSEGV)
+               sigaction(SIGSEGV, &act, NULL);
+#  endif
 
+#  if defined(SIGBUS)
+               sigaction(SIGBUS, &act, NULL);
+#  endif
 
-               /* catch ArithmeticException */
+#  if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+               /* SIGFPE handler */
 
-#if defined(__I386__) || defined(__X86_64__)
                act.sa_sigaction = md_signal_handler_sigfpe;
-               act.sa_flags = SA_NODEFER | SA_SIGINFO;
+               act.sa_flags     = SA_NODEFER | SA_SIGINFO;
                sigaction(SIGFPE, &act, NULL);
-#endif
+#  endif
+
+#  if defined(__ARM__)
+               /* XXX use better defines for that (in arch.h) */
+               /* SIGILL handler */
+
+               act.sa_sigaction = md_signal_handler_sigill;
+               act.sa_flags     = SA_NODEFER | SA_SIGINFO;
+               sigaction(SIGILL, &act, NULL);
+#  endif
+
+#  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 */
 
-       /* catch SIGINT for exiting properly on <ctrl>-c */
+       act.sa_sigaction = signal_handler_sighup;
+       act.sa_flags     = 0;
+       sigaction(SIGHUP, &act, NULL);
+#endif
 
-       act.sa_sigaction = signal_handler_sigint;
-       act.sa_flags = SA_NODEFER | SA_SIGINFO;
-       sigaction(SIGINT, &act, NULL);
+#if defined(ENABLE_THREADS) && defined(ENABLE_PROFILING)
+       /* SIGUSR2 handler for profiling sampling */
 
+       act.sa_sigaction = md_signal_handler_sigusr2;
+       act.sa_flags     = SA_SIGINFO;
+       sigaction(SIGUSR2, &act, NULL);
+#endif
 
+#endif /* !defined(__CYGWIN__) */
+}
 
-       /* catch SIGQUIT for thread dump */
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-#if !defined(__FREEBSD__)
-       act.sa_sigaction = signal_handler_sigquit;
-       act.sa_flags = SA_SIGINFO;
-       sigaction(SIGQUIT, &act, NULL);
+/* signal_thread ************************************************************
 
-       /* XXX boehm uses SIGUSR1 for suspend on freebsd */
+   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.  Especially, this makes
+   problems on slow machines.
 
-       act.sa_sigaction = signal_handler_sigusr1;
-       act.sa_flags = SA_SIGINFO;
-       sigaction(SIGUSR1, &act, NULL);
-#endif
+*******************************************************************************/
+
+static void signal_thread(void)
+{
+       sigset_t mask;
+       int      sig;
+
+       if (sigemptyset(&mask) != 0)
+               vm_abort("signal_thread: sigemptyset failed: %s", strerror(errno));
+
+       sigaddset(&mask, SIGINT);
+#if !defined(__FREEBSD__)
+       sigaddset(&mask, SIGQUIT);
 #endif
-}
 
+       while (true) {
+               /* just wait for a signal */
 
-/* signal_handler_sigquit ******************************************************
+               (void) sigwait(&mask, &sig);
 
-   XXX
+               switch (sig) {
+               case SIGINT:
+                       /* exit the vm properly */
 
-*******************************************************************************/
+                       vm_exit(0);
+                       break;
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-void signal_handler_sigquit(int sig, siginfo_t *siginfo, void *_p)
-{
-       /* do thread dump */
+               case SIGQUIT:
+                       /* print a thread dump */
+#if defined(ENABLE_THREADS)
+                       threads_dump();
+#endif
 
-       threads_dump();
-}
+#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_handler_sigint *******************************************************
+/* signal_start_thread *********************************************************
 
-   Handler for SIGINT (<ctrl>-c) which shuts down CACAO properly with
-   Runtime.exit(I)V.
+   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");
+
+       thread_signal = threads_create_thread(name);
+
+       if (thread_signal == NULL)
+               return false;
+
+       /* actually start the signal handler thread */
 
-       /* exit the vm properly */
+       threads_start_thread(thread_signal, signal_thread);
 
-       vm_exit(0);
+       /* everything's ok */
+
+       return true;
+#else
+#warning FIX ME!
+#endif
 }
 
 
-/* signal_handler_sigusr1 ******************************************************
+/* signal_handler_sighup *******************************************************
 
-   XXX
+   This handler is required by threads_thread_interrupt and does
+   nothing.
 
 *******************************************************************************/
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
+#if defined(ENABLE_THREADS)
+void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p)
 {
-       /* call stacktrace function */
-
-       stacktrace_dump_trace();
+       /* do nothing */
 }
 #endif