1 |
/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. |
/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002 Free Software Foundation, Inc. |
2 |
* |
* |
3 |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
4 |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
102 |
|
|
103 |
|
|
104 |
/* take_signal is installed as the C signal handler whenever a Scheme |
/* take_signal is installed as the C signal handler whenever a Scheme |
105 |
handler is set. when a signal arrives, take_signal marks the corresponding |
handler is set. when a signal arrives, take_signal will queue the |
106 |
element of got_signal and marks signal_async. the thunk in signal_async |
Scheme handler procedure for its thread. */ |
|
(sys_deliver_signals) will be run at the next opportunity, outside a |
|
|
critical section. sys_deliver_signals runs each Scheme handler for |
|
|
which got_signal is set. */ |
|
107 |
|
|
|
static SCM signal_async; |
|
108 |
|
|
109 |
static char got_signal[NSIG]; |
/* Scheme vectors with information about a signal. signal_handlers |
110 |
|
contains the handler procedure or #f, signal_handler_cells contains |
111 |
/* a Scheme vector of handler procedures. */ |
preallocated cells for queuing the handler in take_signal since we |
112 |
|
can't allocate during signal delivery, signal_handler_threads |
113 |
|
points to the thread that a signal should be delivered to. |
114 |
|
*/ |
115 |
static SCM *signal_handlers; |
static SCM *signal_handlers; |
116 |
|
static SCM signal_handler_cells; |
117 |
|
static SCM signal_handler_threads; |
118 |
|
|
119 |
/* saves the original C handlers, when a new handler is installed. |
/* saves the original C handlers, when a new handler is installed. |
120 |
set to SIG_ERR if the original handler is installed. */ |
set to SIG_ERR if the original handler is installed. */ |
127 |
static SIGRETTYPE |
static SIGRETTYPE |
128 |
take_signal (int signum) |
take_signal (int signum) |
129 |
{ |
{ |
130 |
got_signal[signum] = 1; |
if (signum >= 0 && signum < NSIG) |
131 |
scm_system_async_mark_from_signal_handler (signal_async); |
{ |
132 |
|
SCM thread = SCM_VECTOR_REF (signal_handler_threads, signum); |
133 |
|
scm_i_queue_async_cell (SCM_VECTOR_REF(signal_handler_cells, signum), |
134 |
|
scm_i_thread_root (thread)); |
135 |
|
} |
136 |
|
#ifndef HAVE_SIGACTION |
137 |
|
signal (signum, take_signal); |
138 |
|
#endif |
139 |
} |
} |
140 |
|
|
141 |
static SCM |
SCM |
142 |
sys_deliver_signals (void) |
scm_sigaction (SCM signum, SCM handler, SCM flags) |
143 |
{ |
{ |
144 |
int i; |
return scm_sigaction_for_thread (signum, handler, flags, SCM_UNDEFINED); |
145 |
|
} |
146 |
|
|
147 |
for (i = 0; i < NSIG; i++) |
static SCM |
148 |
{ |
close_1 (SCM proc, SCM arg) |
149 |
if (got_signal[i]) |
{ |
150 |
{ |
return scm_primitive_eval_x (scm_list_3 (scm_sym_lambda, SCM_EOL, |
151 |
/* The flag is reset before calling the handler in case the |
scm_list_2 (proc, arg))); |
|
handler doesn't return. If the handler doesn't return |
|
|
but leaves other signals flagged, they their handlers |
|
|
will be applied some time later when the async is checked |
|
|
again. It would probably be better to reset the flags |
|
|
after doing a longjmp. */ |
|
|
got_signal[i] = 0; |
|
|
#ifndef HAVE_SIGACTION |
|
|
signal (i, take_signal); |
|
|
#endif |
|
|
scm_call_1 (SCM_VELTS (*signal_handlers)[i], SCM_MAKINUM (i)); |
|
|
} |
|
|
} |
|
|
return SCM_UNSPECIFIED; |
|
152 |
} |
} |
153 |
|
|
154 |
/* user interface for installation of signal handlers. */ |
/* user interface for installation of signal handlers. */ |
155 |
SCM_DEFINE (scm_sigaction, "sigaction", 1, 2, 0, |
SCM_DEFINE (scm_sigaction_for_thread, "sigaction", 1, 3, 0, |
156 |
(SCM signum, SCM handler, SCM flags), |
(SCM signum, SCM handler, SCM flags, SCM thread), |
157 |
"Install or report the signal handler for a specified signal.\n\n" |
"Install or report the signal handler for a specified signal.\n\n" |
158 |
"@var{signum} is the signal number, which can be specified using the value\n" |
"@var{signum} is the signal number, which can be specified using the value\n" |
159 |
"of variables such as @code{SIGINT}.\n\n" |
"of variables such as @code{SIGINT}.\n\n" |
160 |
"If @var{action} is omitted, @code{sigaction} returns a pair: the\n" |
"If @var{handler} is omitted, @code{sigaction} returns a pair: the\n" |
161 |
"CAR is the current\n" |
"CAR is the current\n" |
162 |
"signal hander, which will be either an integer with the value @code{SIG_DFL}\n" |
"signal hander, which will be either an integer with the value @code{SIG_DFL}\n" |
163 |
"(default action) or @code{SIG_IGN} (ignore), or the Scheme procedure which\n" |
"(default action) or @code{SIG_IGN} (ignore), or the Scheme procedure which\n" |
164 |
"handles the signal, or @code{#f} if a non-Scheme procedure handles the\n" |
"handles the signal, or @code{#f} if a non-Scheme procedure handles the\n" |
165 |
"signal. The CDR contains the current @code{sigaction} flags for the handler.\n\n" |
"signal. The CDR contains the current @code{sigaction} flags for the handler.\n\n" |
166 |
"If @var{action} is provided, it is installed as the new handler for\n" |
"If @var{handler} is provided, it is installed as the new handler for\n" |
167 |
"@var{signum}. @var{action} can be a Scheme procedure taking one\n" |
"@var{signum}. @var{handler} can be a Scheme procedure taking one\n" |
168 |
"argument, or the value of @code{SIG_DFL} (default action) or\n" |
"argument, or the value of @code{SIG_DFL} (default action) or\n" |
169 |
"@code{SIG_IGN} (ignore), or @code{#f} to restore whatever signal handler\n" |
"@code{SIG_IGN} (ignore), or @code{#f} to restore whatever signal handler\n" |
170 |
"was installed before @code{sigaction} was first used. Flags can\n" |
"was installed before @code{sigaction} was first used. When\n" |
171 |
|
"a scheme procedure has been specified, that procedure will run\n" |
172 |
|
"in the given @var{thread}. When no thread has been given, the\n" |
173 |
|
"thread that made this call to @code{sigaction} is used.\n" |
174 |
|
"Flags can " |
175 |
"optionally be specified for the new handler (@code{SA_RESTART} will\n" |
"optionally be specified for the new handler (@code{SA_RESTART} will\n" |
176 |
"always be added if it's available and the system is using restartable\n" |
"always be added if it's available and the system is using restartable\n" |
177 |
"system calls.) The return value is a pair with information about the\n" |
"system calls.) The return value is a pair with information about the\n" |
180 |
"facility. Maybe this is not needed, since the thread support may\n" |
"facility. Maybe this is not needed, since the thread support may\n" |
181 |
"provide solutions to the problem of consistent access to data\n" |
"provide solutions to the problem of consistent access to data\n" |
182 |
"structures.") |
"structures.") |
183 |
#define FUNC_NAME s_scm_sigaction |
#define FUNC_NAME s_scm_sigaction_for_thread |
184 |
{ |
{ |
185 |
int csig; |
int csig; |
186 |
#ifdef HAVE_SIGACTION |
#ifdef HAVE_SIGACTION |
196 |
SCM old_handler; |
SCM old_handler; |
197 |
|
|
198 |
SCM_VALIDATE_INUM_COPY (1, signum, csig); |
SCM_VALIDATE_INUM_COPY (1, signum, csig); |
199 |
|
if (csig < 0 || csig > NSIG) |
200 |
|
SCM_OUT_OF_RANGE (1, signum); |
201 |
#if defined(HAVE_SIGACTION) |
#if defined(HAVE_SIGACTION) |
202 |
#if defined(SA_RESTART) && defined(HAVE_RESTARTABLE_SYSCALLS) |
#if defined(SA_RESTART) && defined(HAVE_RESTARTABLE_SYSCALLS) |
203 |
/* don't allow SA_RESTART to be omitted if HAVE_RESTARTABLE_SYSCALLS |
/* don't allow SA_RESTART to be omitted if HAVE_RESTARTABLE_SYSCALLS |
213 |
action.sa_flags |= SCM_INUM (flags); |
action.sa_flags |= SCM_INUM (flags); |
214 |
} |
} |
215 |
sigemptyset (&action.sa_mask); |
sigemptyset (&action.sa_mask); |
216 |
|
if (SCM_UNBNDP (thread)) |
217 |
|
thread = scm_current_thread (); |
218 |
|
else |
219 |
|
SCM_VALIDATE_THREAD (4, thread); |
220 |
#endif |
#endif |
221 |
SCM_DEFER_INTS; |
SCM_DEFER_INTS; |
222 |
old_handler = SCM_VELTS(*signal_handlers)[csig]; |
old_handler = SCM_VECTOR_REF(*signal_handlers, csig); |
223 |
if (SCM_UNBNDP (handler)) |
if (SCM_UNBNDP (handler)) |
224 |
query_only = 1; |
query_only = 1; |
225 |
else if (SCM_EQ_P (scm_integer_p (handler), SCM_BOOL_T)) |
else if (SCM_EQ_P (scm_integer_p (handler), SCM_BOOL_T)) |
273 |
if (orig_handlers[csig] == SIG_ERR) |
if (orig_handlers[csig] == SIG_ERR) |
274 |
save_handler = 1; |
save_handler = 1; |
275 |
#endif |
#endif |
276 |
|
handler = close_1 (handler, signum); |
277 |
SCM_VECTOR_SET (*signal_handlers, csig, handler); |
SCM_VECTOR_SET (*signal_handlers, csig, handler); |
278 |
|
SCM_VECTOR_SET (signal_handler_cells, csig, |
279 |
|
scm_cons (handler, SCM_EOL)); |
280 |
|
SCM_VECTOR_SET (signal_handler_threads, csig, thread); |
281 |
} |
} |
282 |
|
|
283 |
/* XXX - Silently ignore setting handlers for `program error signals' |
/* XXX - Silently ignore setting handlers for `program error signals' |
565 |
void |
void |
566 |
scm_init_scmsigs () |
scm_init_scmsigs () |
567 |
{ |
{ |
|
SCM thunk; |
|
568 |
int i; |
int i; |
569 |
|
|
570 |
signal_handlers = |
signal_handlers = |
571 |
SCM_VARIABLE_LOC (scm_c_define ("signal-handlers", |
SCM_VARIABLE_LOC (scm_c_define ("signal-handlers", |
572 |
scm_c_make_vector (NSIG, SCM_BOOL_F))); |
scm_c_make_vector (NSIG, SCM_BOOL_F))); |
573 |
/* XXX - use scm_c_make_gsubr here instead of `define'? */ |
signal_handler_cells = |
574 |
thunk = scm_c_define_gsubr ("%deliver-signals", 0, 0, 0, |
scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F)); |
575 |
sys_deliver_signals); |
signal_handler_threads = |
576 |
signal_async = scm_system_async (thunk); |
scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F)); |
577 |
|
|
578 |
for (i = 0; i < NSIG; i++) |
for (i = 0; i < NSIG; i++) |
579 |
{ |
{ |
|
got_signal[i] = 0; |
|
580 |
#ifdef HAVE_SIGACTION |
#ifdef HAVE_SIGACTION |
581 |
orig_handlers[i].sa_handler = SIG_ERR; |
orig_handlers[i].sa_handler = SIG_ERR; |
582 |
|
|