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
Joe Groff 2011-10-20 21:00:25 -07:00
parent 1dc31d133b
commit dc42365007
5 changed files with 92 additions and 42 deletions

View File

@ -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)

View File

@ -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
} }
} }

View File

@ -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);
} }

View File

@ -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();
} }

View File

@ -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();