From e9309a425aef7d278d229b1d80d662260d08e59c Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Wed, 19 Oct 2011 15:39:44 -0700 Subject: [PATCH] vm: handle async signals at safepoints on unix Factor now supports the new 4.0BSD feature of "signals". --- vm/code_heap.hpp | 6 ++++++ vm/errors.cpp | 34 ++++++++++++++++++++++++++++------ vm/errors.hpp | 2 +- vm/mach_signal.cpp | 2 +- vm/mvm-none.cpp | 3 +-- vm/mvm-unix.cpp | 3 +-- vm/mvm-windows.cpp | 6 ++---- vm/mvm.hpp | 9 ++++++++- vm/os-unix.cpp | 40 ++++++++++++++++++++++++++++++---------- vm/primitives.hpp | 1 + vm/vm.cpp | 1 + vm/vm.hpp | 6 +++++- 12 files changed, 85 insertions(+), 28 deletions(-) diff --git a/vm/code_heap.hpp b/vm/code_heap.hpp index fd125bae01..75f19e2b7c 100755 --- a/vm/code_heap.hpp +++ b/vm/code_heap.hpp @@ -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 { diff --git a/vm/errors.cpp b/vm/errors.cpp index 7c4b043423..6d5b91dcf0 100755 --- a/vm/errors.cpp +++ b/vm/errors.cpp @@ -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(); +} + } diff --git a/vm/errors.hpp b/vm/errors.hpp index 34a23bd46d..ae7557ad52 100755 --- a/vm/errors.hpp +++ b/vm/errors.hpp @@ -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(); } diff --git a/vm/mach_signal.cpp b/vm/mach_signal.cpp index f87c0c8635..469b9f2ef6 100755 --- a/vm/mach_signal.cpp +++ b/vm/mach_signal.cpp @@ -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; } } diff --git a/vm/mvm-none.cpp b/vm/mvm-none.cpp index ab1b53a4b5..b6198afd25 100644 --- a/vm/mvm-none.cpp +++ b/vm/mvm-none.cpp @@ -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; } diff --git a/vm/mvm-unix.cpp b/vm/mvm-unix.cpp index adba52b122..a797b8c41a 100644 --- a/vm/mvm-unix.cpp +++ b/vm/mvm-unix.cpp @@ -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; } diff --git a/vm/mvm-windows.cpp b/vm/mvm-windows.cpp index 92c20672aa..9d6eb7fb07 100644 --- a/vm/mvm-windows.cpp +++ b/vm/mvm-windows.cpp @@ -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); } } diff --git a/vm/mvm.hpp b/vm/mvm.hpp index 52430b7c01..4fbc9b7467 100644 --- a/vm/mvm.hpp +++ b/vm/mvm.hpp @@ -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); diff --git a/vm/os-unix.cpp b/vm/os-unix.cpp index 7045a073bb..a0963a9385 100755 --- a/vm/os-unix.cpp +++ b/vm/os-unix.cpp @@ -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 diff --git a/vm/primitives.hpp b/vm/primitives.hpp index e9965c2f3b..ea02c07f6c 100644 --- a/vm/primitives.hpp +++ b/vm/primitives.hpp @@ -89,6 +89,7 @@ namespace factor _(ftell) \ _(full_gc) \ _(fwrite) \ + _(guard_safepoint) \ _(identity_hashcode) \ _(innermost_stack_frame_executing) \ _(innermost_stack_frame_scan) \ diff --git a/vm/vm.cpp b/vm/vm.cpp index ee469f7445..5379e33db9 100755 --- a/vm/vm.cpp +++ b/vm/vm.cpp @@ -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), diff --git a/vm/vm.hpp b/vm/vm.hpp index ed7f9bf6d0..447c300e9a 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -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);