vm: fep on SIGINT or SIGQUIT instead of exception
It's not robust currently to raise an exception because a lot of our code that isn't already written with exceptions in mind breaks. Also, a signal is likely to be received by an FFI callback installed on the IO multiplexer, which will cause Factor to die since the callback cannot handle the exception. We need a more robust solution to dealing with SIGINT. Also lay some groundwork for counting profile samples and reporting non-interrupting asynchronous signals.db4
parent
1dc31d133b
commit
dc42365007
|
@ -352,6 +352,7 @@ void factor_vm::factorbug()
|
|||
}
|
||||
|
||||
/* open_console(); */
|
||||
fep_p = true;
|
||||
|
||||
std::cout << "Starting low level debugger...\n";
|
||||
std::cout << " Basic commands:\n";
|
||||
|
@ -446,7 +447,10 @@ void factor_vm::factorbug()
|
|||
else if(strcmp(cmd,"g") == 0)
|
||||
dump_generations();
|
||||
else if(strcmp(cmd,"q") == 0)
|
||||
{
|
||||
fep_p = false;
|
||||
return;
|
||||
}
|
||||
else if(strcmp(cmd,"x") == 0)
|
||||
exit(1);
|
||||
else if(strcmp(cmd,"im") == 0)
|
||||
|
|
|
@ -156,19 +156,39 @@ void fp_signal_handler_impl()
|
|||
current_vm()->fp_signal_handler_impl();
|
||||
}
|
||||
|
||||
void factor_vm::enqueue_safepoint_fep()
|
||||
{
|
||||
if (fep_p)
|
||||
fatal_error("Low-level debugger interrupted", 0);
|
||||
safepoint_fep = true;
|
||||
code->guard_safepoint();
|
||||
}
|
||||
|
||||
void factor_vm::enqueue_safepoint_signal(cell signal)
|
||||
{
|
||||
safepoint_signal_number = signal;
|
||||
sigaddset(&safepoint_signals, signal);
|
||||
code->guard_safepoint();
|
||||
}
|
||||
|
||||
void factor_vm::enqueue_safepoint_sample()
|
||||
{
|
||||
if (!sampling_p)
|
||||
fatal_error("Received sampling signal while not sampling!", 0);
|
||||
++safepoint_sample_count;
|
||||
}
|
||||
|
||||
void factor_vm::handle_safepoint()
|
||||
{
|
||||
assert(safepoint_signal_number != 0);
|
||||
code->unguard_safepoint();
|
||||
cell signal = safepoint_signal_number;
|
||||
safepoint_signal_number = 0;
|
||||
general_error(ERROR_SIGNAL,from_unsigned_cell(signal),false_object);
|
||||
if (safepoint_fep) {
|
||||
std::cout << "Interrupted. Entering low-level debugger...\n";
|
||||
std::cout << "\n";
|
||||
factorbug();
|
||||
code->unguard_safepoint();
|
||||
safepoint_fep = false;
|
||||
return;
|
||||
}
|
||||
// XXX handle sample count
|
||||
// XXX handle queued signals
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ void synchronous_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
|||
fatal_error("Foreign thread received signal ", signal);
|
||||
}
|
||||
|
||||
void next_safepoint_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||
void enqueue_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||
{
|
||||
factor_vm *vm = current_vm_p();
|
||||
if (vm)
|
||||
|
@ -176,6 +176,24 @@ void next_safepoint_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
|||
fatal_error("Foreign thread received signal ", signal);
|
||||
}
|
||||
|
||||
void fep_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||
{
|
||||
factor_vm *vm = current_vm_p();
|
||||
if (vm)
|
||||
vm->enqueue_safepoint_fep();
|
||||
else
|
||||
fatal_error("Foreign thread received signal ", signal);
|
||||
}
|
||||
|
||||
void sample_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||
{
|
||||
factor_vm *vm = current_vm_p();
|
||||
if (vm)
|
||||
vm->enqueue_safepoint_sample();
|
||||
else
|
||||
fatal_error("Foreign thread received signal ", signal);
|
||||
}
|
||||
|
||||
void ignore_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||
{
|
||||
}
|
||||
|
@ -206,6 +224,15 @@ static void sigaction_safe(int signum, const struct sigaction *act, struct sigac
|
|||
fatal_error("sigaction failed", 0);
|
||||
}
|
||||
|
||||
static void init_sigaction_with_handler(struct sigaction *act,
|
||||
void (*handler)(int, siginfo_t*, void*))
|
||||
{
|
||||
memset(act, 0, sizeof(struct sigaction));
|
||||
sigemptyset(&act->sa_mask);
|
||||
act->sa_sigaction = handler;
|
||||
act->sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
}
|
||||
|
||||
void factor_vm::unix_init_signals()
|
||||
{
|
||||
/* OpenBSD doesn't support sigaltstack() if we link against
|
||||
|
@ -225,53 +252,43 @@ void factor_vm::unix_init_signals()
|
|||
|
||||
struct sigaction memory_sigaction;
|
||||
struct sigaction synchronous_sigaction;
|
||||
struct sigaction next_safepoint_sigaction;
|
||||
struct sigaction enqueue_sigaction;
|
||||
struct sigaction fep_sigaction;
|
||||
struct sigaction sample_sigaction;
|
||||
struct sigaction fpe_sigaction;
|
||||
struct sigaction ignore_sigaction;
|
||||
|
||||
memset(&memory_sigaction,0,sizeof(struct sigaction));
|
||||
sigemptyset(&memory_sigaction.sa_mask);
|
||||
memory_sigaction.sa_sigaction = memory_signal_handler;
|
||||
memory_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
|
||||
init_sigaction_with_handler(&memory_sigaction, memory_signal_handler);
|
||||
sigaction_safe(SIGBUS,&memory_sigaction,NULL);
|
||||
sigaction_safe(SIGSEGV,&memory_sigaction,NULL);
|
||||
sigaction_safe(SIGTRAP,&memory_sigaction,NULL);
|
||||
|
||||
memset(&fpe_sigaction,0,sizeof(struct sigaction));
|
||||
sigemptyset(&fpe_sigaction.sa_mask);
|
||||
fpe_sigaction.sa_sigaction = fpe_signal_handler;
|
||||
fpe_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
|
||||
init_sigaction_with_handler(&fpe_sigaction, fpe_signal_handler);
|
||||
sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
|
||||
|
||||
memset(&synchronous_sigaction,0,sizeof(struct sigaction));
|
||||
sigemptyset(&synchronous_sigaction.sa_mask);
|
||||
synchronous_sigaction.sa_sigaction = synchronous_signal_handler;
|
||||
synchronous_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
|
||||
init_sigaction_with_handler(&synchronous_sigaction, synchronous_signal_handler);
|
||||
sigaction_safe(SIGILL,&synchronous_sigaction,NULL);
|
||||
sigaction_safe(SIGABRT,&synchronous_sigaction,NULL);
|
||||
|
||||
memset(&next_safepoint_sigaction,0,sizeof(struct sigaction));
|
||||
sigemptyset(&next_safepoint_sigaction.sa_mask);
|
||||
next_safepoint_sigaction.sa_sigaction = next_safepoint_signal_handler;
|
||||
next_safepoint_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
sigaction_safe(SIGALRM,&next_safepoint_sigaction,NULL);
|
||||
sigaction_safe(SIGVTALRM,&next_safepoint_sigaction,NULL);
|
||||
sigaction_safe(SIGPROF,&next_safepoint_sigaction,NULL);
|
||||
sigaction_safe(SIGQUIT,&next_safepoint_sigaction,NULL);
|
||||
sigaction_safe(SIGINT,&next_safepoint_sigaction,NULL);
|
||||
sigaction_safe(SIGUSR1,&next_safepoint_sigaction,NULL);
|
||||
sigaction_safe(SIGUSR2,&next_safepoint_sigaction,NULL);
|
||||
init_sigaction_with_handler(&enqueue_sigaction, enqueue_signal_handler);
|
||||
sigaction_safe(SIGUSR1,&enqueue_sigaction,NULL);
|
||||
sigaction_safe(SIGUSR2,&enqueue_sigaction,NULL);
|
||||
sigaction_safe(SIGWINCH,&enqueue_sigaction,NULL);
|
||||
#ifdef SIGINFO
|
||||
sigaction_safe(SIGINFO,&enqueue_sigaction,NULL);
|
||||
#endif
|
||||
|
||||
init_sigaction_with_handler(&fep_sigaction, fep_signal_handler);
|
||||
sigaction_safe(SIGQUIT,&fep_sigaction,NULL);
|
||||
sigaction_safe(SIGINT,&fep_sigaction,NULL);
|
||||
|
||||
init_sigaction_with_handler(&sample_sigaction, sample_signal_handler);
|
||||
sigaction_safe(SIGALRM,&sample_sigaction,NULL);
|
||||
|
||||
/* We don't use SA_IGN here because then the ignore action is inherited
|
||||
by subprocesses, which we don't want. There is a unit test in
|
||||
io.launcher.unix for this. */
|
||||
memset(&ignore_sigaction,0,sizeof(struct sigaction));
|
||||
sigemptyset(&ignore_sigaction.sa_mask);
|
||||
ignore_sigaction.sa_sigaction = ignore_signal_handler;
|
||||
ignore_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
init_sigaction_with_handler(&ignore_sigaction, ignore_signal_handler);
|
||||
sigaction_safe(SIGPIPE,&ignore_sigaction,NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,15 +8,19 @@ factor_vm::factor_vm() :
|
|||
callback_id(0),
|
||||
c_to_factor_func(NULL),
|
||||
profiling_p(false),
|
||||
safepoint_signal_number(0),
|
||||
sampling_p(false),
|
||||
safepoint_fep(false),
|
||||
safepoint_sample_count(0),
|
||||
gc_off(false),
|
||||
current_gc(NULL),
|
||||
gc_events(NULL),
|
||||
fep_p(false),
|
||||
fep_disabled(false),
|
||||
full_output(false),
|
||||
last_nano_count(0),
|
||||
signal_callstack_seg(NULL)
|
||||
{
|
||||
sigemptyset(&safepoint_signals);
|
||||
primitive_reset_dispatch_stats();
|
||||
}
|
||||
|
||||
|
|
11
vm/vm.hpp
11
vm/vm.hpp
|
@ -51,13 +51,17 @@ struct factor_vm
|
|||
|
||||
/* Is call counting enabled? */
|
||||
bool profiling_p;
|
||||
/* Is sampling profiler enabled? */
|
||||
bool sampling_p;
|
||||
|
||||
/* Global variables used to pass fault handler state from signal handler
|
||||
to VM */
|
||||
cell signal_number;
|
||||
cell signal_fault_addr;
|
||||
unsigned int signal_fpu_status;
|
||||
cell safepoint_signal_number;
|
||||
bool safepoint_fep;
|
||||
cell safepoint_sample_count;
|
||||
sigset_t safepoint_signals;
|
||||
|
||||
/* GC is off during heap walking */
|
||||
bool gc_off;
|
||||
|
@ -89,6 +93,7 @@ struct factor_vm
|
|||
std::vector<code_root *> code_roots;
|
||||
|
||||
/* Debugger */
|
||||
bool fep_p;
|
||||
bool fep_disabled;
|
||||
bool full_output;
|
||||
|
||||
|
@ -182,6 +187,8 @@ struct factor_vm
|
|||
void memory_signal_handler_impl();
|
||||
void synchronous_signal_handler_impl();
|
||||
void fp_signal_handler_impl();
|
||||
void enqueue_safepoint_fep();
|
||||
void enqueue_safepoint_sample();
|
||||
void enqueue_safepoint_signal(cell signal);
|
||||
void handle_safepoint();
|
||||
|
||||
|
@ -578,7 +585,6 @@ struct factor_vm
|
|||
template<typename Iterator> void iterate_callstack_object(callstack *stack_, Iterator &iterator);
|
||||
void check_frame(stack_frame *frame);
|
||||
callstack *allot_callstack(cell size);
|
||||
stack_frame *fix_callstack_top(stack_frame *top);
|
||||
stack_frame *second_from_top_stack_frame(context *ctx);
|
||||
cell capture_callstack(context *ctx);
|
||||
void primitive_callstack();
|
||||
|
@ -591,7 +597,6 @@ struct factor_vm
|
|||
cell frame_scan(stack_frame *frame);
|
||||
cell frame_offset(stack_frame *frame);
|
||||
void set_frame_offset(stack_frame *frame, cell offset);
|
||||
void scrub_return_address();
|
||||
void primitive_callstack_to_array();
|
||||
stack_frame *innermost_stack_frame(stack_frame *bottom, stack_frame *top);
|
||||
void primitive_innermost_stack_frame_executing();
|
||||
|
|
Loading…
Reference in New Issue