/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- display_sigset
- validsigp
- sigset_op
- Scm_SignalName
- default_sighandler
- exit_sighandler
- through_sighandler
- sigset_print
- sigset_allocate
- make_sigset
- Scm_SysSigsetOp
- Scm_SysSigsetFill
- sig_handle
- Scm_SignalQueueInit
- Scm_SigCheck
- Scm_SetSignalHandler
- Scm_GetSignalHandler
- Scm_GetSignalHandlers
- Scm_GetMasterSigmask
- Scm_SetMasterSigmask
- Scm_SysSigmask
- scm_sigsuspend
- Scm_SigSuspend
- Scm_Pause
- sigaction
- Scm__InitSignal
1 /*
2 * signal.c - signal handling
3 *
4 * Copyright (c) 2000-2005 Shiro Kawai, All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the authors nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id: signal.c,v 1.33 2005/06/30 22:48:31 shirok Exp $
34 */
35
36 #include <stdlib.h>
37 #include <signal.h>
38 #define LIBGAUCHE_BODY
39 #include "gauche.h"
40 #include "gauche/vm.h"
41 #include "gauche/class.h"
42
43 /* Signals
44 *
45 * C-application that embeds Gauche can specify a set of signals
46 * that Gauche can handle.
47 *
48 * The Scheme program can specify which signal it wants to handle
49 * by setting a Scheme signal handler. Gauche registers the internal
50 * signal handler for the specified signal. What the internal signal
51 * handler does is just queue the signal in the VM's signal queue.
52 * VM calls Scm_SigCheck() at the "safe" point, which flushes
53 * the signal queue and make a list of handlers to be called.
54 *
55 * Scheme signal handler vector is shared by all threads. Each
56 * thread can set a signal mask. By default, only the primordial
57 * thread handles signals.
58 *
59 * For most signals, Gauche installs the default signal handler that
60 * raises 'unhandled signal exception'. For other signals, Gauche lets
61 * the system to handle the signal unless the Scheme program installs
62 * the handler. Such signals are the ones that can't be caught, or
63 * are ignored by default. SIGPWR and SIGXCPU are also left to the system
64 * since GC uses it in the Linux/pthread environment.
65 */
66
67 #ifndef __MINGW32__
68 #ifdef GAUCHE_USE_PTHREADS
69 #define SIGPROCMASK pthread_sigmask
70 #else
71 #define SIGPROCMASK sigprocmask
72 #endif
73 #else /* __MINGW32__ */
74 /* This isn't correct (we need some mechanism to block the signal),
75 but just for the time being ... */
76 #define SIGPROCMASK(mode, set, omask) (0)
77 #endif /* __MINGW32__ */
78
79 /* Master signal handler vector. */
80 static struct sigHandlersRec {
81 ScmObj handlers[NSIG]; /* Scheme signal handlers */
82 sigset_t masterSigset; /* The signals Gauche is _allowed_ to handle.
83 set by Scm_SetMasterSigset.
84 For some signals in this set Gauche sets
85 the default signal handlers; for other
86 signals in this set Gauche leaves them
87 for the system to handle. These can be
88 overridden by Scm_SetSignalHandler. */
89 ScmInternalMutex mutex;
90 } sigHandlers = {{NULL}};
91
92 /* Table of signals and its initial behavior. */
93 #define SIGDEF_NOHANDLE 0 /* Gauche doesn't install a signal handler,
94 leaving it to the application. */
95 #define SIGDEF_DFL 1 /* Gauche resets the singal handler to
96 SIG_DFL. */
97 #define SIGDEF_ERROR 2 /* Gauche installs a default signal handler
98 that raises an error. */
99 #define SIGDEF_EXIT 3 /* Gauche installs a handler that calls
100 Scm_Exit(). */
101
102 #define SIGDEF(x, flag) { #x, x, flag }
103
104 static struct sigdesc {
105 const char *name;
106 int num;
107 int defaultHandle;
108 } sigDesc[] = {
109 #ifdef SIGHUP
110 SIGDEF(SIGHUP, SIGDEF_EXIT), /* Hangup (POSIX) */
111 #endif
112 SIGDEF(SIGINT, SIGDEF_ERROR), /* Interrupt (ANSI) */
113 #ifdef SIGQUIT
114 SIGDEF(SIGQUIT, SIGDEF_EXIT), /* Quit (POSIX) */
115 #endif
116 SIGDEF(SIGILL, SIGDEF_NOHANDLE), /* Illegal instruction (ANSI) */
117 #ifdef SIGTRAP
118 SIGDEF(SIGTRAP, SIGDEF_ERROR), /* Trace trap */
119 #endif
120 SIGDEF(SIGABRT, SIGDEF_NOHANDLE), /* Abort (ANSI) */
121 #ifdef SIGIOT
122 SIGDEF(SIGIOT, SIGDEF_ERROR), /* IOT trap (4.2 BSD) */
123 #endif
124 #ifdef SIGBUS
125 SIGDEF(SIGBUS, SIGDEF_NOHANDLE), /* BUS error (4.2 BSD) */
126 #endif
127 SIGDEF(SIGFPE, SIGDEF_ERROR), /* Floating-point exception (ANSI) */
128 #ifdef SIGKILL
129 SIGDEF(SIGKILL, SIGDEF_NOHANDLE), /* Kill, unblockable (POSIX) */
130 #endif
131 #ifdef SIGUSR1
132 SIGDEF(SIGUSR1, SIGDEF_ERROR), /* User-defined signal 1 (POSIX) */
133 #endif
134 SIGDEF(SIGSEGV, SIGDEF_NOHANDLE), /* Segmentation violation (ANSI) */
135 #ifdef SIGUSR2
136 SIGDEF(SIGUSR2, SIGDEF_ERROR), /* User-defined signal 2 (POSIX) */
137 #endif
138 #ifdef SIGPIPE
139 SIGDEF(SIGPIPE, SIGDEF_ERROR), /* Broken pipe (POSIX) */
140 #endif
141 #ifdef SIGALRM
142 SIGDEF(SIGALRM, SIGDEF_ERROR), /* Alarm clock (POSIX) */
143 #endif
144 SIGDEF(SIGTERM, SIGDEF_EXIT), /* Termination (ANSI) */
145 #ifdef SIGSTKFLT
146 SIGDEF(SIGSTKFLT, SIGDEF_ERROR), /* Stack fault */
147 #endif
148 #ifdef SIGCHLD
149 SIGDEF(SIGCHLD, SIGDEF_DFL), /* Child status has changed (POSIX) */
150 #endif
151 #ifdef SIGCONT
152 SIGDEF(SIGCONT, SIGDEF_NOHANDLE), /* Continue (POSIX) */
153 #endif
154 #ifdef SIGSTOP
155 SIGDEF(SIGSTOP, SIGDEF_NOHANDLE), /* Stop, unblockable (POSIX) */
156 #endif
157 #ifdef SIGTSTP
158 SIGDEF(SIGTSTP, SIGDEF_NOHANDLE), /* Keyboard stop (POSIX) */
159 #endif
160 #ifdef SIGTTIN
161 SIGDEF(SIGTTIN, SIGDEF_NOHANDLE), /* Background read from tty (POSIX) */
162 #endif
163 #ifdef SIGTTOU
164 SIGDEF(SIGTTOU, SIGDEF_NOHANDLE), /* Background write to tty (POSIX) */
165 #endif
166 #ifdef SIGURG
167 SIGDEF(SIGURG, SIGDEF_NOHANDLE), /* Urgent condition on socket (4.2 BSD) */
168 #endif
169 #ifdef SIGXCPU
170 SIGDEF(SIGXCPU, SIGDEF_NOHANDLE), /* CPU limit exceeded (4.2 BSD) */
171 #endif
172 #ifdef SIGXFSZ
173 SIGDEF(SIGXFSZ, SIGDEF_ERROR), /* File size limit exceeded (4.2 BSD) */
174 #endif
175 #ifdef SIGVTALRM
176 SIGDEF(SIGVTALRM, SIGDEF_ERROR), /* Virtual alarm clock (4.2 BSD) */
177 #endif
178 #ifdef SIGPROF
179 SIGDEF(SIGPROF, SIGDEF_ERROR), /* Profiling alarm clock (4.2 BSD) */
180 #endif
181 #ifdef SIGWINCH
182 SIGDEF(SIGWINCH, SIGDEF_NOHANDLE),/* Window size change (4.3 BSD, Sun) */
183 #endif
184 #ifdef SIGPOLL
185 SIGDEF(SIGPOLL, SIGDEF_ERROR), /* Pollable event occurred (System V) */
186 #endif
187 #ifdef SIGIO
188 SIGDEF(SIGIO, SIGDEF_ERROR), /* I/O now possible (4.2 BSD) */
189 #endif
190 #ifdef SIGPWR
191 SIGDEF(SIGPWR, SIGDEF_NOHANDLE), /* Power failure restart (System V) */
192 #endif
193 { NULL, -1 }
194 };
195
196 /*
197 * utilities for sigset
198 */
199 static void display_sigset(sigset_t *set, ScmPort *port)
200 {
201 struct sigdesc *desc = sigDesc;
202 int cnt = 0;
203 for (; desc->name; desc++) {
204 if (sigismember(set, desc->num)) {
205 if (cnt++) Scm_Putc('|', port);
206 Scm_Putz(desc->name+3, -1, port);
207 }
208 }
209 }
210
211 static int validsigp(int signum)
212 {
213 if (signum > 0) {
214 struct sigdesc *desc = sigDesc;
215 for (; desc->name; desc++) {
216 if (desc->num == signum) return TRUE;
217 }
218 }
219 return FALSE;
220 }
221
222 static void sigset_op(sigset_t *s1, sigset_t *s2, int delp)
223 {
224 struct sigdesc *desc = sigDesc;
225 for (; desc->name; desc++) {
226 if (sigismember(s2, desc->num)) {
227 if (!delp) sigaddset(s1, desc->num);
228 else sigdelset(s1, desc->num);
229 }
230 }
231 }
232
233 ScmObj Scm_SignalName(int signum)
234 {
235 struct sigdesc *desc = sigDesc;
236 for (; desc->name; desc++) {
237 if (desc->num == signum) {
238 return SCM_MAKE_STR_IMMUTABLE(desc->name);
239 }
240 }
241 return SCM_FALSE;
242 }
243
244 /*
245 * default handler
246 */
247 /* For most signals, default handler raises an error. */
248 static ScmObj default_sighandler(ScmObj *args, int nargs, void *data)
249 {
250 int signum;
251 struct sigdesc *desc;
252 const char *name = NULL;
253
254 SCM_ASSERT(nargs == 1 && SCM_INTP(args[0]));
255 signum = SCM_INT_VALUE(args[0]);
256
257 for (desc = sigDesc; desc->name; desc++) {
258 if (desc->num == signum) {
259 name = desc->name;
260 break;
261 }
262 }
263 if (name) {
264 Scm_Error("unhandled signal %d (%s)", signum, name);
265 } else {
266 Scm_Error("unhandled signal %d (unknown signal)", signum);
267 }
268 return SCM_UNDEFINED; /* dummy */
269 }
270
271 static SCM_DEFINE_STRING_CONST(default_sighandler_name,
272 "%default-signal-handler", 23, 23);
273 static SCM_DEFINE_SUBR(default_sighandler_stub, 1, 0,
274 SCM_OBJ(&default_sighandler_name),
275 default_sighandler,
276 NULL, NULL);
277
278 #define DEFAULT_SIGHANDLER SCM_OBJ(&default_sighandler_stub)
279
280 /* For some signals, exits. */
281 static ScmObj exit_sighandler(ScmObj *args, int nargs, void *data)
282 {
283 Scm_Exit(0);
284 return SCM_UNDEFINED; /* dummy */
285 }
286
287 static SCM_DEFINE_STRING_CONST(exit_sighandler_name,
288 "%exit-signal-handler", 20, 20);
289 static SCM_DEFINE_SUBR(exit_sighandler_stub, 1, 0,
290 SCM_OBJ(&exit_sighandler_name),
291 exit_sighandler,
292 NULL, NULL);
293
294 #define EXIT_SIGHANDLER SCM_OBJ(&exit_sighandler_stub)
295
296 /* For some signals, gauche does nothing */
297 static ScmObj through_sighandler(ScmObj *args, int nargs, void *data)
298 {
299 return SCM_UNDEFINED;
300 }
301
302 static SCM_DEFINE_STRING_CONST(through_sighandler_name,
303 "%through-signal-handler", 20, 20);
304 static SCM_DEFINE_SUBR(through_sighandler_stub, 1, 0,
305 SCM_OBJ(&through_sighandler_name),
306 through_sighandler,
307 NULL, NULL);
308
309 #define THROUGH_SIGHANDLER SCM_OBJ(&through_sighandler_stub)
310
311
312 /*
313 * sigset class
314 */
315
316 static void sigset_print(ScmObj obj, ScmPort *out, ScmWriteContext *ctx);
317 static ScmObj sigset_allocate(ScmClass *klass, ScmObj initargs);
318
319 SCM_DEFINE_BUILTIN_CLASS(Scm_SysSigsetClass, sigset_print,
320 NULL, NULL, sigset_allocate, SCM_CLASS_DEFAULT_CPL);
321
322 void sigset_print(ScmObj obj, ScmPort *out, ScmWriteContext *ctx)
323 {
324 Scm_Printf(out, "#<sys-sigset [");
325 display_sigset(&SCM_SYS_SIGSET(obj)->set, out);
326 Scm_Printf(out, "]>");
327 }
328
329 ScmObj sigset_allocate(ScmClass *klass, ScmObj initargs)
330 {
331 ScmSysSigset *s = SCM_ALLOCATE(ScmSysSigset, klass);
332 SCM_SET_CLASS(s, klass);
333 sigemptyset(&s->set);
334 return SCM_OBJ(s);
335 }
336
337 ScmSysSigset *make_sigset(void)
338 {
339 return SCM_SYS_SIGSET(sigset_allocate(SCM_CLASS_SYS_SIGSET, SCM_NIL));
340 }
341
342 /* multifunction on sigset
343 if delp == FALSE, signals are added to set.
344 else, signals are removed from set.
345 signals is a list of either integer or #t (all signals), or other sigset.
346 */
347 ScmObj Scm_SysSigsetOp(ScmSysSigset *set, ScmObj signals, int delp)
348 {
349 ScmObj cp;
350
351 if (!SCM_PAIRP(signals)) {
352 Scm_Error("list of signals required, but got %S", signals);
353 }
354 SCM_FOR_EACH(cp, signals) {
355 ScmObj s = SCM_CAR(cp);
356 if (SCM_TRUEP(s)) {
357 if (!delp) sigfillset(&set->set);
358 else sigemptyset(&set->set);
359 break;
360 }
361 if (SCM_SYS_SIGSET_P(s)) {
362 sigset_op(&set->set, &SCM_SYS_SIGSET(s)->set, delp);
363 continue;
364 }
365 if (!SCM_INTP(s) || !validsigp(SCM_INT_VALUE(s))) {
366 Scm_Error("bad signal number %S", s);
367 }
368 if (!delp) sigaddset(&set->set, SCM_INT_VALUE(s));
369 else sigdelset(&set->set, SCM_INT_VALUE(s));
370 }
371 return SCM_OBJ(set);
372 }
373
374 /* fill or empty sigset. */
375 ScmObj Scm_SysSigsetFill(ScmSysSigset *set, int emptyp)
376 {
377 if (emptyp) sigemptyset(&(set->set));
378 else sigfillset(&(set->set));
379 return SCM_OBJ(set);
380 }
381
382 /*
383 * Signal handling
384 */
385
386 /*
387 * System's signal handler - just enqueue the signal
388 */
389
390 static void sig_handle(int signum)
391 {
392 ScmVM *vm = Scm_VM();
393 /* It is possible that vm == NULL at this point, if the thread is
394 terminating and in the cleanup phase. */
395 if (vm == NULL) return;
396
397 if (vm->sigq.overflow) {
398 /* TODO: what should we do? */
399 Scm_Warn("Signal queue overflow\n");
400 return;
401 }
402 vm->sigq.queue[vm->sigq.tail++] = signum;
403 if (vm->sigq.tail >= SCM_VM_SIGQ_SIZE) {
404 vm->sigq.tail = 0;
405 }
406 if (vm->sigq.tail == vm->sigq.head) vm->sigq.overflow++;
407 vm->queueNotEmpty |= SCM_VM_SIGQ_MASK;
408 }
409
410 /*
411 * Initializes signal queue
412 */
413 void Scm_SignalQueueInit(ScmSignalQueue* q)
414 {
415 int i;
416 for (i=0; i<SCM_VM_SIGQ_SIZE; i++) q->queue[i] = -1;
417 q->head = q->tail = 0;
418 q->overflow = 0;
419 q->pending = SCM_NIL;
420 }
421
422 /*
423 * Called from VM's safe point to flush the queued signals.
424 * VM already checks there's a pending signal in the queue.
425 */
426 void Scm_SigCheck(ScmVM *vm)
427 {
428 ScmObj tail, cell, sp;
429 ScmSignalQueue *q = &vm->sigq;
430 sigset_t omask;
431 int sigQsize, i;
432 int sigQcopy[SCM_VM_SIGQ_SIZE]; /* copy of signal queue */
433
434 /* Copy VM's signal queue to local storage, for we can't call
435 storage allocation during blocking signals. */
436 SIGPROCMASK(SIG_BLOCK, &sigHandlers.masterSigset, &omask);
437 for (sigQsize = 0; q->head != q->tail; sigQsize++) {
438 sigQcopy[sigQsize] = q->queue[q->head++];
439 if (q->head >= SCM_VM_SIGQ_SIZE) q->head = 0;
440 }
441 q->overflow = 0; /*TODO: we should do something*/
442 vm->queueNotEmpty &= ~SCM_VM_SIGQ_MASK;
443 SIGPROCMASK(SIG_SETMASK, &omask, NULL);
444
445 /* Now, prepare queued signal handlers
446 If an error is thrown in this loop, the queued signals will be
447 lost---it doesn't look like so, but I may overlook something. */
448 tail = q->pending;
449 if (!SCM_NULLP(tail)) tail = Scm_LastPair(tail);
450 for (i=0; i<sigQsize; i++) {
451 if (SCM_PROCEDUREP(sigHandlers.handlers[sigQcopy[i]])) {
452 cell = Scm_Acons(sigHandlers.handlers[sigQcopy[i]],
453 SCM_MAKE_INT(sigQcopy[i]),
454 SCM_NIL);
455 if (SCM_NULLP(tail)) {
456 q->pending = tail = cell;
457 } else {
458 SCM_SET_CDR(tail, cell);
459 tail = SCM_CDR(tail);
460 }
461 }
462 }
463
464 /* Call the queued signal handlers. If an error is thrown in one
465 of those handlers, the rest of handlers remain in the queue. */
466 /* TODO: if VM is active, it'd be better to make the active VM to handle
467 those handler procs, instead of calling Scm_Eval. */
468 SCM_FOR_EACH(sp, q->pending) {
469 ScmObj h = SCM_CAR(sp);
470 q->pending = SCM_CDR(sp);
471 Scm_Apply(SCM_CAR(h), SCM_LIST1(SCM_CDR(h)));
472 }
473 }
474
475 /*
476 * set-signal-handler!
477 */
478 ScmObj Scm_SetSignalHandler(ScmObj sigs, ScmObj handler)
479 {
480 struct sigaction act;
481 struct sigdesc *desc;
482 sigset_t sigset;
483 int badproc = FALSE, sigactionfailed = FALSE;
484
485 if (SCM_INTP(sigs)) {
486 int signum = SCM_INT_VALUE(sigs);
487 if (signum < 0 || signum >= NSIG) {
488 Scm_Error("bad signal number: %d", signum);
489 }
490 sigemptyset(&sigset);
491 sigaddset(&sigset, signum);
492 } else if (SCM_SYS_SIGSET_P(sigs)) {
493 sigset = SCM_SYS_SIGSET(sigs)->set;
494 } else {
495 Scm_Error("bad signal number: must be an integer signal number or a <sys-sigset> object, but got %S", sigs);
496 }
497
498 (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
499 if (SCM_TRUEP(handler)) {
500 act.sa_handler = SIG_DFL;
501 } else if (SCM_FALSEP(handler)) {
502 act.sa_handler = SIG_IGN;
503 } else if (SCM_PROCEDUREP(handler)
504 && SCM_PROCEDURE_TAKE_NARG_P(handler, 1)) {
505 act.sa_handler = sig_handle;
506 } else {
507 badproc = TRUE;
508 }
509 if (!badproc) {
510 sigemptyset(&act.sa_mask);
511 act.sa_flags = 0;
512 for (desc=sigDesc; desc->name; desc++) {
513 if (!sigismember(&sigset, desc->num)) continue;
514 if (!sigismember(&sigHandlers.masterSigset, desc->num)) continue;
515 if (sigaction(desc->num, &act, NULL) != 0) {
516 sigactionfailed = desc->num;
517 } else {
518 sigHandlers.handlers[desc->num] = handler;
519 }
520 }
521 }
522 (void)SCM_INTERNAL_MUTEX_UNLOCK(sigHandlers.mutex);
523 if (badproc) Scm_Error("bad signal handling procedure: must be either a procedure that takes at least one argument, #t, or #f, but got %S", handler);
524 if (sigactionfailed) Scm_Error("sigaction failed when setting a sighandler for signal %d", sigactionfailed);
525 return SCM_UNDEFINED;
526 }
527
528 ScmObj Scm_GetSignalHandler(int signum)
529 {
530 ScmObj r;
531 if (signum < 0 || signum >= NSIG) {
532 Scm_Error("bad signal number: %d", signum);
533 }
534 (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
535 r = sigHandlers.handlers[signum];
536 (void)SCM_INTERNAL_MUTEX_UNLOCK(sigHandlers.mutex);
537 return r;
538 }
539
540 ScmObj Scm_GetSignalHandlers(void)
541 {
542 ScmObj h = SCM_NIL, hp;
543 ScmObj handlers[NSIG];
544 struct sigdesc *desc;
545 sigset_t masterSet;
546 int i;
547
548 /* copy handler vector and master sig set locally, so that we won't
549 grab the lock for extensive time */
550 (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
551 for (i=0; i<NSIG; i++) handlers[i] = sigHandlers.handlers[i];
552 masterSet = sigHandlers.masterSigset;
553 (void)SCM_INTERNAL_MUTEX_UNLOCK(sigHandlers.mutex);
554
555 for (desc=sigDesc; desc->name; desc++) {
556 if (!sigismember(&masterSet, desc->num)) continue;
557 SCM_FOR_EACH(hp, h) {
558 if (SCM_EQ(SCM_CDAR(hp), handlers[desc->num])) {
559 sigaddset(&(SCM_SYS_SIGSET(SCM_CAAR(hp))->set), desc->num);
560 break;
561 }
562 }
563 if (SCM_NULLP(hp)) {
564 ScmSysSigset *set = make_sigset();
565 sigaddset(&(set->set), desc->num);
566 h = Scm_Acons(SCM_OBJ(set), handlers[desc->num], h);
567 }
568 }
569 return h;
570 }
571
572 /*
573 * set/get master signal
574 */
575 sigset_t Scm_GetMasterSigmask(void)
576 {
577 return sigHandlers.masterSigset;
578 }
579
580 /* this should be called before any thread is created. */
581 void Scm_SetMasterSigmask(sigset_t *set)
582 {
583 struct sigdesc *desc = sigDesc;
584 struct sigaction acton, actoff;
585
586 acton.sa_handler = (void(*)())sig_handle;
587 acton.sa_mask = *set;
588 acton.sa_flags = 0;
589 actoff.sa_handler = SIG_DFL;
590 sigemptyset(&actoff.sa_mask);
591 actoff.sa_flags = 0;
592
593 for (; desc->name; desc++) {
594 if (sigismember(&sigHandlers.masterSigset, desc->num)
595 && !sigismember(set, desc->num)) {
596 /* remove sighandler */
597 if (sigaction(desc->num, &actoff, NULL) != 0) {
598 Scm_SysError("sigaction on %d failed", desc->num);
599 }
600 sigHandlers.handlers[desc->num] = SCM_TRUE;
601 } else if (!sigismember(&sigHandlers.masterSigset, desc->num)
602 && sigismember(set, desc->num)) {
603 /* add sighandler if necessary */
604 if (desc->defaultHandle == SIGDEF_DFL) {
605 if (sigaction(desc->num, &actoff, NULL) != 0) {
606 Scm_SysError("sigaction on %d failed", desc->num);
607 }
608 sigHandlers.handlers[desc->num] = SCM_TRUE;
609 } else if (desc->defaultHandle != SIGDEF_NOHANDLE) {
610 if (sigaction(desc->num, &acton, NULL) != 0) {
611 Scm_SysError("sigaction on %d failed", desc->num);
612 }
613 switch (desc->defaultHandle) {
614 case SIGDEF_ERROR:
615 sigHandlers.handlers[desc->num] = DEFAULT_SIGHANDLER;
616 break;
617 case SIGDEF_EXIT:
618 sigHandlers.handlers[desc->num] = EXIT_SIGHANDLER;
619 break;
620 default:
621 Scm_Panic("Scm_SetMasterSigmask: can't be here");
622 }
623 }
624 }
625 }
626 sigHandlers.masterSigset = *set;
627 Scm_VM()->sigMask = sigHandlers.masterSigset;
628 }
629
630 /*
631 * set signal mask
632 */
633
634 ScmObj Scm_SysSigmask(int how, ScmSysSigset *newmask)
635 {
636 ScmSysSigset *oldmask = make_sigset();
637 if (how != SIG_SETMASK && how != SIG_BLOCK && how != SIG_UNBLOCK) {
638 Scm_Error("bad 'how' argument for signal mask action: %d", how);
639 }
640 if (SIGPROCMASK(how, &(newmask->set), &(oldmask->set)) != 0) {
641 Scm_Error("sigprocmask failed");
642 }
643 return SCM_OBJ(oldmask);
644 }
645
646 /*
647 * sigsuspend
648 */
649 static void scm_sigsuspend(sigset_t *mask)
650 {
651 #ifndef __MINGW32__
652 sigset_t omask;
653 ScmVM *vm = Scm_VM();
654 for (;;) {
655 SIGPROCMASK(SIG_BLOCK, &sigHandlers.masterSigset, &omask);
656 if (vm->sigq.tail != vm->sigq.head) {
657 SIGPROCMASK(SIG_SETMASK, &omask, NULL);
658 Scm_SigCheck(vm);
659 continue;
660 }
661 break;
662 }
663 sigsuspend(mask);
664 SIGPROCMASK(SIG_SETMASK, &omask, NULL);
665 SCM_SIGCHECK(vm);
666 #else /*__MINGW32__*/
667 Scm_Error("sigsuspend not supported on MinGW port");
668 #endif /*__MINGW32__*/
669 }
670
671 ScmObj Scm_SigSuspend(ScmSysSigset *mask)
672 {
673 scm_sigsuspend(&(mask->set));
674 return SCM_UNDEFINED;
675 }
676
677 /*
678 * Alternative of 'pause()'
679 * we can't use pause() reliably, since the process may miss a signal
680 * if it is delivered after the last call of Scm_SigCheck before pause();
681 * the signal is queued, but will never be processed until pause() returns
682 * by another signal.
683 */
684 ScmObj Scm_Pause(void)
685 {
686 sigset_t omask;
687 SIGPROCMASK(SIG_SETMASK, NULL, &omask);
688 scm_sigsuspend(&omask);
689 return SCM_UNDEFINED;
690 }
691
692 /*
693 * Emulation stubs for Windows/MinGW
694 */
695 #ifdef __MINGW32__
696
697 int sigaction(int signum, const struct sigaction *act,
698 struct sigaction *oact)
699 {
700 if (oact != NULL) {
701 Scm_Panic("sigaction() with oldact != NULL isn't supported on MinGW port");
702 }
703 if (signal(signum, act->sa_handler) == SIG_ERR) {
704 return -1;
705 } else {
706 return 0;
707 }
708 }
709 #endif /* __MINGW32__ */
710
711
712 /*
713 * initialize
714 */
715
716 void Scm__InitSignal(void)
717 {
718 ScmModule *mod = Scm_GaucheModule();
719 ScmObj defsigh_sym = Scm_Intern(&default_sighandler_name);
720 struct sigdesc *desc;
721 int i;
722
723 (void)SCM_INTERNAL_MUTEX_INIT(sigHandlers.mutex);
724 sigemptyset(&sigHandlers.masterSigset);
725 for (i=0; i<NSIG; i++) sigHandlers.handlers[i] = SCM_FALSE;
726
727 Scm_InitStaticClass(&Scm_SysSigsetClass, "<sys-sigset>",
728 mod, NULL, 0);
729
730 for (desc = sigDesc; desc->name; desc++) {
731 SCM_DEFINE(mod, desc->name, SCM_MAKE_INT(desc->num));
732 }
733 Scm_Define(mod, SCM_SYMBOL(defsigh_sym), DEFAULT_SIGHANDLER);
734 }