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