https://github.com/JuliaLang/julia
Tip revision: bb73f3489d837e3339fce2c1aab283d3b2e97a4c authored by Tony Kelman on 06 December 2015, 21:47:01 UTC
Tag v0.4.2
Tag v0.4.2
Tip revision: bb73f34
signals-unix.c
// This file is a part of Julia. License is MIT: http://julialang.org/license
void fpe_handler(int arg)
{
(void)arg;
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, SIGFPE);
sigprocmask(SIG_UNBLOCK, &sset, NULL);
jl_throw(jl_diverror_exception);
}
static int is_addr_on_stack(void *addr)
{
#ifdef COPY_STACKS
return ((char*)addr > (char*)jl_stack_lo-3000000 &&
(char*)addr < (char*)jl_stack_hi);
#else
return ((char*)addr > (char*)jl_current_task->stack-8192 &&
(char*)addr < (char*)jl_current_task->stack+jl_current_task->ssize);
#endif
}
#ifndef SIGINFO
#define SIGINFO SIGUSR1
#endif
void sigdie_handler(int sig, siginfo_t *info, void *context)
{
if (sig != SIGINFO) {
sigset_t sset;
uv_tty_reset_mode();
sigfillset(&sset);
sigprocmask(SIG_UNBLOCK, &sset, NULL);
signal(sig, SIG_DFL);
}
jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig));
#ifdef __APPLE__
bt_size = rec_backtrace_ctx(bt_data, MAX_BT_SIZE, (bt_context_t)&((ucontext64_t*)context)->uc_mcontext64->__ss);
#else
bt_size = rec_backtrace_ctx(bt_data, MAX_BT_SIZE, (ucontext_t*)context);
#endif
jlbacktrace();
gc_debug_print_status();
if (sig != SIGSEGV &&
sig != SIGBUS &&
sig != SIGILL &&
sig != SIGINFO) {
raise(sig);
}
}
#ifndef __APPLE__ // Apple handles this from a separate thread (catch_exception_raise)
extern int in_jl_;
void segv_handler(int sig, siginfo_t *info, void *context)
{
sigset_t sset;
assert(sig == SIGSEGV);
if (in_jl_ || is_addr_on_stack(info->si_addr)) { // stack overflow, or restarting jl_
sigemptyset(&sset);
sigaddset(&sset, SIGSEGV);
sigprocmask(SIG_UNBLOCK, &sset, NULL);
jl_throw(jl_stackovf_exception);
}
else if (info->si_code == SEGV_ACCERR) { // writing to read-only memory (e.g., mmap)
sigemptyset(&sset);
sigaddset(&sset, SIGSEGV);
sigprocmask(SIG_UNBLOCK, &sset, NULL);
jl_throw(jl_readonlymemory_exception);
}
else {
#ifdef SEGV_EXCEPTION
sigemptyset(&sset);
sigaddset(&sset, SIGSEGV);
sigprocmask(SIG_UNBLOCK, &sset, NULL);
jl_throw(jl_segv_exception);
#else
sigdie_handler(sig, info, context);
#endif
}
}
#endif
void restore_signals(void)
{
sigset_t sset;
sigemptyset(&sset);
sigprocmask(SIG_SETMASK, &sset, 0);
}
void sigint_handler(int sig, siginfo_t *info, void *context)
{
if (jl_defer_signal) {
jl_signal_pending = sig;
}
else {
jl_signal_pending = 0;
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, SIGINT);
sigprocmask(SIG_UNBLOCK, &sset, NULL);
jl_sigint_action();
}
}
DLLEXPORT void jl_install_sigint_handler(void)
{
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_sigaction = sigint_handler;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGINT, &act, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
}
void jl_install_default_signal_handlers(void)
{
#if defined(__linux__) && defined(JL_USE_INTEL_JITEVENTS)
if (jl_using_intel_jitevents)
// Intel VTune Amplifier needs at least 64k for alternate stack.
if (SIGSTKSZ < 1<<16)
sig_stack_size = 1<<16;
#endif
signal_stack = malloc(sig_stack_size);
struct sigaction actf;
memset(&actf, 0, sizeof(struct sigaction));
sigemptyset(&actf.sa_mask);
actf.sa_handler = fpe_handler;
actf.sa_flags = 0;
if (sigaction(SIGFPE, &actf, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) {
jl_error("fatal error: Couldn't set SIGPIPE");
}
#if defined (_OS_DARWIN_)
kern_return_t ret;
mach_port_t self = mach_task_self();
ret = mach_port_allocate(self,MACH_PORT_RIGHT_RECEIVE,&segv_port);
HANDLE_MACH_ERROR("mach_port_allocate",ret);
ret = mach_port_insert_right(self,segv_port,segv_port,MACH_MSG_TYPE_MAKE_SEND);
HANDLE_MACH_ERROR("mach_port_insert_right",ret);
// Alright, create a thread to serve as the listener for exceptions
pthread_t thread;
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0) {
jl_error("pthread_attr_init failed");
}
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
if (pthread_create(&thread,&attr,mach_segv_listener,NULL) != 0) {
jl_error("pthread_create failed");
}
pthread_attr_destroy(&attr);
attach_exception_port();
#else // defined(_OS_DARWIN_)
stack_t ss;
ss.ss_flags = 0;
ss.ss_size = sig_stack_size;
ss.ss_sp = signal_stack;
if (sigaltstack(&ss, NULL) < 0) {
jl_errorf("fatal error: sigaltstack: %s", strerror(errno));
}
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_sigaction = segv_handler;
act.sa_flags = SA_ONSTACK | SA_SIGINFO;
if (sigaction(SIGSEGV, &act, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
#endif // defined(_OS_DARWIN_)
struct sigaction act_die;
memset(&act_die, 0, sizeof(struct sigaction));
sigemptyset(&act_die.sa_mask);
act_die.sa_sigaction = sigdie_handler;
act_die.sa_flags = SA_SIGINFO;
if (sigaction(SIGINFO, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGBUS, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGILL, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGTERM, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGABRT, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGQUIT, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
if (sigaction(SIGSYS, &act_die, NULL) < 0) {
jl_errorf("fatal error: sigaction: %s", strerror(errno));
}
}