vm: handle async signals at safepoints on unix
Factor now supports the new 4.0BSD feature of "signals".db4
parent
6f75e84d93
commit
b3e5f75c9e
|
@ -43,6 +43,12 @@ struct code_heap {
|
||||||
void flush_icache();
|
void flush_icache();
|
||||||
void guard_safepoint();
|
void guard_safepoint();
|
||||||
void unguard_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 {
|
struct code_heap_room {
|
||||||
|
|
|
@ -84,9 +84,9 @@ void factor_vm::not_implemented_error()
|
||||||
|
|
||||||
void factor_vm::memory_protection_error(cell addr)
|
void factor_vm::memory_protection_error(cell addr)
|
||||||
{
|
{
|
||||||
/* Retain and call stack underflows are not supposed to happen */
|
if(code->safepoint_p(addr))
|
||||||
|
handle_safepoint();
|
||||||
if(ctx->datastack_seg->underflow_p(addr))
|
else if(ctx->datastack_seg->underflow_p(addr))
|
||||||
general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
|
general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
|
||||||
else if(ctx->datastack_seg->overflow_p(addr))
|
else if(ctx->datastack_seg->overflow_p(addr))
|
||||||
general_error(ERROR_DATASTACK_OVERFLOW,false_object,false_object);
|
general_error(ERROR_DATASTACK_OVERFLOW,false_object,false_object);
|
||||||
|
@ -134,15 +134,17 @@ void memory_signal_handler_impl()
|
||||||
current_vm()->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();
|
scrub_return_address();
|
||||||
signal_error(signal_number);
|
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()
|
void factor_vm::fp_signal_handler_impl()
|
||||||
|
@ -159,4 +161,24 @@ void fp_signal_handler_impl()
|
||||||
current_vm()->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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,6 @@ void critical_error(const char *msg, cell tagged);
|
||||||
void out_of_memory();
|
void out_of_memory();
|
||||||
void memory_signal_handler_impl();
|
void memory_signal_handler_impl();
|
||||||
void fp_signal_handler_impl();
|
void fp_signal_handler_impl();
|
||||||
void misc_signal_handler_impl();
|
void synchronous_signal_handler_impl();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ void factor_vm::call_fault_handler(
|
||||||
default: signal_number = SIGABRT; break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,8 @@ void register_vm_with_thread(factor_vm *vm)
|
||||||
global_vm = vm;
|
global_vm = vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
factor_vm *current_vm()
|
factor_vm *current_vm_p()
|
||||||
{
|
{
|
||||||
assert(global_vm != NULL);
|
|
||||||
return global_vm;
|
return global_vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,9 @@ void register_vm_with_thread(factor_vm *vm)
|
||||||
pthread_setspecific(current_vm_tls_key,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);
|
factor_vm *vm = (factor_vm*)pthread_getspecific(current_vm_tls_key);
|
||||||
assert(vm != NULL);
|
|
||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,9 @@ void register_vm_with_thread(factor_vm *vm)
|
||||||
fatal_error("TlsSetValue() failed",0);
|
fatal_error("TlsSetValue() failed",0);
|
||||||
}
|
}
|
||||||
|
|
||||||
factor_vm *current_vm()
|
factor_vm *current_vm_p()
|
||||||
{
|
{
|
||||||
factor_vm *vm = (factor_vm *)TlsGetValue(current_vm_tls_key);
|
return (factor_vm *)TlsGetValue(current_vm_tls_key);
|
||||||
assert(vm != NULL);
|
|
||||||
return vm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,14 @@ namespace factor
|
||||||
|
|
||||||
void init_mvm();
|
void init_mvm();
|
||||||
void register_vm_with_thread(factor_vm *vm);
|
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);
|
VM_C_API THREADHANDLE start_standalone_factor_in_new_thread(int argc, vm_char **argv);
|
||||||
|
|
||||||
|
|
|
@ -151,11 +151,18 @@ void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
|
||||||
vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
|
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();
|
factor_vm *vm = current_vm();
|
||||||
vm->signal_number = signal;
|
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)
|
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,
|
vm->dispatch_signal(uap,
|
||||||
(siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF)
|
(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);
|
: factor::fp_signal_handler_impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +213,8 @@ void factor_vm::unix_init_signals()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct sigaction memory_sigaction;
|
struct sigaction memory_sigaction;
|
||||||
struct sigaction misc_sigaction;
|
struct sigaction synchronous_sigaction;
|
||||||
|
struct sigaction next_safepoint_sigaction;
|
||||||
struct sigaction fpe_sigaction;
|
struct sigaction fpe_sigaction;
|
||||||
struct sigaction ignore_sigaction;
|
struct sigaction ignore_sigaction;
|
||||||
|
|
||||||
|
@ -226,13 +234,25 @@ void factor_vm::unix_init_signals()
|
||||||
|
|
||||||
sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
|
sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
|
||||||
|
|
||||||
memset(&misc_sigaction,0,sizeof(struct sigaction));
|
memset(&synchronous_sigaction,0,sizeof(struct sigaction));
|
||||||
sigemptyset(&misc_sigaction.sa_mask);
|
sigemptyset(&synchronous_sigaction.sa_mask);
|
||||||
misc_sigaction.sa_sigaction = misc_signal_handler;
|
synchronous_sigaction.sa_sigaction = synchronous_signal_handler;
|
||||||
misc_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
synchronous_sigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||||
|
|
||||||
sigaction_safe(SIGQUIT,&misc_sigaction,NULL);
|
sigaction_safe(SIGILL,&synchronous_sigaction,NULL);
|
||||||
sigaction_safe(SIGILL,&misc_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
|
/* 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
|
||||||
|
|
|
@ -89,6 +89,7 @@ namespace factor
|
||||||
_(ftell) \
|
_(ftell) \
|
||||||
_(full_gc) \
|
_(full_gc) \
|
||||||
_(fwrite) \
|
_(fwrite) \
|
||||||
|
_(guard_safepoint) \
|
||||||
_(identity_hashcode) \
|
_(identity_hashcode) \
|
||||||
_(innermost_stack_frame_executing) \
|
_(innermost_stack_frame_executing) \
|
||||||
_(innermost_stack_frame_scan) \
|
_(innermost_stack_frame_scan) \
|
||||||
|
|
|
@ -8,6 +8,7 @@ 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),
|
||||||
gc_off(false),
|
gc_off(false),
|
||||||
current_gc(NULL),
|
current_gc(NULL),
|
||||||
gc_events(NULL),
|
gc_events(NULL),
|
||||||
|
|
|
@ -57,6 +57,7 @@ struct factor_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;
|
||||||
|
|
||||||
/* GC is off during heap walking */
|
/* GC is off during heap walking */
|
||||||
bool gc_off;
|
bool gc_off;
|
||||||
|
@ -179,8 +180,11 @@ struct factor_vm
|
||||||
void fp_trap_error(unsigned int fpu_status);
|
void fp_trap_error(unsigned int fpu_status);
|
||||||
void primitive_unimplemented();
|
void primitive_unimplemented();
|
||||||
void memory_signal_handler_impl();
|
void memory_signal_handler_impl();
|
||||||
void misc_signal_handler_impl();
|
void synchronous_signal_handler_impl();
|
||||||
void fp_signal_handler_impl();
|
void fp_signal_handler_impl();
|
||||||
|
void enqueue_safepoint_signal(cell signal);
|
||||||
|
void handle_safepoint();
|
||||||
|
void primitive_guard_safepoint();
|
||||||
|
|
||||||
// bignum
|
// bignum
|
||||||
int bignum_equal_p(bignum * x, bignum * y);
|
int bignum_equal_p(bignum * x, bignum * y);
|
||||||
|
|
Loading…
Reference in New Issue