root/src/signal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. display_sigset
  2. validsigp
  3. sigset_op
  4. Scm_SignalName
  5. default_sighandler
  6. exit_sighandler
  7. through_sighandler
  8. sigset_print
  9. sigset_allocate
  10. make_sigset
  11. Scm_SysSigsetOp
  12. Scm_SysSigsetFill
  13. sig_handle
  14. Scm_SignalQueueInit
  15. Scm_SigCheck
  16. Scm_SetSignalHandler
  17. Scm_GetSignalHandler
  18. Scm_GetSignalHandlers
  19. Scm_GetMasterSigmask
  20. Scm_SetMasterSigmask
  21. Scm_SysSigmask
  22. scm_sigsuspend
  23. Scm_SigSuspend
  24. Scm_Pause
  25. sigaction
  26. 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 }

/* [<][>][^][v][top][bottom][index][help] */