1 /***********************************************************************/
5 /* Xavier Leroy and Damien Doligez, INRIA Rocquencourt */
7 /* Copyright 1996 Institut National de Recherche en Informatique et */
8 /* en Automatique. All rights reserved. This file is distributed */
9 /* under the terms of the GNU Library General Public License, with */
10 /* the special exception on linking described in file ../LICENSE. */
12 /***********************************************************************/
14 /* $Id: signals.c 7904 2007-02-23 09:29:45Z xleroy $ */
16 /* Signal handling, code common to the bytecode and native systems */
28 #include "signals_machdep.h"
35 /* The set of pending signals (received but not yet processed) */
37 CAMLexport intnat volatile caml_signals_are_pending = 0;
38 CAMLexport intnat volatile caml_pending_signals[NSIG];
40 /* Execute all pending signals */
42 void caml_process_pending_signals(void)
46 if (caml_signals_are_pending) {
47 caml_signals_are_pending = 0;
48 for (i = 0; i < NSIG; i++) {
49 if (caml_pending_signals[i]) {
50 caml_pending_signals[i] = 0;
51 caml_execute_signal(i, 0);
57 /* Record the delivery of a signal, and arrange for it to be processed
59 - in bytecode: via caml_something_to_do, processed in caml_process_event
60 - in native-code: by playing with the allocation limit, processed
61 in caml_garbage_collection
64 void caml_record_signal(int signal_number)
66 caml_pending_signals[signal_number] = 1;
67 caml_signals_are_pending = 1;
69 caml_something_to_do = 1;
71 caml_young_limit = caml_young_end;
75 /* Management of blocking sections. */
77 static intnat volatile caml_async_signal_mode = 0;
79 static void caml_enter_blocking_section_default(void)
81 Assert (caml_async_signal_mode == 0);
82 caml_async_signal_mode = 1;
85 static void caml_leave_blocking_section_default(void)
87 Assert (caml_async_signal_mode == 1);
88 caml_async_signal_mode = 0;
91 static int caml_try_leave_blocking_section_default(void)
94 Read_and_clear(res, caml_async_signal_mode);
98 CAMLexport void (*caml_enter_blocking_section_hook)(void) =
99 caml_enter_blocking_section_default;
100 CAMLexport void (*caml_leave_blocking_section_hook)(void) =
101 caml_leave_blocking_section_default;
102 CAMLexport int (*caml_try_leave_blocking_section_hook)(void) =
103 caml_try_leave_blocking_section_default;
105 CAMLexport void caml_enter_blocking_section(void)
108 /* Process all pending signals now */
109 caml_process_pending_signals();
110 caml_enter_blocking_section_hook ();
111 /* Check again for pending signals.
112 If none, done; otherwise, try again */
113 if (! caml_signals_are_pending) break;
114 caml_leave_blocking_section_hook ();
118 CAMLexport void caml_leave_blocking_section(void)
120 caml_leave_blocking_section_hook ();
121 caml_process_pending_signals();
124 /* Execute a signal handler immediately */
126 static value caml_signal_handlers = 0;
128 void caml_execute_signal(int signal_number, int in_signal_handler)
133 /* Block the signal before executing the handler, and record in sigs
134 the original signal mask */
136 sigaddset(&sigs, signal_number);
137 sigprocmask(SIG_BLOCK, &sigs, &sigs);
139 res = caml_callback_exn(
140 Field(caml_signal_handlers, signal_number),
141 Val_int(caml_rev_convert_signal_number(signal_number)));
143 if (! in_signal_handler) {
144 /* Restore the original signal mask */
145 sigprocmask(SIG_SETMASK, &sigs, NULL);
146 } else if (Is_exception_result(res)) {
147 /* Restore the original signal mask and unblock the signal itself */
148 sigdelset(&sigs, signal_number);
149 sigprocmask(SIG_SETMASK, &sigs, NULL);
152 if (Is_exception_result(res)) caml_raise(Extract_exception(res));
155 /* Arrange for a garbage collection to be performed as soon as possible */
157 int volatile caml_force_major_slice = 0;
159 void caml_urge_major_slice (void)
161 caml_force_major_slice = 1;
163 caml_something_to_do = 1;
165 caml_young_limit = caml_young_end;
166 /* This is only moderately effective on ports that cache [caml_young_limit]
167 in a register, since [caml_modify] is called directly, not through
168 [caml_c_call], so it may take a while before the register is reloaded
169 from [caml_young_limit]. */
173 /* OS-independent numbering of signals */
239 static int posix_signals[] = {
240 SIGABRT, SIGALRM, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, SIGPIPE,
241 SIGQUIT, SIGSEGV, SIGTERM, SIGUSR1, SIGUSR2, SIGCHLD, SIGCONT,
242 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGVTALRM, SIGPROF
245 CAMLexport int caml_convert_signal_number(int signo)
247 if (signo < 0 && signo >= -(sizeof(posix_signals) / sizeof(int)))
248 return posix_signals[-signo-1];
253 CAMLexport int caml_rev_convert_signal_number(int signo)
256 for (i = 0; i < sizeof(posix_signals) / sizeof(int); i++)
257 if (signo == posix_signals[i]) return -i - 1;
261 /* Installation of a signal handler (as per [Sys.signal]) */
263 CAMLprim value caml_install_signal_handler(value signal_number, value action)
265 CAMLparam2 (signal_number, action);
267 int sig, act, oldact;
269 sig = caml_convert_signal_number(Int_val(signal_number));
270 if (sig < 0 || sig >= NSIG)
271 caml_invalid_argument("Sys.signal: unavailable signal");
273 case Val_int(0): /* Signal_default */
276 case Val_int(1): /* Signal_ignore */
279 default: /* Signal_handle */
283 oldact = caml_set_signal_action(sig, act);
285 case 0: /* was Signal_default */
288 case 1: /* was Signal_ignore */
291 case 2: /* was Signal_handle */
292 res = caml_alloc_small (1, 0);
293 Field(res, 0) = Field(caml_signal_handlers, sig);
295 default: /* error in caml_set_signal_action */
296 caml_sys_error(NO_ARG);
298 if (Is_block(action)) {
299 if (caml_signal_handlers == 0) {
300 caml_signal_handlers = caml_alloc(NSIG, 0);
301 caml_register_global_root(&caml_signal_handlers);
303 caml_modify(&Field(caml_signal_handlers, sig), Field(action, 0));
305 caml_process_pending_signals();