diff options
Diffstat (limited to 'byterun/signals.c')
-rw-r--r-- | byterun/signals.c | 159 |
1 files changed, 73 insertions, 86 deletions
diff --git a/byterun/signals.c b/byterun/signals.c index 1f0d1284e..31604eba2 100644 --- a/byterun/signals.c +++ b/byterun/signals.c @@ -13,6 +13,8 @@ /* $Id$ */ +/* Signal handling, code common to the bytecode and native systems */ + #include <signal.h> #include "alloc.h" #include "callback.h" @@ -30,20 +32,14 @@ #define NSIG 64 #endif -#ifdef _WIN32 -typedef void (*sighandler)(int sig); -extern sighandler caml_win32_signal(int sig, sighandler action); -#define signal(sig,act) caml_win32_signal(sig,act) -#endif +/* The set of pending signals (received but not yet processed) */ CAMLexport intnat volatile caml_signals_are_pending = 0; CAMLexport intnat volatile caml_pending_signals[NSIG]; -CAMLexport int volatile caml_something_to_do = 0; -int volatile caml_force_major_slice = 0; -value caml_signal_handlers = 0; -CAMLexport void (* volatile caml_async_action_hook)(void) = NULL; -static void caml_process_pending_signals(void) +/* Execute all pending signals */ + +void caml_process_pending_signals(void) { int i; @@ -58,20 +54,26 @@ static void caml_process_pending_signals(void) } } -void caml_process_event(void) -{ - void (*async_action)(void); +/* Record the delivery of a signal, and arrange for it to be processed + as soon as possible: + - in bytecode: via caml_something_to_do, processed in caml_process_event + - in native-code: by playing with the allocation limit, processed + in caml_garbage_collection +*/ - if (caml_force_major_slice) caml_minor_collection (); - /* FIXME should be [caml_check_urgent_gc] */ - caml_process_pending_signals(); - async_action = caml_async_action_hook; - if (async_action != NULL) { - caml_async_action_hook = NULL; - (*async_action)(); - } +void caml_record_signal(int signal_number) +{ + caml_pending_signals[signal_number] = 1; + caml_signals_are_pending = 1; +#ifndef NATIVE_CODE + caml_something_to_do = 1; +#else + caml_young_limit = caml_young_end; +#endif } +/* Management of blocking sections. */ + static intnat volatile caml_async_signal_mode = 0; static void caml_enter_blocking_section_default(void) @@ -100,10 +102,29 @@ CAMLexport void (*caml_leave_blocking_section_hook)(void) = CAMLexport int (*caml_try_leave_blocking_section_hook)(void) = caml_try_leave_blocking_section_default; -CAMLexport int caml_rev_convert_signal_number(int signo); +CAMLexport void caml_enter_blocking_section(void) +{ + while (1){ + /* Process all pending signals now */ + caml_process_pending_signals(); + caml_enter_blocking_section_hook (); + /* Check again for pending signals. + If none, done; otherwise, try again */ + if (! caml_signals_are_pending) break; + caml_leave_blocking_section_hook (); + } +} + +CAMLexport void caml_leave_blocking_section(void) +{ + caml_leave_blocking_section_hook (); + caml_process_pending_signals(); +} /* Execute a signal handler immediately */ +static value caml_signal_handlers = 0; + void caml_execute_signal(int signal_number, int in_signal_handler) { value res; @@ -131,54 +152,25 @@ void caml_execute_signal(int signal_number, int in_signal_handler) if (Is_exception_result(res)) caml_raise(Extract_exception(res)); } -/* Record the delivery of a signal, and arrange so that caml_process_event - is called as soon as possible. */ +/* Arrange for a garbage collection to be performed as soon as possible */ -void caml_record_signal(int signal_number) -{ - caml_pending_signals[signal_number] = 1; - caml_signals_are_pending = 1; - caml_something_to_do = 1; -} - -static void handle_signal(int signal_number) -{ -#if !defined(POSIX_SIGNALS) && !defined(BSD_SIGNALS) - signal(signal_number, handle_signal); -#endif - if (signal_number < 0 || signal_number >= NSIG) return; - if (caml_try_leave_blocking_section_hook()) { - caml_execute_signal(signal_number, 1); - caml_enter_blocking_section_hook(); - }else{ - caml_record_signal(signal_number); - } -} +int volatile caml_force_major_slice = 0; void caml_urge_major_slice (void) { caml_force_major_slice = 1; +#ifndef NATIVE_CODE caml_something_to_do = 1; +#else + caml_young_limit = caml_young_end; + /* This is only moderately effective on ports that cache [caml_young_limit] + in a register, since [caml_modify] is called directly, not through + [caml_c_call], so it may take a while before the register is reloaded + from [caml_young_limit]. */ +#endif } -CAMLexport void caml_enter_blocking_section(void) -{ - while (1){ - /* Process all pending signals now */ - caml_process_pending_signals(); - caml_enter_blocking_section_hook (); - /* Check again for pending signals. - If none, done; otherwise, try again */ - if (! caml_signals_are_pending) break; - caml_leave_blocking_section_hook (); - } -} - -CAMLexport void caml_leave_blocking_section(void) -{ - caml_leave_blocking_section_hook (); - caml_process_pending_signals(); -} +/* OS-independent numbering of signals */ #ifndef SIGABRT #define SIGABRT -1 @@ -266,48 +258,43 @@ CAMLexport int caml_rev_convert_signal_number(int signo) return signo; } +/* Installation of a signal handler (as per [Sys.signal]) */ + CAMLprim value caml_install_signal_handler(value signal_number, value action) { CAMLparam2 (signal_number, action); - int sig; - void (*act)(int signo), (*oldact)(int signo); -#ifdef POSIX_SIGNALS - struct sigaction sigact, oldsigact; -#endif CAMLlocal1 (res); + int sig, act, oldact; sig = caml_convert_signal_number(Int_val(signal_number)); if (sig < 0 || sig >= NSIG) caml_invalid_argument("Sys.signal: unavailable signal"); switch(action) { case Val_int(0): /* Signal_default */ - act = SIG_DFL; + act = 0; break; case Val_int(1): /* Signal_ignore */ - act = SIG_IGN; + act = 1; break; default: /* Signal_handle */ - act = handle_signal; + act = 2; break; } -#ifdef POSIX_SIGNALS - sigact.sa_handler = act; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - if (sigaction(sig, &sigact, &oldsigact) == -1) caml_sys_error(NO_ARG); - oldact = oldsigact.sa_handler; -#else - oldact = signal(sig, act); - if (oldact == SIG_ERR) caml_sys_error(NO_ARG); -#endif - if (oldact == handle_signal) { - res = caml_alloc_small (1, 0); /* Signal_handle */ + oldact = caml_set_signal_action(sig, act); + switch (oldact) { + case 0: /* was Signal_default */ + res = Val_int(0); + break; + case 1: /* was Signal_ignore */ + res = Val_int(1); + break; + case 2: /* was Signal_handle */ + res = caml_alloc_small (1, 0); Field(res, 0) = Field(caml_signal_handlers, sig); + break; + default: /* error in caml_set_signal_action */ + caml_sys_error(NO_ARG); } - else if (oldact == SIG_IGN) - res = Val_int(1); /* Signal_ignore */ - else - res = Val_int(0); /* Signal_default */ if (Is_block(action)) { if (caml_signal_handlers == 0) { caml_signal_handlers = caml_alloc(NSIG, 0); |