1 /*
2 * signal.c - signal handling
3 *
4 * Copyright (c) 2000-2020 Shiro Kawai <shiro@acm.org>
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
34 #define LIBGAUCHE_BODY
35 #include "gauche.h"
36 #include "gauche/vm.h"
37 #include "gauche/class.h"
38
39 /* Signals
40 *
41 * C-application that embeds Gauche can specify a set of signals
42 * that Gauche can handle.
43 *
44 * The Scheme program can specify which signal it wants to handle
45 * by setting a Scheme signal handler. Gauche registers the internal
46 * signal handler for the specified signal. What the internal signal
47 * handler does is just queue the signal in the VM's signal queue.
48 * VM calls Scm_SigCheck() at the "safe" point, which flushes
49 * the signal queue and make a list of handlers to be called.
50 *
51 * Scheme signal handler vector is shared by all threads. Each
52 * thread can set a signal mask. By default, only the primordial
53 * thread handles signals.
54 *
55 * For most signals, Gauche installs the default signal handler that
56 * raises 'unhandled signal exception'. For other signals, Gauche lets
57 * the system to handle the signal unless the Scheme program installs
58 * the handler. Such signals are the ones that can't be caught, or
59 * are ignored by default. SIGPWR and SIGXCPU are also left to the system
60 * since GC uses it in the Linux/pthread environment.
61 *
62 * About the signal behavior on windows, see "Note on windows port" below.
63 */
64 #if !defined(GAUCHE_WINDOWS)
65 # ifdef GAUCHE_USE_PTHREADS
66 # define SIGPROCMASK pthread_sigmask
67 # else
68 # define SIGPROCMASK sigprocmask
69 # endif
70 #else /* GAUCHE_WINDOWS */
71 /* emulation routine is defined below */
72 # define SIGPROCMASK sigprocmask_win
73 static int sigprocmask_win(int how, const sigset_t *set, sigset_t *oldset);
74 #endif /* GAUCHE_WINDOWS */
75
76 /* Master signal handler vector. */
77 static struct sigHandlersRec {
78 ScmObj handlers[SCM_NSIG]; /* Scheme signal handlers. This is #<undef> on
79 signals to which Gauche does not install
80 C-level signal handler (sig_handle). */
81 ScmSysSigset *masks[SCM_NSIG];/* Signal masks during executing Scheme
82 handlers. Can be NULL, which means
83 the handling signal(s) are blocked. */
84 sigset_t masterSigset; /* The signals Gauche is _allowed_ to handle.
85 set by Scm_SetMasterSigmask.
86 For some signals in this set Gauche sets
87 the default signal handlers; for other
88 signals in this set Gauche leaves them
89 for the system to handle. These can be
90 overridden by Scm_SetSignalHandler. */
91 ScmInternalMutex mutex;
92 } sigHandlers;
93
94 /* Maximum # of the same signals before it is processed by the VM loop.
95 If any one of signals exceeds this count, Gauche exits with Scm_Abort.
96 It is useful to terminate unresponsive program that are executing
97 long-running C-routine and do not returns to VM.
98 The actual limit can be changed at runtime by Scm_SetSignalPendingLimit().
99 If signalPendingLimit is 0, the number of pending signals is unlimited. */
100 #define SIGNAL_PENDING_LIMIT_DEFAULT 3
101 #define SIGNAL_PENDING_LIMIT_MAX 255
102
103 static unsigned int signalPendingLimit = SIGNAL_PENDING_LIMIT_DEFAULT;
104
105
106 /* Table of signals and its initial behavior. If Application asks
107 Gauche to handle a specific signal (via Scm_SetMasterSigmask),
108 Gauche installs a signal handler specified in this table.
109 (In general, the signals reserved by GC are excluded from the master
110 signal mask, so we don't need to consider them here. See main.c.)
111
112 Note on SIGPIPE behavior: The Unix convention is that the default
113 behavior or writing to closed pipe terminates the process. It is
114 suitable for small commands designed to be piped together, for
115 a failure of any one of the commands in the chunk causes
116 entire chain to be finished promptly. However it is rather an
117 annoyance if we use an fd for transient communication (e.g.
118 sockets, most notably). Since signal handlers are process-global,
119 it is quite tricky for general libraries/middlewares to control
120 SIGPIPE behavior transparently.
121
122 As a library, Gauche employs simpler model: Application will specify
123 which signals they want handle and which signals they want Gauche
124 to handle. Once app delegates handling of a specific signal,
125 Gauche has a right to install its own handler.
126
127 So, here's the deal: If the app wants to handle SIGPIPE by itself,
128 it's fine. By default SIGPIPE terminates the process. If the app
129 installs its own SIGPIPE handler that returns, then Gauche sees
130 EPIPE and raises <system-error>.
131
132 If the app let Gauche to handle SIGPIPE, we install our own handler,
133 which does nothing. Scheme code can handle the situation via EPIPE
134 <system-error>. To emulate Unix default behavior, however, EPIPE
135 caused by standard output and standard error will terminate the
136 process by default. It can be configured per-port basis.
137 */
138
139 #define SIGDEF_NOHANDLE 0 /* Gauche doesn't install a signal handler,
140 leaving it to the application. */
141 #define SIGDEF_DFL 1 /* Gauche resets the singal handler to
142 SIG_DFL. */
143 #define SIGDEF_ERROR 2 /* Gauche installs a default signal handler
144 that raises an error. */
145 #define SIGDEF_EXIT 3 /* Gauche installs a handler that calls
146 Scm_Exit(). */
147 #define SIGDEF_INDIFFERENT 4 /* Gauche installs a handler that does
148 nothing. */
149
150 #define SIGDEF(x, flag) { #x, x, flag }
151
152 static struct sigdesc {
153 const char *name;
154 int num;
155 int defaultHandle;
156 } sigDesc[] = {
157 #ifdef SIGHUP
158 SIGDEF(SIGHUP, SIGDEF_EXIT), /* Hangup (POSIX) */
159 #endif
160 SIGDEF(SIGINT, SIGDEF_ERROR), /* Interrupt (ANSI) */
161 #ifdef SIGQUIT
162 SIGDEF(SIGQUIT, SIGDEF_EXIT), /* Quit (POSIX) */
163 #endif
164 SIGDEF(SIGILL, SIGDEF_NOHANDLE), /* Illegal instruction (ANSI) */
165 #ifdef SIGTRAP
166 SIGDEF(SIGTRAP, SIGDEF_ERROR), /* Trace trap */
167 #endif
168 SIGDEF(SIGABRT, SIGDEF_NOHANDLE), /* Abort (ANSI) */
169 #ifdef SIGIOT
170 SIGDEF(SIGIOT, SIGDEF_ERROR), /* IOT trap (4.2 BSD) */
171 #endif
172 #ifdef SIGBUS
173 SIGDEF(SIGBUS, SIGDEF_NOHANDLE), /* BUS error (4.2 BSD) */
174 #endif
175 SIGDEF(SIGFPE, SIGDEF_ERROR), /* Floating-point exception (ANSI) */
176 #ifdef SIGKILL
177 SIGDEF(SIGKILL, SIGDEF_NOHANDLE), /* Kill, unblockable (POSIX) */
178 #endif
179 #ifdef SIGUSR1
180 SIGDEF(SIGUSR1, SIGDEF_ERROR), /* User-defined signal 1 (POSIX) */
181 #endif
182 SIGDEF(SIGSEGV, SIGDEF_NOHANDLE), /* Segmentation violation (ANSI) */
183 #ifdef SIGUSR2
184 SIGDEF(SIGUSR2, SIGDEF_ERROR), /* User-defined signal 2 (POSIX) */
185 #endif
186 #ifdef SIGPIPE
187 SIGDEF(SIGPIPE, SIGDEF_INDIFFERENT), /* Broken pipe (POSIX).
188 See above note on SIGPIPE. */
189 #endif
190 #ifdef SIGALRM
191 SIGDEF(SIGALRM, SIGDEF_ERROR), /* Alarm clock (POSIX) */
192 #endif
193 SIGDEF(SIGTERM, SIGDEF_EXIT), /* Termination (ANSI) */
194 #ifdef SIGSTKFLT
195 SIGDEF(SIGSTKFLT, SIGDEF_ERROR), /* Stack fault */
196 #endif
197 #ifdef SIGCHLD
198 SIGDEF(SIGCHLD, SIGDEF_DFL), /* Child status has changed (POSIX) */
199 #endif
200 #ifdef SIGCONT
201 SIGDEF(SIGCONT, SIGDEF_NOHANDLE), /* Continue (POSIX) */
202 #endif
203 #ifdef SIGSTOP
204 SIGDEF(SIGSTOP, SIGDEF_NOHANDLE), /* Stop, unblockable (POSIX) */
205 #endif
206 #ifdef SIGTSTP
207 SIGDEF(SIGTSTP, SIGDEF_NOHANDLE), /* Keyboard stop (POSIX) */
208 #endif
209 #ifdef SIGTTIN
210 SIGDEF(SIGTTIN, SIGDEF_NOHANDLE), /* Background read from tty (POSIX) */
211 #endif
212 #ifdef SIGTTOU
213 SIGDEF(SIGTTOU, SIGDEF_NOHANDLE), /* Background write to tty (POSIX) */
214 #endif
215 #ifdef SIGURG
216 SIGDEF(SIGURG, SIGDEF_NOHANDLE), /* Urgent condition on socket (4.2 BSD) */
217 #endif
218 #ifdef SIGXCPU
219 SIGDEF(SIGXCPU, SIGDEF_NOHANDLE), /* CPU limit exceeded (4.2 BSD) */
220 #endif
221 #ifdef SIGXFSZ
222 SIGDEF(SIGXFSZ, SIGDEF_ERROR), /* File size limit exceeded (4.2 BSD) */
223 #endif
224 #ifdef SIGVTALRM
225 SIGDEF(SIGVTALRM, SIGDEF_ERROR), /* Virtual alarm clock (4.2 BSD) */
226 #endif
227 #ifdef SIGPROF
228 SIGDEF(SIGPROF, SIGDEF_ERROR), /* Profiling alarm clock (4.2 BSD) */
229 #endif
230 #ifdef SIGWINCH
231 SIGDEF(SIGWINCH, SIGDEF_NOHANDLE),/* Window size change (4.3 BSD, Sun) */
232 #endif
233 #ifdef SIGPOLL
234 SIGDEF(SIGPOLL, SIGDEF_ERROR), /* Pollable event occurred (System V) */
235 #endif
236 #ifdef SIGIO
237 SIGDEF(SIGIO, SIGDEF_ERROR), /* I/O now possible (4.2 BSD) */
238 #endif
239 #ifdef SIGPWR
240 SIGDEF(SIGPWR, SIGDEF_NOHANDLE), /* Power failure restart (System V) */
241 #endif
242 #ifdef SIGTHR
243 SIGDEF(SIGTHR, SIGDEF_NOHANDLE), /* Thread interrupt / AST (FreeBSD, OpenBSD) */
244 #endif
245 { NULL, -1, 0 }
246 };
247
248 /*===============================================================
249 * Signal set operations
250 */
251
252 /*
253 * utilities for sigset
254 */
display_sigset(sigset_t * set,ScmPort * port)255 static void display_sigset(sigset_t *set, ScmPort *port)
256 {
257 struct sigdesc *desc = sigDesc;
258 int cnt = 0;
259 for (; desc->name; desc++) {
260 if (sigismember(set, desc->num)) {
261 if (cnt++) Scm_Putc('|', port);
262 Scm_Putz(desc->name+3, -1, port);
263 }
264 }
265 }
266
validsigp(int signum)267 static int validsigp(int signum)
268 {
269 if (signum > 0) {
270 struct sigdesc *desc = sigDesc;
271 for (; desc->name; desc++) {
272 if (desc->num == signum) return TRUE;
273 }
274 }
275 return FALSE;
276 }
277
sigset_op(sigset_t * s1,sigset_t * s2,int delp)278 static void sigset_op(sigset_t *s1, sigset_t *s2, int delp)
279 {
280 struct sigdesc *desc = sigDesc;
281 for (; desc->name; desc++) {
282 if (sigismember(s2, desc->num)) {
283 if (!delp) sigaddset(s1, desc->num);
284 else sigdelset(s1, desc->num);
285 }
286 }
287 }
288
Scm_SignalName(int signum)289 ScmObj Scm_SignalName(int signum)
290 {
291 struct sigdesc *desc = sigDesc;
292 for (; desc->name; desc++) {
293 if (desc->num == signum) {
294 return SCM_MAKE_STR_IMMUTABLE(desc->name);
295 }
296 }
297 return SCM_FALSE;
298 }
299
300 /*
301 * sigset class
302 */
303
304 static void sigset_print(ScmObj obj, ScmPort *out, ScmWriteContext *ctx);
305 static ScmObj sigset_allocate(ScmClass *klass, ScmObj initargs);
306
307 SCM_DEFINE_BUILTIN_CLASS(Scm_SysSigsetClass, sigset_print,
308 NULL, NULL, sigset_allocate, SCM_CLASS_DEFAULT_CPL);
309
sigset_print(ScmObj obj,ScmPort * out,ScmWriteContext * ctx SCM_UNUSED)310 void sigset_print(ScmObj obj, ScmPort *out,
311 ScmWriteContext *ctx SCM_UNUSED)
312 {
313 Scm_Printf(out, "#<sys-sigset [");
314 display_sigset(&SCM_SYS_SIGSET(obj)->set, out);
315 Scm_Printf(out, "]>");
316 }
317
sigset_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)318 ScmObj sigset_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
319 {
320 ScmSysSigset *s = SCM_NEW_INSTANCE(ScmSysSigset, klass);
321 sigemptyset(&s->set);
322 return SCM_OBJ(s);
323 }
324
make_sigset(void)325 ScmSysSigset *make_sigset(void)
326 {
327 return SCM_SYS_SIGSET(sigset_allocate(SCM_CLASS_SYS_SIGSET, SCM_NIL));
328 }
329
330 /* multifunction on sigset
331 if delp == FALSE, signals are added to set.
332 else, signals are removed from set.
333 signals is a list of either integer or #t (all signals), or other sigset.
334 */
Scm_SysSigsetOp(ScmSysSigset * set,ScmObj signals,int delp)335 ScmObj Scm_SysSigsetOp(ScmSysSigset *set, ScmObj signals, int delp)
336 {
337 if (!SCM_PAIRP(signals)) {
338 Scm_Error("list of signals required, but got %S", signals);
339 }
340
341 ScmObj cp;
342 SCM_FOR_EACH(cp, signals) {
343 ScmObj s = SCM_CAR(cp);
344 if (SCM_TRUEP(s)) {
345 if (!delp) sigfillset(&set->set);
346 else sigemptyset(&set->set);
347 break;
348 }
349 if (SCM_SYS_SIGSET_P(s)) {
350 sigset_op(&set->set, &SCM_SYS_SIGSET(s)->set, delp);
351 continue;
352 }
353 if (!SCM_INTP(s) || !validsigp(SCM_INT_VALUE(s))) {
354 Scm_Error("bad signal number %S", s);
355 }
356 if (!delp) sigaddset(&set->set, SCM_INT_VALUE(s));
357 else sigdelset(&set->set, SCM_INT_VALUE(s));
358 }
359 return SCM_OBJ(set);
360 }
361
362 /* fill or empty sigset. */
Scm_SysSigsetFill(ScmSysSigset * set,int emptyp)363 ScmObj Scm_SysSigsetFill(ScmSysSigset *set, int emptyp)
364 {
365 if (emptyp) sigemptyset(&(set->set));
366 else sigfillset(&(set->set));
367 return SCM_OBJ(set);
368 }
369
370 /* Fills sigset_t with as many signals as we can reasonably handle. */
Scm_SigFillSetMostly(sigset_t * set)371 void Scm_SigFillSetMostly(sigset_t *set) /* out */
372 {
373 sigfillset(set);
374 sigdelset(set, SIGABRT);
375 sigdelset(set, SIGILL);
376 #ifdef SIGKILL
377 sigdelset(set, SIGKILL);
378 #endif
379 #ifdef SIGSTOP
380 sigdelset(set, SIGSTOP);
381 #endif
382 sigdelset(set, SIGSEGV);
383 #ifdef SIGBUS
384 sigdelset(set, SIGBUS);
385 #endif
386 #ifdef SIGTHR
387 sigdelset(set, SIGTHR);
388 #endif
389
390 /* Exclude signals used by GC to stop and restart the world. */
391 #ifdef GC_THREADS
392 int sig_suspend = GC_get_suspend_signal();
393 if (sig_suspend >= 0) sigdelset(set, sig_suspend);
394 int sig_restart = GC_get_thr_restart_signal();
395 if (sig_restart >= 0) sigdelset(set, sig_restart);
396 #endif /*GC_THREADS*/
397
398 /* Exclude SIGPROF when we're using gperftools profiler. */
399 #if defined(HAVE_GPERFTOOLS_PROFILER_H)
400 sigdelset(set, SIGPROF);
401 #endif /*WITHGPERFTOOLS*/
402 }
403
404 /*=============================================================
405 * C-level signal handling
406 */
407
408
409 /*-------------------------------------------------------------------
410 * C-level signal handler - just records the signal delivery.
411 */
412
sig_handle(int signum)413 static void sig_handle(int signum)
414 {
415 ScmVM *vm = Scm_VM();
416 /* It is possible that vm == NULL at this point, if the thread is
417 terminating and in the cleanup phase. */
418 if (vm == NULL) return;
419
420 if (signalPendingLimit == 0) {
421 vm->sigq.sigcounts[signum] = 1;
422 } else if (++vm->sigq.sigcounts[signum] >= signalPendingLimit) {
423 Scm_Abort("Received too many signals before processing them. Exitting for the emergency...\n");
424 }
425 vm->signalPending = TRUE;
426 vm->attentionRequest = TRUE;
427 }
428
429 /*-------------------------------------------------------------------
430 * Signal queue operations
431 */
432
433 /*
434 * Clear the signal queue
435 */
Scm_SignalQueueClear(ScmSignalQueue * q)436 void Scm_SignalQueueClear(ScmSignalQueue* q)
437 {
438 for (int i=0; i<SCM_NSIG; i++) q->sigcounts[i] = 0;
439 }
440
441 /*
442 * Initializes signal queue
443 */
Scm_SignalQueueInit(ScmSignalQueue * q)444 void Scm_SignalQueueInit(ScmSignalQueue* q)
445 {
446 q->sigcounts = SCM_NEW_ARRAY(unsigned char, SCM_NSIG);
447 Scm_SignalQueueClear(q);
448 q->pending = SCM_NIL;
449 }
450
451 /*
452 * Get/Set signal pending limit
453 */
Scm_GetSignalPendingLimit(void)454 int Scm_GetSignalPendingLimit(void)
455 {
456 return signalPendingLimit;
457 }
458
Scm_SetSignalPendingLimit(int num)459 void Scm_SetSignalPendingLimit(int num)
460 {
461 if (num < 0 || num >= SIGNAL_PENDING_LIMIT_MAX) {
462 Scm_Error("signal-pending-limit argument out of range: %d", num);
463 }
464 signalPendingLimit = num;
465 }
466
467 /*
468 * Called from VM's safe point to flush the queued signals.
469 * VM already checks there's a pending signal in the queue.
470 */
Scm_SigCheck(ScmVM * vm)471 void Scm_SigCheck(ScmVM *vm)
472 {
473 ScmSignalQueue *q = &vm->sigq;
474 unsigned char sigcounts[SCM_NSIG]; /* copy of signal counter */
475
476 /* Copy VM's signal counter to local storage, for we can't call
477 storage allocation during blocking signals. */
478 sigset_t omask;
479 SIGPROCMASK(SIG_BLOCK, &sigHandlers.masterSigset, &omask);
480 memcpy(sigcounts, vm->sigq.sigcounts, SCM_NSIG * sizeof(unsigned char));
481 Scm_SignalQueueClear(&vm->sigq);
482 vm->signalPending = FALSE;
483 SIGPROCMASK(SIG_SETMASK, &omask, NULL);
484
485 #if defined(GAUCHE_USE_PTHREADS) && defined(GAUCHE_PTHREAD_SIGNAL)
486 /* We may use GAUCHE_PTHREAD_SIGNAL signal to terminate a thread
487 gracefully. See Scm_ThreadTerminate in ext/threads/threads.c */
488 if (sigcounts[GAUCHE_PTHREAD_SIGNAL] > 0) {
489 /* The thread state will be set to TERMINATED by the cleanup
490 handler so we don't need to change it. */
491 SCM_INTERNAL_THREAD_EXIT();
492 /* NOTREACHED */
493 }
494 #endif /* defined(GAUCHE_USE_PTHREADS) && defined(GAUCHE_PTHREAD_SIGNAL) */
495
496 /* Now, queue the signal handlers */
497 ScmObj tail = q->pending;
498 if (!SCM_NULLP(tail)) tail = Scm_LastPair(tail);
499 for (int i=0; i<SCM_NSIG; i++) {
500 if (sigcounts[i] == 0) continue;
501 if (SCM_PROCEDUREP(sigHandlers.handlers[i])) {
502 ScmObj cell = Scm_Cons(SCM_LIST3(sigHandlers.handlers[i],
503 SCM_MAKE_INT(i),
504 SCM_OBJ_SAFE(sigHandlers.masks[i])),
505 SCM_NIL);
506 if (SCM_NULLP(tail)) {
507 q->pending = tail = cell;
508 } else {
509 SCM_SET_CDR_UNCHECKED(tail, cell);
510 tail = SCM_CDR(tail);
511 }
512 }
513 }
514
515 /* Call the queued signal handlers. If an error is thrown in one
516 of those handlers, the rest of handlers remain in the queue. */
517 /* TODO: if VM is active, it'd be better to make the active VM to handle
518 those handler procs, instead of calling Scm_Eval. */
519 ScmObj sp;
520 SCM_FOR_EACH(sp, q->pending) {
521 ScmObj e = SCM_CAR(sp);
522 q->pending = SCM_CDR(sp);
523 ScmObj handler = SCM_CAR(e);
524 ScmObj num = SCM_CADR(e);
525 ScmObj mask = SCM_CAR(SCM_CDDR(e));
526 if (SCM_SYS_SIGSET_P(mask)) {
527 sigset_t omask;
528 sigemptyset(&omask);
529 SCM_UNWIND_PROTECT {
530 SIGPROCMASK(SIG_BLOCK, &SCM_SYS_SIGSET(mask)->set, &omask);
531 Scm_ApplyRec(handler, SCM_LIST1(num));
532 }
533 SCM_WHEN_ERROR {
534 SIGPROCMASK(SIG_SETMASK, &omask, NULL);
535 SCM_NEXT_HANDLER;
536 }
537 SCM_END_PROTECT;
538 SIGPROCMASK(SIG_SETMASK, &omask, NULL);
539 } else {
540 Scm_ApplyRec(handler, SCM_LIST1(num));
541 }
542 }
543 }
544
545 /*=============================================================
546 * Scheme-level signal handling
547 */
548
549 /*-------------------------------------------------------------
550 * Default Scheme-level handlers
551 */
552 /* For most signals, default handler raises an error. */
default_sighandler(ScmObj * args,int nargs,void * data SCM_UNUSED)553 static ScmObj default_sighandler(ScmObj *args, int nargs, void *data SCM_UNUSED)
554 {
555 SCM_ASSERT(nargs == 1 && SCM_INTP(args[0]));
556 int signum = SCM_INT_VALUE(args[0]);
557
558 struct sigdesc *desc;
559 const char *name = NULL;
560 for (desc = sigDesc; desc->name; desc++) {
561 if (desc->num == signum) {
562 name = desc->name;
563 break;
564 }
565 }
566 if (name) {
567 Scm_RaiseCondition(SCM_OBJ(SCM_CLASS_UNHANDLED_SIGNAL_ERROR),
568 "signal", SCM_MAKE_INT(signum),
569 SCM_RAISE_CONDITION_MESSAGE,
570 "unhandled signal %d (%s)", signum, name);
571 } else {
572 Scm_RaiseCondition(SCM_OBJ(SCM_CLASS_UNHANDLED_SIGNAL_ERROR),
573 "signal", SCM_MAKE_INT(signum),
574 SCM_RAISE_CONDITION_MESSAGE,
575 "unhandled signal %d (unknown signal)", signum);
576 }
577 return SCM_UNDEFINED; /* dummy */
578 }
579
580 static SCM_DEFINE_STRING_CONST(default_sighandler_name,
581 "%default-signal-handler", 23, 23);
582 static SCM_DEFINE_SUBR(default_sighandler_stub, 1, 0,
583 SCM_OBJ(&default_sighandler_name),
584 default_sighandler,
585 NULL, NULL);
586
587 #define DEFAULT_SIGHANDLER SCM_OBJ(&default_sighandler_stub)
588
589 /* For some signals, exits. */
exit_sighandler(ScmObj * args SCM_UNUSED,int nargs SCM_UNUSED,void * data SCM_UNUSED)590 static ScmObj exit_sighandler(ScmObj *args SCM_UNUSED,
591 int nargs SCM_UNUSED,
592 void *data SCM_UNUSED)
593 {
594 Scm_Exit(0);
595 return SCM_UNDEFINED; /* dummy */
596 }
597
598 static SCM_DEFINE_STRING_CONST(exit_sighandler_name,
599 "%exit-signal-handler", 20, 20);
600 static SCM_DEFINE_SUBR(exit_sighandler_stub, 1, 0,
601 SCM_OBJ(&exit_sighandler_name),
602 exit_sighandler,
603 NULL, NULL);
604
605 #define EXIT_SIGHANDLER SCM_OBJ(&exit_sighandler_stub)
606
607 /* For some signals, gauche does nothing */
indifferent_sighandler(ScmObj * args SCM_UNUSED,int nargs SCM_UNUSED,void * data SCM_UNUSED)608 static ScmObj indifferent_sighandler(ScmObj *args SCM_UNUSED,
609 int nargs SCM_UNUSED,
610 void *data SCM_UNUSED)
611 {
612 return SCM_UNDEFINED;
613 }
614
615 static SCM_DEFINE_STRING_CONST(indifferent_sighandler_name,
616 "%indifferent-signal-handler", 27, 27);
617 static SCM_DEFINE_SUBR(indifferent_sighandler_stub, 1, 0,
618 SCM_OBJ(&indifferent_sighandler_name),
619 indifferent_sighandler,
620 NULL, NULL);
621
622 #define INDIFFERENT_SIGHANDLER SCM_OBJ(&indifferent_sighandler_stub)
623
624 /*
625 * An emulation stub for Windows
626 *
627 * Note on windows port:
628 * Windows does provide signal() function to conform C standard, but
629 * its use is so limited that it's effectively useless. You can only
630 * trap SIGABRT, SIGFPE, SIGILL, SIGSEGV and SIGTERM, and you cannot
631 * send signal to other processes. Emulating POSIX signal behavior is
632 * not an easy task (see http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/how-signals-work.txt?cvsroot=src ).
633 * So, although we provide a signal interface, DO NOT USE IT. It's better
634 * to expose Windows native IPC and build an abstraction on top if it.
635 */
636 #if defined(GAUCHE_WINDOWS)
sigaction(int signum,const struct sigaction * act,struct sigaction * oact)637 int sigaction(int signum, const struct sigaction *act,
638 struct sigaction *oact)
639 {
640 if (oact != NULL) {
641 Scm_Panic("sigaction() with oldact != NULL isn't supported on MinGW port");
642 }
643 if (signal(signum, act->sa_handler) == SIG_ERR) {
644 return -1;
645 } else {
646 return 0;
647 }
648 }
649
sigprocmask_win(int how SCM_UNUSED,const sigset_t * set SCM_UNUSED,sigset_t * oldset SCM_UNUSED)650 int sigprocmask_win(int how SCM_UNUSED, const sigset_t *set SCM_UNUSED,
651 sigset_t *oldset SCM_UNUSED)
652 {
653 return 0;
654 }
655 #endif /* GAUCHE_WINDOWS */
656
657 /*
658 * set-signal-handler!
659 */
Scm_SetSignalHandler(ScmObj sigs,ScmObj handler,ScmSysSigset * mask)660 ScmObj Scm_SetSignalHandler(ScmObj sigs, ScmObj handler, ScmSysSigset *mask)
661 {
662 sigset_t sigset;
663 int badproc = FALSE, sigactionfailed = FALSE;
664
665 sigemptyset(&sigset);
666 if (SCM_INTP(sigs)) {
667 int signum = SCM_INT_VALUE(sigs);
668 if (signum < 0 || signum >= SCM_NSIG) {
669 Scm_Error("bad signal number: %d", signum);
670 }
671 sigaddset(&sigset, signum);
672 } else if (SCM_SYS_SIGSET_P(sigs)) {
673 sigset = SCM_SYS_SIGSET(sigs)->set;
674 } else {
675 Scm_Error("bad signal number: must be an integer signal number or a <sys-sigset> object, but got %S", sigs);
676 }
677
678 if (SCM_UNDEFINEDP(handler)) return SCM_UNDEFINED;
679
680 struct sigaction act;
681 if (SCM_TRUEP(handler)) {
682 act.sa_handler = SIG_DFL;
683 } else if (SCM_FALSEP(handler)) {
684 act.sa_handler = SIG_IGN;
685 } else if (SCM_PROCEDUREP(handler)
686 && SCM_PROCEDURE_TAKE_NARG_P(handler, 1)) {
687 act.sa_handler = sig_handle;
688 } else {
689 badproc = TRUE;
690 }
691
692 if (mask == NULL) {
693 /* If no mask is specified, block signals in SIGS. */
694 mask = make_sigset();
695 mask->set = sigset;
696 }
697
698 (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
699 if (!badproc) {
700 sigfillset(&act.sa_mask); /* we should block all the signals */
701 act.sa_flags = 0;
702 for (struct sigdesc *desc=sigDesc; desc->name; desc++) {
703 if (!sigismember(&sigset, desc->num)) continue;
704 if (!sigismember(&sigHandlers.masterSigset, desc->num)) continue;
705 else if (sigaction(desc->num, &act, NULL) != 0) {
706 sigactionfailed = desc->num;
707 } else {
708 sigHandlers.handlers[desc->num] = handler;
709 sigHandlers.masks[desc->num] = mask;
710 }
711 }
712 }
713 (void)SCM_INTERNAL_MUTEX_UNLOCK(sigHandlers.mutex);
714 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);
715 if (sigactionfailed) Scm_Error("sigaction failed when setting a sighandler for signal %d", sigactionfailed);
716 return SCM_UNDEFINED;
717 }
718
Scm_GetSignalHandler(int signum)719 ScmObj Scm_GetSignalHandler(int signum)
720 {
721 if (signum < 0 || signum >= SCM_NSIG) {
722 Scm_Error("bad signal number: %d", signum);
723 }
724 /* No lock; atomic pointer access */
725 return sigHandlers.handlers[signum];
726 }
727
Scm_GetSignalHandlerMask(int signum)728 ScmObj Scm_GetSignalHandlerMask(int signum)
729 {
730 ScmSysSigset *r;
731 if (signum < 0 || signum >= SCM_NSIG) {
732 Scm_Error("bad signal number: %d", signum);
733 }
734 /* No lock; atomic pointer access */
735 r = sigHandlers.masks[signum];
736 return r? SCM_OBJ(r) : SCM_FALSE;
737 }
738
Scm_GetSignalHandlers(void)739 ScmObj Scm_GetSignalHandlers(void)
740 {
741 ScmObj h = SCM_NIL;
742 ScmObj handlers[SCM_NSIG];
743
744 /* copy handler vector and master sig set locally, so that we won't
745 grab the lock for extensive time */
746 (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
747 for (int i=0; i<SCM_NSIG; i++) handlers[i] = sigHandlers.handlers[i];
748 sigset_t masterSet = sigHandlers.masterSigset;
749 (void)SCM_INTERNAL_MUTEX_UNLOCK(sigHandlers.mutex);
750
751 for (struct sigdesc *desc=sigDesc; desc->name; desc++) {
752 if (!sigismember(&masterSet, desc->num)) continue;
753 ScmObj hp;
754 SCM_FOR_EACH(hp, h) {
755 if (SCM_EQ(SCM_CDAR(hp), handlers[desc->num])) {
756 sigaddset(&(SCM_SYS_SIGSET(SCM_CAAR(hp))->set), desc->num);
757 break;
758 }
759 }
760 if (SCM_NULLP(hp)) {
761 ScmSysSigset *set = make_sigset();
762 sigaddset(&(set->set), desc->num);
763 h = Scm_Acons(SCM_OBJ(set), handlers[desc->num], h);
764 }
765 }
766 return h;
767 }
768
769 /*
770 * set/get master signal
771 */
Scm_GetMasterSigmask(void)772 sigset_t Scm_GetMasterSigmask(void)
773 {
774 return sigHandlers.masterSigset;
775 }
776
777 /* this should be called before any thread is created. */
Scm_SetMasterSigmask(sigset_t * set)778 void Scm_SetMasterSigmask(sigset_t *set)
779 {
780 struct sigdesc *desc = sigDesc;
781 struct sigaction acton, actoff;
782
783 acton.sa_handler = (void(*)(int))sig_handle;
784 acton.sa_mask = *set;
785 acton.sa_flags = 0;
786 actoff.sa_handler = SIG_DFL;
787 sigemptyset(&actoff.sa_mask);
788 actoff.sa_flags = 0;
789
790 for (; desc->name; desc++) {
791 if (sigismember(&sigHandlers.masterSigset, desc->num)
792 && !sigismember(set, desc->num)) {
793 /* remove sighandler */
794 if (sigaction(desc->num, &actoff, NULL) != 0) {
795 Scm_SysError("sigaction on %d failed", desc->num);
796 }
797 sigHandlers.handlers[desc->num] = SCM_TRUE;
798 } else if (!sigismember(&sigHandlers.masterSigset, desc->num)
799 && sigismember(set, desc->num)) {
800 /* add sighandler if necessary */
801 if (desc->defaultHandle == SIGDEF_DFL) {
802 if (sigaction(desc->num, &actoff, NULL) != 0) {
803 Scm_SysError("sigaction on %d failed", desc->num);
804 }
805 sigHandlers.handlers[desc->num] = SCM_TRUE;
806 } else if (desc->defaultHandle != SIGDEF_NOHANDLE) {
807 if (sigaction(desc->num, &acton, NULL) != 0) {
808 Scm_SysError("sigaction on %d failed", desc->num);
809 }
810 switch (desc->defaultHandle) {
811 case SIGDEF_ERROR:
812 sigHandlers.handlers[desc->num] = DEFAULT_SIGHANDLER;
813 break;
814 case SIGDEF_EXIT:
815 sigHandlers.handlers[desc->num] = EXIT_SIGHANDLER;
816 break;
817 case SIGDEF_INDIFFERENT:
818 sigHandlers.handlers[desc->num] = INDIFFERENT_SIGHANDLER;
819 break;
820 default:
821 Scm_Panic("Scm_SetMasterSigmask: can't be here");
822 }
823 }
824 }
825 }
826 #ifdef GAUCHE_PTHREAD_SIGNAL
827 /* On pthread and when available, we reserve one signal for inter-thread
828 communication. See gauche/pthread.h for the definition of
829 GAUCHE_PTHREAD_SIGNAL. In sigHandlers we set DEFAULT_SIGHANDLER,
830 but this signal is intercepted in Scm_SigCheck() so a you can't
831 set Scheme handler for this signal. */
832 if (sigaction(GAUCHE_PTHREAD_SIGNAL, &acton, NULL) != 0) {
833 Scm_SysError("sigaction on %d failed", GAUCHE_PTHREAD_SIGNAL);
834 }
835 sigHandlers.handlers[GAUCHE_PTHREAD_SIGNAL] = DEFAULT_SIGHANDLER;
836 #endif /* GAUCHE_PTHREAD_SIGNAL */
837 sigHandlers.masterSigset = *set;
838 Scm_VM()->sigMask = sigHandlers.masterSigset;
839 }
840
841 /*============================================================
842 * Other signal-related operations
843 */
844
845 /*
846 * Convenience routines hiding platform-dependent stuff
847 *
848 * TRANSIENT: These used to be used in vm.c, but no longer. As of 0.9.3 these
849 * aren't used anywhere. Scm_SysSigmask covers those functionalities,
850 * so we'll drop them by 1.0.
851 */
852 #if GAUCHE_API_VERSION < 1000
Scm_GetSigmask(sigset_t * mask)853 void Scm_GetSigmask(sigset_t *mask)
854 {
855 if (SIGPROCMASK(SIG_SETMASK, NULL, mask) != 0) {
856 Scm_SysError("sigprocmask failed");
857 }
858 }
859
Scm_SetSigmask(sigset_t * mask)860 void Scm_SetSigmask(sigset_t *mask)
861 {
862 if (SIGPROCMASK(SIG_SETMASK, mask, NULL) != 0) {
863 Scm_SysError("sigprocmask failed");
864 }
865 }
866 #endif /*GAUCHE_API_VERSION < 1000*/
867
868 /*
869 * set signal mask
870 */
871
Scm_SysSigmask(int how,ScmSysSigset * newmask)872 ScmObj Scm_SysSigmask(int how, ScmSysSigset *newmask)
873 {
874 ScmSysSigset *oldmask = make_sigset();
875 sigset_t *newset = NULL;
876
877 if (newmask) {
878 newset = &(newmask->set);
879 if (how != SIG_SETMASK && how != SIG_BLOCK && how != SIG_UNBLOCK) {
880 Scm_Error("bad 'how' argument for signal mask action: %d", how);
881 }
882 }
883 if (SIGPROCMASK(how, newset, &(oldmask->set)) != 0) {
884 Scm_SysError("sigprocmask failed");
885 }
886 return SCM_OBJ(oldmask);
887 }
888
889 /*
890 * Reset signal handlers except the masked ones.
891 * This is called just before we change the signal mask and call exec(2),
892 * so that we can avoid the hazard that the signal handler is called
893 * between sigsetmask and exec.
894 */
Scm_ResetSignalHandlers(sigset_t * mask)895 void Scm_ResetSignalHandlers(sigset_t *mask)
896 {
897 struct sigdesc *desc = sigDesc;
898 struct sigaction act;
899
900 for (; desc->name; desc++) {
901 if (!sigismember(&sigHandlers.masterSigset, desc->num)
902 && (!mask || !sigismember(mask, desc->num))) {
903 act.sa_flags = 0;
904 act.sa_handler = SIG_IGN;
905 // NB: we tolerate failure of this
906 sigaction(desc->num, &act, NULL);
907 }
908 }
909 }
910
911 /*
912 * sigsuspend
913 */
scm_sigsuspend(sigset_t * mask)914 static void scm_sigsuspend(sigset_t *mask)
915 {
916 #if !defined(GAUCHE_WINDOWS)
917 sigset_t omask;
918 ScmVM *vm = Scm_VM();
919 for (;;) {
920 SIGPROCMASK(SIG_BLOCK, &sigHandlers.masterSigset, &omask);
921 if (vm->signalPending) {
922 SIGPROCMASK(SIG_SETMASK, &omask, NULL);
923 Scm_SigCheck(vm);
924 continue;
925 }
926 break;
927 }
928 sigsuspend(mask);
929 SIGPROCMASK(SIG_SETMASK, &omask, NULL);
930 SCM_SIGCHECK(vm);
931 #else /* GAUCHE_WINDOWS */
932 (void)mask; /* suppress unused var warning */
933 Scm_Error("sigsuspend not supported on Windows port");
934 #endif /* GAUCHE_WINDOWS */
935 }
936
Scm_SigSuspend(ScmSysSigset * mask)937 ScmObj Scm_SigSuspend(ScmSysSigset *mask)
938 {
939 scm_sigsuspend(&(mask->set));
940 return SCM_UNDEFINED;
941 }
942
943 /*
944 * Alternative of 'pause()'
945 * we can't use pause() reliably, since the process may miss a signal
946 * if it is delivered after the last call of Scm_SigCheck before pause();
947 * the signal is queued, but will never be processed until pause() returns
948 * by another signal.
949 */
Scm_Pause(void)950 ScmObj Scm_Pause(void)
951 {
952 sigset_t omask;
953 SIGPROCMASK(SIG_SETMASK, NULL, &omask);
954 scm_sigsuspend(&omask);
955 return SCM_UNDEFINED;
956 }
957
958 /*
959 * Sigwait wrapper
960 *
961 * The behavior of sigwait is undefined if a signal handler is set to
962 * the waiting signal. On Cygwin, for example, using both signal handler
963 * and sigwait makes havoc. Since Gauche installs sig_handle()
964 * implicitly to some signals, a casual user may be confused by the
965 * unpredictable behavior when he doesn't reset signal handlers explicitly.
966 * So we take care of them here.
967 *
968 * We remove the signal handlers for the signals to be waited before calling
969 * sigwait(), and restore them after its return. We assume those signals
970 * are blocked at this moment (if not, the behavior of sigwait() is
971 * undefined), so we don't need to care about race condition. If another
972 * thread replaces signal handlers during this thread's waiting for a
973 * signal, it would be reverted upon returning from this function, but
974 * such operation is inherently unsafe anyway, so we don't care.
975 */
Scm_SigWait(ScmSysSigset * mask)976 int Scm_SigWait(ScmSysSigset *mask)
977 {
978 #if defined(HAVE_SIGWAIT)
979 int r = 0, sig = 0;
980 int failed_sig = -1;
981 int sigwait_called = FALSE;
982 int errno_save = 0;
983 sigset_t to_wait; /* real set of signals to wait */
984 sigset_t saved;
985 struct sigaction act, oacts[SCM_NSIG];
986
987 (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
988 /* we can't wait for the signals Gauche doesn't handle. */
989 to_wait = mask->set;
990 for (int i=0; i<SCM_NSIG; i++) {
991 if (!sigismember(&sigHandlers.masterSigset, i)) {
992 sigdelset(&to_wait, i);
993 }
994 }
995
996 /* Remove C-level handlers */
997 sigemptyset(&saved);
998 act.sa_handler = SIG_DFL;
999 act.sa_flags = 0;
1000 for (int i=1; i<SCM_NSIG; i++) {
1001 if (!sigismember(&to_wait, i)) continue;
1002 if (sigaction(i, &act, &oacts[i]) < 0) {
1003 failed_sig = i;
1004 errno_save = errno;
1005 break;
1006 }
1007 sigaddset(&saved, i);
1008 }
1009
1010 if (failed_sig < 0) {
1011 (void)SCM_INTERNAL_MUTEX_UNLOCK(sigHandlers.mutex);
1012 sigwait_called = TRUE;
1013 r = sigwait(&to_wait, &sig);
1014 (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
1015 }
1016
1017 /* Restore C-level handlers */
1018 for (int i=1; i<SCM_NSIG; i++) {
1019 if (!sigismember(&saved, i)) continue;
1020 if (sigaction(i, &oacts[i], NULL) < 0) {
1021 failed_sig = i;
1022 errno_save = errno;
1023 }
1024 }
1025 (void)SCM_INTERNAL_MUTEX_UNLOCK(sigHandlers.mutex);
1026
1027 /* error handling */
1028 if (failed_sig >= 0) {
1029 errno = errno_save;
1030 Scm_SysError("sigaction(2) call failed on signal %d"
1031 " %s sigwait call",
1032 failed_sig,
1033 sigwait_called? "after" : "before");
1034 }
1035 if (r != 0) {
1036 errno = r;
1037 Scm_SysError("sigwait failed");
1038 }
1039 return sig;
1040 #else /* !HAVE_SIGWAIT */
1041 (void)mask; /* suppress unused var warning */
1042 Scm_Error("sigwait not supported on this platform");
1043 return 0;
1044 #endif
1045 }
1046
1047
1048 /*================================================================
1049 * Initialize
1050 */
1051
Scm__InitSignal(void)1052 void Scm__InitSignal(void)
1053 {
1054 ScmModule *mod = Scm_GaucheModule();
1055 ScmObj defsigh_sym = Scm_Intern(&default_sighandler_name);
1056
1057 (void)SCM_INTERNAL_MUTEX_INIT(sigHandlers.mutex);
1058 sigemptyset(&sigHandlers.masterSigset);
1059 for (int i=0; i<SCM_NSIG; i++) sigHandlers.handlers[i] = SCM_UNDEFINED;
1060
1061 Scm_InitStaticClass(&Scm_SysSigsetClass, "<sys-sigset>",
1062 mod, NULL, 0);
1063
1064 for (struct sigdesc *desc = sigDesc; desc->name; desc++) {
1065 SCM_DEFINE(mod, desc->name, SCM_MAKE_INT(desc->num));
1066 }
1067 Scm_Define(mod, SCM_SYMBOL(defsigh_sym), DEFAULT_SIGHANDLER);
1068 }
1069