*.[ch]: Replace GUILE_PROC w/ SCM_DEFINE.
[bpt/guile.git] / libguile / scmsigs.c
CommitLineData
8638b097 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * 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
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
48#include <signal.h>
49#include "_scm.h"
50
e1a191a8
GH
51#include "async.h"
52#include "eval.h"
1bbd0b84
GB
53
54#include "scm_validate.h"
20e6290e
JB
55#include "scmsigs.h"
56
0f2d19dd
JB
57#ifdef HAVE_UNISTD_H
58#include <unistd.h>
59#endif
60
b74f4728
JB
61/* The thread system has its own sleep and usleep functions. */
62#ifndef USE_THREADS
63
64#if defined(MISSING_SLEEP_DECL)
65int sleep ();
66#endif
67
68#if defined(HAVE_USLEEP) && defined(MISSING_USLEEP_DECL)
69int usleep ();
ce874f2d 70#endif
b74f4728 71
0935d604 72#endif
0f2d19dd
JB
73
74\f
75
317607b0
MD
76#ifdef USE_MIT_PTHREADS
77#undef signal
78#define signal pthread_signal
79#endif
80
0f2d19dd
JB
81\f
82
e1a191a8 83/* SIGRETTYPE is the type that signal handlers return. See <signal.h> */
0f2d19dd
JB
84
85#ifdef RETSIGTYPE
e1a191a8 86# define SIGRETTYPE RETSIGTYPE
0f2d19dd 87#else
e1a191a8
GH
88# ifdef STDC_HEADERS
89# define SIGRETTYPE void
90# else
91# define SIGRETTYPE int
92# endif
0f2d19dd
JB
93#endif
94
95\f
96
e1a191a8
GH
97/* take_signal is installed as the C signal handler whenever a Scheme
98 handler is set. when a signal arrives, take_signal marks the corresponding
99 element of got_signal and marks signal_async. the thunk in signal_async
100 (sys_deliver_signals) will be run at the next opportunity, outside a
101 critical section. sys_deliver_signals runs each Scheme handler for
102 which got_signal is set. */
0f2d19dd 103
e1a191a8 104static SCM signal_async;
0f2d19dd 105
e1a191a8 106static char got_signal[NSIG];
0f2d19dd 107
e1a191a8
GH
108/* a Scheme vector of handler procedures. */
109static SCM *signal_handlers;
0f2d19dd 110
e1a191a8
GH
111/* saves the original C handlers, when a new handler is installed.
112 set to SIG_ERR if the original handler is installed. */
113#ifdef HAVE_SIGACTION
114static struct sigaction orig_handlers[NSIG];
115#else
116static SIGRETTYPE (*orig_handlers)(int)[NSIG];
0f2d19dd
JB
117#endif
118
e1a191a8
GH
119static SIGRETTYPE
120take_signal (int signum)
121{
ee149d03 122 int saved_errno = errno;
e1a191a8
GH
123 SCM ignored;
124 if (!scm_ints_disabled)
125 {
126 /* For reasons of speed, the SCM_NEWCELL macro doesn't defer
127 interrupts. Instead, it first sets its argument to point to
128 the first cell in the list, and then advances the freelist
129 pointer to the next cell. Now, if this procedure is
130 interrupted, the only anomalous state possible is to have
131 both SCM_NEWCELL's argument and scm_freelist pointing to the
132 same cell. To deal with this case, we always throw away the
133 first cell in scm_freelist here.
134
135 At least, that's the theory. I'm not convinced that that's
136 the only anomalous path we need to worry about. */
137 SCM_NEWCELL (ignored);
138 }
139 got_signal[signum] = 1;
140#if HAVE_SIGACTION
141 /* unblock the signal before the scheme handler gets to run, since
142 it may use longjmp to escape (i.e., throw an exception). */
143 {
144 sigset_t set;
145 sigemptyset (&set);
146 sigaddset (&set, signum);
147 sigprocmask (SIG_UNBLOCK, &set, NULL);
148 }
149#endif
150 scm_system_async_mark (signal_async);
ee149d03 151 errno = saved_errno;
e1a191a8 152}
0f2d19dd 153
e1a191a8
GH
154static SCM
155sys_deliver_signals (void)
156{
157 int i;
158
159 for (i = 0; i < NSIG; i++)
160 {
161 if (got_signal[i])
162 {
cc0b3312
GH
163 /* The flag is reset before calling the handler in case the
164 handler doesn't return. If the handler doesn't return
165 but leaves other signals flagged, they their handlers
166 will be applied some time later when the async is checked
167 again. It would probably be better to reset the flags
168 after doing a longjmp. */
e1a191a8
GH
169 got_signal[i] = 0;
170#ifndef HAVE_SIGACTION
171 signal (i, take_signal);
172#endif
2ad6b1a5
GH
173 scm_apply (SCM_VELTS (*signal_handlers)[i],
174 scm_listify (SCM_MAKINUM (i), SCM_UNDEFINED),
175 SCM_EOL);
e1a191a8
GH
176 }
177 }
178 return SCM_UNSPECIFIED;
0f2d19dd
JB
179}
180
e1a191a8 181/* user interface for installation of signal handlers. */
a1ec6916 182SCM_DEFINE(scm_sigaction, "sigaction", 1, 2, 0,
1bbd0b84 183 (SCM signum, SCM handler, SCM flags),
4079f87e
GB
184"Install or report the signal hander for a specified signal.
185
186@var{signum} is the signal number, which can be specified using the value
187of variables such as @code{SIGINT}.
188
189If @var{action} is omitted, @code{sigaction} returns a pair: the
190CAR is the current
191signal hander, which will be either an integer with the value @code{SIG_DFL}
192(default action) or @code{SIG_IGN} (ignore), or the Scheme procedure which
193handles the signal, or @code{#f} if a non-Scheme procedure handles the
194signal. The CDR contains the current @code{sigaction} flags for the handler.
195
196If @var{action} is provided, it is installed as the new handler for
197@var{signum}. @var{action} can be a Scheme procedure taking one
198argument, or the value of @code{SIG_DFL} (default action) or
199@code{SIG_IGN} (ignore), or @code{#f} to restore whatever signal handler
200was installed before @code{sigaction} was first used. Flags can
201optionally be specified for the new handler (@code{SA_RESTART} will
202always be added if it's available and the system is using rstartable
203system calls.) The return value is a pair with information about the
204old handler as described above.
205
206This interface does not provide access to the \"signal blocking\"
207facility. Maybe this is not needed, since the thread support may
208provide solutions to the problem of consistent access to data
209structures.")
1bbd0b84 210#define FUNC_NAME s_scm_sigaction
e1a191a8
GH
211{
212 int csig;
213#ifdef HAVE_SIGACTION
214 struct sigaction action;
215 struct sigaction old_action;
216#else
217 SIGRETTYPE (* chandler) (int);
218 SIGRETTYPE (* old_chandler) (int);
219#endif
220 int query_only = 0;
221 int save_handler = 0;
222 SCM *scheme_handlers = SCM_VELTS (*signal_handlers);
223 SCM old_handler;
224
47c6b75e 225 SCM_VALIDATE_INUM_COPY(1,signum,csig);
7ee92fce
GH
226#if defined(HAVE_SIGACTION)
227#if defined(SA_RESTART) && defined(HAVE_RESTARTABLE_SYSCALLS)
228 /* don't allow SA_RESTART to be omitted if HAVE_RESTARTABLE_SYSCALLS
229 is defined, since libguile would be likely to produce spurious
230 EINTR errors. */
e1a191a8
GH
231 action.sa_flags = SA_RESTART;
232#else
233 action.sa_flags = 0;
234#endif
235 if (!SCM_UNBNDP (flags))
236 {
47c6b75e 237 SCM_VALIDATE_INUM(3,flags);
e1a191a8
GH
238 action.sa_flags |= SCM_INUM (flags);
239 }
240 sigemptyset (&action.sa_mask);
241#endif
242 SCM_DEFER_INTS;
243 old_handler = scheme_handlers[csig];
244 if (SCM_UNBNDP (handler))
245 query_only = 1;
7ee92fce 246 else if (scm_integer_p (handler) == SCM_BOOL_T)
e1a191a8 247 {
1bbd0b84
GB
248 if (SCM_NUM2LONG (2,handler) == (long) SIG_DFL
249 || SCM_NUM2LONG (2,handler) == (long) SIG_IGN)
e1a191a8
GH
250 {
251#ifdef HAVE_SIGACTION
252 action.sa_handler = (SIGRETTYPE (*) (int)) SCM_INUM (handler);
253#else
254 chandler = (SIGRETTYPE (*) (int)) SCM_INUM (handler);
255#endif
256 scheme_handlers[csig] = SCM_BOOL_F;
257 }
258 else
1bbd0b84 259 SCM_OUT_OF_RANGE (2, handler);
e1a191a8
GH
260 }
261 else if (SCM_FALSEP (handler))
262 {
263 /* restore the default handler. */
264#ifdef HAVE_SIGACTION
265 if (orig_handlers[csig].sa_handler == SIG_ERR)
266 query_only = 1;
267 else
268 {
269 action = orig_handlers[csig];
270 orig_handlers[csig].sa_handler = SIG_ERR;
271 scheme_handlers[csig] = SCM_BOOL_F;
272 }
273#else
274 if (orig_handlers[csig] == SIG_ERR)
275 query_only = 1;
276 else
277 {
278 chandler = orig_handlers[csig];
279 orig_handlers[csig] = SIG_ERR;
280 scheme_handlers[csig] = SCM_BOOL_F;
281 }
282#endif
283 }
284 else
285 {
6b5a304f 286 SCM_VALIDATE_NIM (2,handler);
e1a191a8
GH
287#ifdef HAVE_SIGACTION
288 action.sa_handler = take_signal;
289 if (orig_handlers[csig].sa_handler == SIG_ERR)
290 save_handler = 1;
291#else
292 chandler = take_signal;
293 if (orig_handlers[csig] == SIG_ERR)
294 save_handler = 1;
295#endif
296 scheme_handlers[csig] = handler;
297 }
298#ifdef HAVE_SIGACTION
299 if (query_only)
300 {
301 if (sigaction (csig, 0, &old_action) == -1)
1bbd0b84 302 SCM_SYSERROR;
e1a191a8
GH
303 }
304 else
305 {
306 if (sigaction (csig, &action , &old_action) == -1)
1bbd0b84 307 SCM_SYSERROR;
e1a191a8
GH
308 if (save_handler)
309 orig_handlers[csig] = old_action;
310 }
311 if (old_action.sa_handler == SIG_DFL || old_action.sa_handler == SIG_IGN)
7ee92fce 312 old_handler = scm_long2num ((long) old_action.sa_handler);
e1a191a8
GH
313 SCM_ALLOW_INTS;
314 return scm_cons (old_handler, SCM_MAKINUM (old_action.sa_flags));
315#else
316 if (query_only)
317 {
318 if ((old_chandler = signal (csig, SIG_IGN)) == SIG_ERR)
1bbd0b84 319 SCM_SYSERROR;
e1a191a8 320 if (signal (csig, old_chandler) == SIG_ERR)
1bbd0b84 321 SCM_SYSERROR;
e1a191a8
GH
322 }
323 else
324 {
325 if ((old_chandler = signal (csig, chandler)) == SIG_ERR)
1bbd0b84 326 SCM_SYSERROR;
e1a191a8
GH
327 if (save_handler)
328 orig_handlers[csig] = old_chandler;
329 }
330 if (old_chandler == SIG_DFL || old_chandler == SIG_IGN)
7ee92fce 331 old_handler = scm_long2num (old_chandler);
e1a191a8
GH
332 SCM_ALLOW_INTS;
333 return scm_cons (old_handler, SCM_MAKINUM (0));
0f2d19dd 334#endif
e1a191a8 335}
1bbd0b84 336#undef FUNC_NAME
e1a191a8 337
a1ec6916 338SCM_DEFINE (scm_restore_signals, "restore-signals", 0, 0, 0,
1bbd0b84 339 (void),
4079f87e
GB
340"Return all signal handlers to the values they had before any call to
341@code{sigaction} was made. The return value is unspecified.")
1bbd0b84 342#define FUNC_NAME s_scm_restore_signals
e1a191a8
GH
343{
344 int i;
345 SCM *scheme_handlers = SCM_VELTS (*signal_handlers);
346
347 for (i = 0; i < NSIG; i++)
348 {
349#ifdef HAVE_SIGACTION
350 if (orig_handlers[i].sa_handler != SIG_ERR)
351 {
352 if (sigaction (i, &orig_handlers[i], NULL) == -1)
1bbd0b84 353 SCM_SYSERROR;
e1a191a8
GH
354 orig_handlers[i].sa_handler = SIG_ERR;
355 scheme_handlers[i] = SCM_BOOL_F;
356 }
357#else
358 if (orig_handlers[i] != SIG_ERR)
359 {
360 if (signal (i, orig_handlers[i]) == SIG_ERR)
1bbd0b84 361 SCM_SYSERROR;
e1a191a8
GH
362 orig_handlers[i] = SIG_ERR;
363 scheme_handlers[i] = SCM_BOOL_F;
364 }
365#endif
366 }
367 return SCM_UNSPECIFIED;
368}
1bbd0b84 369#undef FUNC_NAME
0f2d19dd 370
a1ec6916 371SCM_DEFINE(scm_alarm, "alarm", 1, 0, 0,
1bbd0b84 372 (SCM i),
4079f87e
GB
373"Set a timer to raise a @code{SIGALRM} signal after the specified
374number of seconds (an integer). It's advisable to install a signal
375handler for
376@code{SIGALRM} beforehand, since the default action is to terminate
377the process.
378
379The return value indicates the time remaining for the previous alarm,
380if any. The new value replaces the previous alarm. If there was
381no previous alarm, the return value is zero.")
1bbd0b84 382#define FUNC_NAME s_scm_alarm
0f2d19dd
JB
383{
384 unsigned int j;
47c6b75e 385 SCM_VALIDATE_INUM(1,i);
e1a191a8 386 j = alarm (SCM_INUM (i));
0f2d19dd
JB
387 return SCM_MAKINUM (j);
388}
1bbd0b84 389#undef FUNC_NAME
0f2d19dd 390
0e958795 391#ifdef HAVE_PAUSE
a1ec6916 392SCM_DEFINE(scm_pause, "pause", 0, 0, 0,
1bbd0b84 393 (),
4079f87e
GB
394"Pause the current process (thread?) until a signal arrives whose
395action is to either terminate the current process or invoke a
396handler procedure. The return value is unspecified.")
1bbd0b84 397#define FUNC_NAME s_scm_pause
0f2d19dd
JB
398{
399 pause ();
400 return SCM_UNSPECIFIED;
401}
1bbd0b84 402#undef FUNC_NAME
0e958795 403#endif
0f2d19dd 404
a1ec6916 405SCM_DEFINE(scm_sleep, "sleep", 1, 0, 0,
1bbd0b84 406 (SCM i),
4079f87e
GB
407"Wait for the given number of seconds (an integer) or until a signal
408arrives. The return value is zero if the time elapses or the number
409of seconds remaining otherwise.")
1bbd0b84 410#define FUNC_NAME s_scm_sleep
0f2d19dd 411{
b74f4728 412 unsigned long j;
47c6b75e 413 SCM_VALIDATE_INUM_MIN(1,i,0);
b74f4728
JB
414#ifdef USE_THREADS
415 j = scm_thread_sleep (SCM_INUM(i));
416#else
e1a191a8 417 j = sleep (SCM_INUM(i));
b74f4728
JB
418#endif
419 return scm_ulong2num (j);
0f2d19dd 420}
1bbd0b84 421#undef FUNC_NAME
0f2d19dd 422
b74f4728 423#if defined(USE_THREADS) || defined(HAVE_USLEEP)
a1ec6916 424SCM_DEFINE(scm_usleep, "usleep", 1, 0, 0,
1bbd0b84
GB
425 (SCM i),
426"")
427#define FUNC_NAME s_scm_usleep
ce874f2d 428{
47c6b75e 429 SCM_VALIDATE_INUM_MIN(1,i,0);
b74f4728
JB
430
431#ifdef USE_THREADS
432 /* If we have threads, we use the thread system's sleep function. */
433 {
434 unsigned long j = scm_thread_usleep (SCM_INUM (i));
435 return scm_ulong2num (j);
436 }
437#else
0935d604
MD
438#ifdef USLEEP_RETURNS_VOID
439 usleep (SCM_INUM (i));
440 return SCM_INUM0;
441#else
b74f4728
JB
442 {
443 int j = usleep (SCM_INUM (i));
444 return SCM_MAKINUM (j);
445 }
0935d604 446#endif
ce874f2d 447#endif
b74f4728 448}
1bbd0b84 449#undef FUNC_NAME
b74f4728 450#endif /* GUILE_ISELECT || HAVE_USLEEP */
ce874f2d 451
a1ec6916 452SCM_DEFINE(scm_raise, "raise", 1, 0, 0,
1bbd0b84 453 (SCM sig),
4079f87e
GB
454"
455Sends a specified signal @var{sig} to the current process, where
456@var{sig} is as described for the kill procedure.")
1bbd0b84 457#define FUNC_NAME s_scm_raise
0f2d19dd 458{
47c6b75e 459 SCM_VALIDATE_INUM(1,sig);
e1a191a8
GH
460 SCM_DEFER_INTS;
461 if (kill (getpid (), (int) SCM_INUM (sig)) != 0)
1bbd0b84 462 SCM_SYSERROR;
e1a191a8
GH
463 SCM_ALLOW_INTS;
464 return SCM_UNSPECIFIED;
0f2d19dd 465}
1bbd0b84 466#undef FUNC_NAME
0f2d19dd
JB
467
468\f
0f2d19dd 469
e1a191a8
GH
470void
471scm_init_scmsigs ()
0f2d19dd 472{
e1a191a8
GH
473 SCM thunk;
474 int i;
475
476 signal_handlers =
477 SCM_CDRLOC (scm_sysintern ("signal-handlers",
478 scm_make_vector (SCM_MAKINUM (NSIG),
e1a191a8
GH
479 SCM_BOOL_F)));
480 thunk = scm_make_gsubr ("%deliver-signals", 0, 0, 0,
481 sys_deliver_signals);
482 signal_async = scm_system_async (thunk);
483
484 for (i = 0; i < NSIG; i++)
485 {
486 got_signal[i] = 0;
487#ifdef HAVE_SIGACTION
488 orig_handlers[i].sa_handler = SIG_ERR;
840ae05d 489
e1a191a8
GH
490#else
491 orig_handlers[i] = SIG_ERR;
0f2d19dd 492#endif
840ae05d 493
08b8c694 494#ifdef HAVE_RESTARTABLE_SYSCALLS
7ee92fce
GH
495 /* If HAVE_RESTARTABLE_SYSCALLS is defined, it's important that
496 signals really are restartable. don't rely on the same
497 run-time that configure got: reset the default for every signal.
498 */
499#ifdef HAVE_SIGINTERRUPT
500 siginterrupt (i, 0);
de881428 501#elif defined(SA_RESTART)
840ae05d
JB
502 {
503 struct sigaction action;
504
505 sigaction (i, NULL, &action);
506 if (!(action.sa_flags & SA_RESTART))
507 {
508 action.sa_flags &= SA_RESTART;
509 sigaction (i, &action, NULL);
510 }
511 }
7ee92fce
GH
512#endif
513 /* if neither siginterrupt nor SA_RESTART are available we may
514 as well assume that signals are always restartable. */
840ae05d 515#endif
e1a191a8 516 }
1cc91f1b 517
e1a191a8
GH
518 scm_sysintern ("NSIG", scm_long2num (NSIG));
519 scm_sysintern ("SIG_IGN", scm_long2num ((long) SIG_IGN));
520 scm_sysintern ("SIG_DFL", scm_long2num ((long) SIG_DFL));
521#ifdef SA_NOCLDSTOP
522 scm_sysintern ("SA_NOCLDSTOP", scm_long2num (SA_NOCLDSTOP));
0f2d19dd 523#endif
e1a191a8
GH
524#ifdef SA_RESTART
525 scm_sysintern ("SA_RESTART", scm_long2num (SA_RESTART));
0f2d19dd 526#endif
1cc91f1b 527
0f2d19dd
JB
528#include "scmsigs.x"
529}
530