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(); */
|
/* open_console(); */
|
||||||
|
fep_p = true;
|
||||||
|
|
||||||
std::cout << "Starting low level debugger...\n";
|
std::cout << "Starting low level debugger...\n";
|
||||||
std::cout << " Basic commands:\n";
|
std::cout << " Basic commands:\n";
|
||||||
|
@ -446,7 +447,10 @@ void factor_vm::factorbug()
|
||||||
else if(strcmp(cmd,"g") == 0)
|
else if(strcmp(cmd,"g") == 0)
|
||||||
dump_generations();
|
dump_generations();
|
||||||
else if(strcmp(cmd,"q") == 0)
|
else if(strcmp(cmd,"q") == 0)
|
||||||
|
{
|
||||||
|
fep_p = false;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
else if(strcmp(cmd,"x") == 0)
|
else if(strcmp(cmd,"x") == 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
else if(strcmp(cmd,"im") == 0)
|
else if(strcmp(cmd,"im") == 0)
|
||||||
|
|
|
@ -156,19 +156,39 @@ void fp_signal_handler_impl()
|
||||||
current_vm()->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)
|
void factor_vm::enqueue_safepoint_signal(cell signal)
|
||||||
{
|
{
|
||||||
safepoint_signal_number = signal;
|
sigaddset(&safepoint_signals, signal);
|
||||||
code->guard_safepoint();
|
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()
|
void factor_vm::handle_safepoint()
|
||||||
{
|
{
|
||||||
assert(safepoint_signal_number != 0);
|
if (safepoint_fep) {
|
||||||
code->unguard_safepoint();
|
std::cout << "Interrupted. Entering low-level debugger...\n";
|
||||||
cell signal = safepoint_signal_number;
|
std::cout << "\n";
|
||||||
safepoint_signal_number = 0;
|
factorbug();
|
||||||
general_error(ERROR_SIGNAL,from_unsigned_cell(signal),false_object);
|
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);
|
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();
|
factor_vm *vm = current_vm_p();
|
||||||
if (vm)
|
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);
|
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)
|
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);
|
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()
|
void factor_vm::unix_init_signals()
|
||||||
{
|
{
|
||||||
/* OpenBSD doesn't support sigaltstack() if we link against
|
/* 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 memory_sigaction;
|
||||||
struct sigaction synchronous_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 fpe_sigaction;
|
||||||
struct sigaction ignore_sigaction;
|
struct sigaction ignore_sigaction;
|
||||||
|
|
||||||
memset(&memory_sigaction,0,sizeof(struct sigaction));
|
init_sigaction_with_handler(&memory_sigaction, memory_signal_handler);
|
||||||
sigemptyset(&memory_sigaction.sa_mask);
|
|
||||||
memory_sigaction.sa_sigaction = memory_signal_handler;
|
|
||||||
memory_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
|
||||||
|
|
||||||
sigaction_safe(SIGBUS,&memory_sigaction,NULL);
|
sigaction_safe(SIGBUS,&memory_sigaction,NULL);
|
||||||
sigaction_safe(SIGSEGV,&memory_sigaction,NULL);
|
sigaction_safe(SIGSEGV,&memory_sigaction,NULL);
|
||||||
sigaction_safe(SIGTRAP,&memory_sigaction,NULL);
|
sigaction_safe(SIGTRAP,&memory_sigaction,NULL);
|
||||||
|
|
||||||
memset(&fpe_sigaction,0,sizeof(struct sigaction));
|
init_sigaction_with_handler(&fpe_sigaction, fpe_signal_handler);
|
||||||
sigemptyset(&fpe_sigaction.sa_mask);
|
|
||||||
fpe_sigaction.sa_sigaction = fpe_signal_handler;
|
|
||||||
fpe_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
|
||||||
|
|
||||||
sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
|
sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
|
||||||
|
|
||||||
memset(&synchronous_sigaction,0,sizeof(struct sigaction));
|
init_sigaction_with_handler(&synchronous_sigaction, synchronous_signal_handler);
|
||||||
sigemptyset(&synchronous_sigaction.sa_mask);
|
|
||||||
synchronous_sigaction.sa_sigaction = synchronous_signal_handler;
|
|
||||||
synchronous_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
|
||||||
|
|
||||||
sigaction_safe(SIGILL,&synchronous_sigaction,NULL);
|
sigaction_safe(SIGILL,&synchronous_sigaction,NULL);
|
||||||
sigaction_safe(SIGABRT,&synchronous_sigaction,NULL);
|
sigaction_safe(SIGABRT,&synchronous_sigaction,NULL);
|
||||||
|
|
||||||
memset(&next_safepoint_sigaction,0,sizeof(struct sigaction));
|
init_sigaction_with_handler(&enqueue_sigaction, enqueue_signal_handler);
|
||||||
sigemptyset(&next_safepoint_sigaction.sa_mask);
|
sigaction_safe(SIGUSR1,&enqueue_sigaction,NULL);
|
||||||
next_safepoint_sigaction.sa_sigaction = next_safepoint_signal_handler;
|
sigaction_safe(SIGUSR2,&enqueue_sigaction,NULL);
|
||||||
next_safepoint_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
sigaction_safe(SIGWINCH,&enqueue_sigaction,NULL);
|
||||||
sigaction_safe(SIGALRM,&next_safepoint_sigaction,NULL);
|
#ifdef SIGINFO
|
||||||
sigaction_safe(SIGVTALRM,&next_safepoint_sigaction,NULL);
|
sigaction_safe(SIGINFO,&enqueue_sigaction,NULL);
|
||||||
sigaction_safe(SIGPROF,&next_safepoint_sigaction,NULL);
|
#endif
|
||||||
sigaction_safe(SIGQUIT,&next_safepoint_sigaction,NULL);
|
|
||||||
sigaction_safe(SIGINT,&next_safepoint_sigaction,NULL);
|
init_sigaction_with_handler(&fep_sigaction, fep_signal_handler);
|
||||||
sigaction_safe(SIGUSR1,&next_safepoint_sigaction,NULL);
|
sigaction_safe(SIGQUIT,&fep_sigaction,NULL);
|
||||||
sigaction_safe(SIGUSR2,&next_safepoint_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
|
/* 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
|
by subprocesses, which we don't want. There is a unit test in
|
||||||
io.launcher.unix for this. */
|
io.launcher.unix for this. */
|
||||||
memset(&ignore_sigaction,0,sizeof(struct sigaction));
|
init_sigaction_with_handler(&ignore_sigaction, ignore_signal_handler);
|
||||||
sigemptyset(&ignore_sigaction.sa_mask);
|
|
||||||
ignore_sigaction.sa_sigaction = ignore_signal_handler;
|
|
||||||
ignore_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
|
||||||
sigaction_safe(SIGPIPE,&ignore_sigaction,NULL);
|
sigaction_safe(SIGPIPE,&ignore_sigaction,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,19 @@ factor_vm::factor_vm() :
|
||||||
callback_id(0),
|
callback_id(0),
|
||||||
c_to_factor_func(NULL),
|
c_to_factor_func(NULL),
|
||||||
profiling_p(false),
|
profiling_p(false),
|
||||||
safepoint_signal_number(0),
|
sampling_p(false),
|
||||||
|
safepoint_fep(false),
|
||||||
|
safepoint_sample_count(0),
|
||||||
gc_off(false),
|
gc_off(false),
|
||||||
current_gc(NULL),
|
current_gc(NULL),
|
||||||
gc_events(NULL),
|
gc_events(NULL),
|
||||||
|
fep_p(false),
|
||||||
fep_disabled(false),
|
fep_disabled(false),
|
||||||
full_output(false),
|
full_output(false),
|
||||||
last_nano_count(0),
|
last_nano_count(0),
|
||||||
signal_callstack_seg(NULL)
|
signal_callstack_seg(NULL)
|
||||||
{
|
{
|
||||||
|
sigemptyset(&safepoint_signals);
|
||||||
primitive_reset_dispatch_stats();
|
primitive_reset_dispatch_stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
vm/vm.hpp
11
vm/vm.hpp
|
@ -51,13 +51,17 @@ struct factor_vm
|
||||||
|
|
||||||
/* Is call counting enabled? */
|
/* Is call counting enabled? */
|
||||||
bool profiling_p;
|
bool profiling_p;
|
||||||
|
/* Is sampling profiler enabled? */
|
||||||
|
bool sampling_p;
|
||||||
|
|
||||||
/* Global variables used to pass fault handler state from signal handler
|
/* Global variables used to pass fault handler state from signal handler
|
||||||
to VM */
|
to VM */
|
||||||
cell signal_number;
|
cell signal_number;
|
||||||
cell signal_fault_addr;
|
cell signal_fault_addr;
|
||||||
unsigned int signal_fpu_status;
|
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 */
|
/* GC is off during heap walking */
|
||||||
bool gc_off;
|
bool gc_off;
|
||||||
|
@ -89,6 +93,7 @@ struct factor_vm
|
||||||
std::vector<code_root *> code_roots;
|
std::vector<code_root *> code_roots;
|
||||||
|
|
||||||
/* Debugger */
|
/* Debugger */
|
||||||
|
bool fep_p;
|
||||||
bool fep_disabled;
|
bool fep_disabled;
|
||||||
bool full_output;
|
bool full_output;
|
||||||
|
|
||||||
|
@ -182,6 +187,8 @@ struct factor_vm
|
||||||
void memory_signal_handler_impl();
|
void memory_signal_handler_impl();
|
||||||
void synchronous_signal_handler_impl();
|
void synchronous_signal_handler_impl();
|
||||||
void fp_signal_handler_impl();
|
void fp_signal_handler_impl();
|
||||||
|
void enqueue_safepoint_fep();
|
||||||
|
void enqueue_safepoint_sample();
|
||||||
void enqueue_safepoint_signal(cell signal);
|
void enqueue_safepoint_signal(cell signal);
|
||||||
void handle_safepoint();
|
void handle_safepoint();
|
||||||
|
|
||||||
|
@ -578,7 +585,6 @@ struct factor_vm
|
||||||
template<typename Iterator> void iterate_callstack_object(callstack *stack_, Iterator &iterator);
|
template<typename Iterator> void iterate_callstack_object(callstack *stack_, Iterator &iterator);
|
||||||
void check_frame(stack_frame *frame);
|
void check_frame(stack_frame *frame);
|
||||||
callstack *allot_callstack(cell size);
|
callstack *allot_callstack(cell size);
|
||||||
stack_frame *fix_callstack_top(stack_frame *top);
|
|
||||||
stack_frame *second_from_top_stack_frame(context *ctx);
|
stack_frame *second_from_top_stack_frame(context *ctx);
|
||||||
cell capture_callstack(context *ctx);
|
cell capture_callstack(context *ctx);
|
||||||
void primitive_callstack();
|
void primitive_callstack();
|
||||||
|
@ -591,7 +597,6 @@ struct factor_vm
|
||||||
cell frame_scan(stack_frame *frame);
|
cell frame_scan(stack_frame *frame);
|
||||||
cell frame_offset(stack_frame *frame);
|
cell frame_offset(stack_frame *frame);
|
||||||
void set_frame_offset(stack_frame *frame, cell offset);
|
void set_frame_offset(stack_frame *frame, cell offset);
|
||||||
void scrub_return_address();
|
|
||||||
void primitive_callstack_to_array();
|
void primitive_callstack_to_array();
|
||||||
stack_frame *innermost_stack_frame(stack_frame *bottom, stack_frame *top);
|
stack_frame *innermost_stack_frame(stack_frame *bottom, stack_frame *top);
|
||||||
void primitive_innermost_stack_frame_executing();
|
void primitive_innermost_stack_frame_executing();
|
||||||
|
|
Loading…
Reference in New Issue