summaryrefslogtreecommitdiffstats
path: root/asmrun/signals_asm.c
diff options
context:
space:
mode:
Diffstat (limited to 'asmrun/signals_asm.c')
-rw-r--r--asmrun/signals_asm.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/asmrun/signals_asm.c b/asmrun/signals_asm.c
new file mode 100644
index 000000000..639fbd4d1
--- /dev/null
+++ b/asmrun/signals_asm.c
@@ -0,0 +1,256 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Xavier Leroy, projet Gallium, INRIA Rocquencourt */
+/* */
+/* Copyright 2007 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file ../LICENSE. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+/* Signal handling, code specific to the native-code compiler */
+
+#if defined(TARGET_amd64) && defined (SYS_linux)
+#define _GNU_SOURCE
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include "fail.h"
+#include "memory.h"
+#include "osdeps.h"
+#include "signals.h"
+#include "signals_machdep.h"
+#include "signals_osdep.h"
+#include "stack.h"
+
+#ifdef HAS_STACK_OVERFLOW_DETECTION
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+#ifndef NSIG
+#define NSIG 64
+#endif
+
+typedef void (*signal_handler)(int signo);
+
+#ifdef _WIN32
+extern signal_handler caml_win32_signal(int sig, signal_handler action);
+#define signal(sig,act) caml_win32_signal(sig,act)
+extern void caml_win32_overflow_detection();
+#endif
+
+extern char * caml_code_area_start, * caml_code_area_end;
+
+#define In_code_area(pc) \
+ ((char *)(pc) >= caml_code_area_start && \
+ (char *)(pc) <= caml_code_area_end)
+
+/* This routine is the common entry point for garbage collection
+ and signal handling. It can trigger a callback to Caml code.
+ With system threads, this callback can cause a context switch.
+ Hence [caml_garbage_collection] must not be called from regular C code
+ (e.g. the [caml_alloc] function) because the context of the call
+ (e.g. [intern_val]) may not allow context switching.
+ Only generated assembly code can call [caml_garbage_collection],
+ via the caml_call_gc assembly stubs. */
+
+void caml_garbage_collection(void)
+{
+ caml_young_limit = caml_young_start;
+ if (caml_young_ptr < caml_young_start || caml_force_major_slice) {
+ caml_minor_collection();
+ }
+ caml_process_pending_signals();
+}
+
+DECLARE_SIGNAL_HANDLER(handle_signal)
+{
+#if !defined(POSIX_SIGNALS) && !defined(BSD_SIGNALS)
+ signal(sig, handle_signal);
+#endif
+ if (sig < 0 || sig >= NSIG) return;
+ if (caml_try_leave_blocking_section_hook ()) {
+ caml_execute_signal(sig, 1);
+ caml_enter_blocking_section_hook();
+ } else {
+ caml_record_signal(sig);
+ /* Some ports cache [caml_young_limit] in a register.
+ Use the signal context to modify that register too, but only if
+ we are inside Caml code (not inside C code). */
+#if defined(CONTEXT_PC) && defined(CONTEXT_YOUNG_LIMIT)
+ if (In_code_area(CONTEXT_PC))
+ CONTEXT_YOUNG_LIMIT = (context_reg) caml_young_limit;
+#endif
+ }
+}
+
+int caml_set_signal_action(int signo, int action)
+{
+ signal_handler oldact;
+#ifdef POSIX_SIGNALS
+ struct sigaction sigact, oldsigact;
+#else
+ signal_handler act;
+#endif
+
+#ifdef POSIX_SIGNALS
+ switch(action) {
+ case 0:
+ sigact.sa_handler = SIG_DFL;
+ sigact.sa_flags = 0;
+ break;
+ case 1:
+ sigact.sa_handler = SIG_IGN;
+ sigact.sa_flags = 0;
+ break;
+ default:
+ SET_SIGACT(sigact, handle_signal);
+ break;
+ }
+ sigemptyset(&sigact.sa_mask);
+ if (sigaction(signo, &sigact, &oldsigact) == -1) return -1;
+ oldact = oldsigact.sa_handler;
+#else
+ switch(action) {
+ case 0: act = SIG_DFL; break;
+ case 1: act = SIG_IGN; break;
+ default: act = handle_signal; break;
+ }
+ oldact = signal(signo, act);
+ if (oldact == SIG_ERR) return -1;
+#endif
+ if (oldact == (signal_handler) handle_signal)
+ return 2;
+ else if (oldact == SIG_IGN)
+ return 1;
+ else
+ return 0;
+}
+
+/* Machine- and OS-dependent handling of bound check trap */
+
+#if defined(TARGET_power) || (defined(TARGET_sparc) && defined(SYS_solaris))
+DECLARE_SIGNAL_HANDLER(trap_handler)
+{
+#if defined(SYS_solaris)
+ if (info->si_code != ILL_ILLTRP) {
+ /* Deactivate our exception handler and return. */
+ struct sigaction act;
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ sigaction(sig, &act, NULL);
+ return;
+ }
+#endif
+#if defined(SYS_rhapsody)
+ /* Unblock SIGTRAP */
+ { sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTRAP);
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ }
+#endif
+ caml_exception_pointer = (char *) CONTEXT_EXCEPTION_POINTER;
+ caml_young_ptr = (char *) CONTEXT_YOUNG_PTR;
+#if defined(SYS_rhapsody)
+ caml_bottom_of_stack = (char *) CONTEXT_SP;
+ caml_last_return_address = (uintnat) CONTEXT_PC;
+#endif
+ caml_array_bound_error();
+}
+#endif
+
+/* Machine- and OS-dependent handling of stack overflow */
+
+#ifdef HAS_STACK_OVERFLOW_DETECTION
+
+static char * system_stack_top;
+static char sig_alt_stack[SIGSTKSZ];
+
+DECLARE_SIGNAL_HANDLER(segv_handler)
+{
+ struct rlimit limit;
+ struct sigaction act;
+ char * fault_addr;
+
+ /* Sanity checks:
+ - faulting address is word-aligned
+ - faulting address is within the stack
+ - we are in Caml code */
+ fault_addr = CONTEXT_FAULTING_ADDRESS;
+ if (((uintnat) fault_addr & (sizeof(intnat) - 1)) == 0
+ && getrlimit(RLIMIT_STACK, &limit) == 0
+ && fault_addr < system_stack_top
+ && fault_addr >= system_stack_top - limit.rlim_cur - 0x2000
+#ifdef CONTEXT_PC
+ && In_code_area(CONTEXT_PC)
+#endif
+ ) {
+ /* Turn this into a Stack_overflow exception */
+#if defined(CONTEXT_YOUNG_PTR) && defined(CONTEXT_EXCEPTION_POINTER)
+ caml_exception_pointer = (char *) CONTEXT_EXCEPTION_POINTER;
+ caml_young_ptr = (char *) CONTEXT_YOUNG_PTR;
+#endif
+ caml_raise_stack_overflow();
+ }
+ /* Otherwise, deactivate our exception handler and return,
+ causing fatal signal to be generated at point of error. */
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ sigaction(SIGSEGV, &act, NULL);
+}
+
+#endif
+
+/* Initialization of signal stuff */
+
+void caml_init_signals(void)
+{
+ /* Bound-check trap handling */
+#if defined(TARGET_sparc) && defined(SYS_solaris)
+ { struct sigaction act;
+ sigemptyset(&act.sa_mask);
+ SET_SIGACT(act, trap_handler);
+ act.sa_flags |= SA_NODEFER;
+ sigaction(SIGILL, &act, NULL);
+ }
+#endif
+
+#if defined(TARGET_power)
+ { struct sigaction act;
+ sigemptyset(&act.sa_mask);
+ SET_SIGACT(act, trap_handler);
+#if !defined(SYS_rhapsody)
+ act.sa_flags |= SA_NODEFER;
+#endif
+ sigaction(SIGTRAP, &act, NULL);
+ }
+#endif
+
+ /* Stack overflow handling */
+#ifdef HAS_STACK_OVERFLOW_DETECTION
+ {
+ struct sigaltstack stk;
+ struct sigaction act;
+ stk.ss_sp = sig_alt_stack;
+ stk.ss_size = SIGSTKSZ;
+ stk.ss_flags = 0;
+ SET_SIGACT(act, segv_handler);
+ act.sa_flags |= SA_ONSTACK | SA_NODEFER;
+ sigemptyset(&act.sa_mask);
+ system_stack_top = (char *) &act;
+ if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); }
+ }
+#endif
+#ifdef _WIN32
+ caml_win32_overflow_detection();
+#endif
+}