vm: handle async signals at safepoints on unix

Factor now supports the new 4.0BSD feature of "signals".
db4
Joe Groff 2011-10-19 15:39:44 -07:00
parent 6f75e84d93
commit b3e5f75c9e
12 changed files with 85 additions and 28 deletions

View File

@ -43,6 +43,12 @@ struct code_heap {
void flush_icache();
void guard_safepoint();
void unguard_safepoint();
bool safepoint_p(cell addr)
{
cell page_mask = ~(getpagesize() - 1);
return (addr & page_mask) == (cell)safepoint_page;
}
};
struct code_heap_room {

View File

@ -84,9 +84,9 @@ void factor_vm::not_implemented_error()
void factor_vm::memory_protection_error(cell addr)
{
/* Retain and call stack underflows are not supposed to happen */
if(ctx->datastack_seg->underflow_p(addr))
if(code->safepoint_p(addr))
handle_safepoint();
else if(ctx->datastack_seg->underflow_p(addr))
general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
else if(ctx->datastack_seg->overflow_p(addr))
general_error(ERROR_DATASTACK_OVERFLOW,false_object,false_object);
@ -134,15 +134,17 @@ void memory_signal_handler_impl()
current_vm()->memory_signal_handler_impl();
}
void factor_vm::misc_signal_handler_impl()
void factor_vm::synchronous_signal_handler_impl()
{
scrub_return_address();
signal_error(signal_number);
}
void misc_signal_handler_impl()
void synchronous_signal_handler_impl()
{
current_vm()->misc_signal_handler_impl();
factor_vm *vm = current_vm_p();
if (vm)
vm->synchronous_signal_handler_impl();
}
void factor_vm::fp_signal_handler_impl()
@ -159,4 +161,24 @@ void fp_signal_handler_impl()
current_vm()->fp_signal_handler_impl();
}
void factor_vm::enqueue_safepoint_signal(cell signal)
{
safepoint_signal_number = signal;
code->guard_safepoint();
}
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);
}
void factor_vm::primitive_guard_safepoint()
{
code->guard_safepoint();
}
}

View File

@ -29,6 +29,6 @@ void critical_error(const char *msg, cell tagged);
void out_of_memory();
void memory_signal_handler_impl();
void fp_signal_handler_impl();
void misc_signal_handler_impl();
void synchronous_signal_handler_impl();
}

View File

@ -60,7 +60,7 @@ void factor_vm::call_fault_handler(
default: signal_number = SIGABRT; break;
}
MACH_PROGRAM_COUNTER(thread_state) = (cell)factor::misc_signal_handler_impl;
MACH_PROGRAM_COUNTER(thread_state) = (cell)factor::synchronous_signal_handler_impl;
}
}

View File

@ -19,9 +19,8 @@ void register_vm_with_thread(factor_vm *vm)
global_vm = vm;
}
factor_vm *current_vm()
factor_vm *current_vm_p()
{
assert(global_vm != NULL);
return global_vm;
}

View File

@ -16,10 +16,9 @@ void register_vm_with_thread(factor_vm *vm)
pthread_setspecific(current_vm_tls_key,vm);
}
factor_vm *current_vm()
factor_vm *current_vm_p()
{
factor_vm *vm = (factor_vm*)pthread_getspecific(current_vm_tls_key);
assert(vm != NULL);
return vm;
}

View File

@ -17,11 +17,9 @@ void register_vm_with_thread(factor_vm *vm)
fatal_error("TlsSetValue() failed",0);
}
factor_vm *current_vm()
factor_vm *current_vm_p()
{
factor_vm *vm = (factor_vm *)TlsGetValue(current_vm_tls_key);
assert(vm != NULL);
return vm;
return (factor_vm *)TlsGetValue(current_vm_tls_key);
}
}

View File

@ -3,7 +3,14 @@ namespace factor
void init_mvm();
void register_vm_with_thread(factor_vm *vm);
factor_vm *current_vm();
factor_vm *current_vm_p();
inline factor_vm *current_vm()
{
factor_vm *vm = current_vm_p();
assert(vm != NULL);
return vm;
}
VM_C_API THREADHANDLE start_standalone_factor_in_new_thread(int argc, vm_char **argv);

View File

@ -151,11 +151,18 @@ void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
}
void misc_signal_handler(int signal, siginfo_t *siginfo, void *uap)
void synchronous_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
factor_vm *vm = current_vm();
vm->signal_number = signal;
vm->dispatch_signal(uap,factor::misc_signal_handler_impl);
vm->dispatch_signal(uap,factor::synchronous_signal_handler_impl);
}
void next_safepoint_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
factor_vm *vm = current_vm_p();
if (vm)
vm->enqueue_safepoint_signal(signal);
}
void ignore_signal_handler(int signal, siginfo_t *siginfo, void *uap)
@ -171,7 +178,7 @@ void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap)
vm->dispatch_signal(uap,
(siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF)
? factor::misc_signal_handler_impl
? factor::synchronous_signal_handler_impl
: factor::fp_signal_handler_impl);
}
@ -206,7 +213,8 @@ void factor_vm::unix_init_signals()
#endif
struct sigaction memory_sigaction;
struct sigaction misc_sigaction;
struct sigaction synchronous_sigaction;
struct sigaction next_safepoint_sigaction;
struct sigaction fpe_sigaction;
struct sigaction ignore_sigaction;
@ -226,13 +234,25 @@ void factor_vm::unix_init_signals()
sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
memset(&misc_sigaction,0,sizeof(struct sigaction));
sigemptyset(&misc_sigaction.sa_mask);
misc_sigaction.sa_sigaction = misc_signal_handler;
misc_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
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;
sigaction_safe(SIGQUIT,&misc_sigaction,NULL);
sigaction_safe(SIGILL,&misc_sigaction,NULL);
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);
/* 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

View File

@ -89,6 +89,7 @@ namespace factor
_(ftell) \
_(full_gc) \
_(fwrite) \
_(guard_safepoint) \
_(identity_hashcode) \
_(innermost_stack_frame_executing) \
_(innermost_stack_frame_scan) \

View File

@ -8,6 +8,7 @@ factor_vm::factor_vm() :
callback_id(0),
c_to_factor_func(NULL),
profiling_p(false),
safepoint_signal_number(0),
gc_off(false),
current_gc(NULL),
gc_events(NULL),

View File

@ -57,6 +57,7 @@ struct factor_vm
cell signal_number;
cell signal_fault_addr;
unsigned int signal_fpu_status;
cell safepoint_signal_number;
/* GC is off during heap walking */
bool gc_off;
@ -179,8 +180,11 @@ struct factor_vm
void fp_trap_error(unsigned int fpu_status);
void primitive_unimplemented();
void memory_signal_handler_impl();
void misc_signal_handler_impl();
void synchronous_signal_handler_impl();
void fp_signal_handler_impl();
void enqueue_safepoint_signal(cell signal);
void handle_safepoint();
void primitive_guard_safepoint();
// bignum
int bignum_equal_p(bignum * x, bignum * y);