• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

signal.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   signal.c -
00004 
00005   $Author: yugui $
00006   created at: Tue Dec 20 10:13:44 JST 1994
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00010   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00011 
00012 **********************************************************************/
00013 
00014 #include "ruby/ruby.h"
00015 #include "vm_core.h"
00016 #include <signal.h>
00017 #include <stdio.h>
00018 #include <errno.h>
00019 
00020 #ifdef _WIN32
00021 typedef LONG rb_atomic_t;
00022 
00023 # define ATOMIC_TEST(var) InterlockedExchange(&(var), 0)
00024 # define ATOMIC_SET(var, val) InterlockedExchange(&(var), (val))
00025 # define ATOMIC_INC(var) InterlockedIncrement(&(var))
00026 # define ATOMIC_DEC(var) InterlockedDecrement(&(var))
00027 
00028 #else
00029 typedef int rb_atomic_t;
00030 
00031 # define ATOMIC_TEST(var) ((var) ? ((var) = 0, 1) : 0)
00032 # define ATOMIC_SET(var, val) ((var) = (val))
00033 # define ATOMIC_INC(var) (++(var))
00034 # define ATOMIC_DEC(var) (--(var))
00035 #endif
00036 
00037 #if defined(__BEOS__) || defined(__HAIKU__)
00038 #undef SIGBUS
00039 #endif
00040 
00041 #if defined HAVE_SIGPROCMASK || defined HAVE_SIGSETMASK
00042 #define USE_TRAP_MASK 1
00043 #else
00044 #define USE_TRAP_MASK 0
00045 #endif
00046 
00047 #ifndef NSIG
00048 # define NSIG (_SIGMAX + 1)      /* For QNX */
00049 #endif
00050 
00051 static const struct signals {
00052     const char *signm;
00053     int  signo;
00054 } siglist [] = {
00055     {"EXIT", 0},
00056 #ifdef SIGHUP
00057     {"HUP", SIGHUP},
00058 #endif
00059     {"INT", SIGINT},
00060 #ifdef SIGQUIT
00061     {"QUIT", SIGQUIT},
00062 #endif
00063 #ifdef SIGILL
00064     {"ILL", SIGILL},
00065 #endif
00066 #ifdef SIGTRAP
00067     {"TRAP", SIGTRAP},
00068 #endif
00069 #ifdef SIGIOT
00070     {"IOT", SIGIOT},
00071 #endif
00072 #ifdef SIGABRT
00073     {"ABRT", SIGABRT},
00074 #endif
00075 #ifdef SIGEMT
00076     {"EMT", SIGEMT},
00077 #endif
00078 #ifdef SIGFPE
00079     {"FPE", SIGFPE},
00080 #endif
00081 #ifdef SIGKILL
00082     {"KILL", SIGKILL},
00083 #endif
00084 #ifdef SIGBUS
00085     {"BUS", SIGBUS},
00086 #endif
00087 #ifdef SIGSEGV
00088     {"SEGV", SIGSEGV},
00089 #endif
00090 #ifdef SIGSYS
00091     {"SYS", SIGSYS},
00092 #endif
00093 #ifdef SIGPIPE
00094     {"PIPE", SIGPIPE},
00095 #endif
00096 #ifdef SIGALRM
00097     {"ALRM", SIGALRM},
00098 #endif
00099 #ifdef SIGTERM
00100     {"TERM", SIGTERM},
00101 #endif
00102 #ifdef SIGURG
00103     {"URG", SIGURG},
00104 #endif
00105 #ifdef SIGSTOP
00106     {"STOP", SIGSTOP},
00107 #endif
00108 #ifdef SIGTSTP
00109     {"TSTP", SIGTSTP},
00110 #endif
00111 #ifdef SIGCONT
00112     {"CONT", SIGCONT},
00113 #endif
00114 #ifdef SIGCHLD
00115     {"CHLD", SIGCHLD},
00116 #endif
00117 #ifdef SIGCLD
00118     {"CLD", SIGCLD},
00119 #else
00120 # ifdef SIGCHLD
00121     {"CLD", SIGCHLD},
00122 # endif
00123 #endif
00124 #ifdef SIGTTIN
00125     {"TTIN", SIGTTIN},
00126 #endif
00127 #ifdef SIGTTOU
00128     {"TTOU", SIGTTOU},
00129 #endif
00130 #ifdef SIGIO
00131     {"IO", SIGIO},
00132 #endif
00133 #ifdef SIGXCPU
00134     {"XCPU", SIGXCPU},
00135 #endif
00136 #ifdef SIGXFSZ
00137     {"XFSZ", SIGXFSZ},
00138 #endif
00139 #ifdef SIGVTALRM
00140     {"VTALRM", SIGVTALRM},
00141 #endif
00142 #ifdef SIGPROF
00143     {"PROF", SIGPROF},
00144 #endif
00145 #ifdef SIGWINCH
00146     {"WINCH", SIGWINCH},
00147 #endif
00148 #ifdef SIGUSR1
00149     {"USR1", SIGUSR1},
00150 #endif
00151 #ifdef SIGUSR2
00152     {"USR2", SIGUSR2},
00153 #endif
00154 #ifdef SIGLOST
00155     {"LOST", SIGLOST},
00156 #endif
00157 #ifdef SIGMSG
00158     {"MSG", SIGMSG},
00159 #endif
00160 #ifdef SIGPWR
00161     {"PWR", SIGPWR},
00162 #endif
00163 #ifdef SIGPOLL
00164     {"POLL", SIGPOLL},
00165 #endif
00166 #ifdef SIGDANGER
00167     {"DANGER", SIGDANGER},
00168 #endif
00169 #ifdef SIGMIGRATE
00170     {"MIGRATE", SIGMIGRATE},
00171 #endif
00172 #ifdef SIGPRE
00173     {"PRE", SIGPRE},
00174 #endif
00175 #ifdef SIGGRANT
00176     {"GRANT", SIGGRANT},
00177 #endif
00178 #ifdef SIGRETRACT
00179     {"RETRACT", SIGRETRACT},
00180 #endif
00181 #ifdef SIGSOUND
00182     {"SOUND", SIGSOUND},
00183 #endif
00184 #ifdef SIGINFO
00185     {"INFO", SIGINFO},
00186 #endif
00187     {NULL, 0}
00188 };
00189 
00190 static int
00191 signm2signo(const char *nm)
00192 {
00193     const struct signals *sigs;
00194 
00195     for (sigs = siglist; sigs->signm; sigs++)
00196         if (strcmp(sigs->signm, nm) == 0)
00197             return sigs->signo;
00198     return 0;
00199 }
00200 
00201 static const char*
00202 signo2signm(int no)
00203 {
00204     const struct signals *sigs;
00205 
00206     for (sigs = siglist; sigs->signm; sigs++)
00207         if (sigs->signo == no)
00208             return sigs->signm;
00209     return 0;
00210 }
00211 
00212 const char *
00213 ruby_signal_name(int no)
00214 {
00215     return signo2signm(no);
00216 }
00217 
00218 /*
00219  * call-seq:
00220  *    SignalException.new(sig_name)              ->  signal_exception
00221  *    SignalException.new(sig_number [, name])   ->  signal_exception
00222  *
00223  *  Construct a new SignalException object.  +sig_name+ should be a known
00224  *  signal name.
00225  */
00226 
00227 static VALUE
00228 esignal_init(int argc, VALUE *argv, VALUE self)
00229 {
00230     int argnum = 1;
00231     VALUE sig = Qnil;
00232     int signo;
00233     const char *signm;
00234 
00235     if (argc > 0) {
00236         sig = rb_check_to_integer(argv[0], "to_int");
00237         if (!NIL_P(sig)) argnum = 2;
00238         else sig = argv[0];
00239     }
00240     if (argc < 1 || argnum < argc) {
00241         rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
00242                  argc, argnum);
00243     }
00244     if (argnum == 2) {
00245         signo = NUM2INT(sig);
00246         if (signo < 0 || signo > NSIG) {
00247             rb_raise(rb_eArgError, "invalid signal number (%d)", signo);
00248         }
00249         if (argc > 1) {
00250             sig = argv[1];
00251         }
00252         else {
00253             signm = signo2signm(signo);
00254             if (signm) {
00255                 sig = rb_sprintf("SIG%s", signm);
00256             }
00257             else {
00258                 sig = rb_sprintf("SIG%u", signo);
00259             }
00260         }
00261     }
00262     else {
00263         signm = SYMBOL_P(sig) ? rb_id2name(SYM2ID(sig)) : StringValuePtr(sig);
00264         if (strncmp(signm, "SIG", 3) == 0) signm += 3;
00265         signo = signm2signo(signm);
00266         if (!signo) {
00267             rb_raise(rb_eArgError, "unsupported name `SIG%s'", signm);
00268         }
00269         sig = rb_sprintf("SIG%s", signm);
00270     }
00271     rb_call_super(1, &sig);
00272     rb_iv_set(self, "signo", INT2NUM(signo));
00273 
00274     return self;
00275 }
00276 
00277 /*
00278  * call-seq:
00279  *    signal_exception.signo   ->  num
00280  *
00281  *  Returns a signal number.
00282  */
00283 
00284 static VALUE
00285 esignal_signo(VALUE self)
00286 {
00287     return rb_iv_get(self, "signo");
00288 }
00289 
00290 /* :nodoc: */
00291 static VALUE
00292 interrupt_init(int argc, VALUE *argv, VALUE self)
00293 {
00294     VALUE args[2];
00295 
00296     args[0] = INT2FIX(SIGINT);
00297     rb_scan_args(argc, argv, "01", &args[1]);
00298     return rb_call_super(2, args);
00299 }
00300 
00301 void
00302 ruby_default_signal(int sig)
00303 {
00304     signal(sig, SIG_DFL);
00305     raise(sig);
00306 }
00307 
00308 /*
00309  *  call-seq:
00310  *     Process.kill(signal, pid, ...)    -> fixnum
00311  *
00312  *  Sends the given signal to the specified process id(s), or to the
00313  *  current process if _pid_ is zero. _signal_ may be an
00314  *  integer signal number or a POSIX signal name (either with or without
00315  *  a +SIG+ prefix). If _signal_ is negative (or starts
00316  *  with a minus sign), kills process groups instead of
00317  *  processes. Not all signals are available on all platforms.
00318  *
00319  *     pid = fork do
00320  *        Signal.trap("HUP") { puts "Ouch!"; exit }
00321  *        # ... do some work ...
00322  *     end
00323  *     # ...
00324  *     Process.kill("HUP", pid)
00325  *     Process.wait
00326  *
00327  *  <em>produces:</em>
00328  *
00329  *     Ouch!
00330  *
00331  *  If _signal_ is an integer but wrong for signal,
00332  *  <code>Errno::EINVAL</code> or +RangeError+ will be raised.
00333  *  Otherwise unless _signal_ is a +String+ or a +Symbol+, and a known
00334  *  signal name, +ArgumentError+ will be raised.
00335  *
00336  *  Also, <code>Errno::ESRCH</code> or +RangeError+ for invalid _pid_,
00337  *  <code>Errno::EPERM</code> when failed because of no privilege,
00338  *  will be raised.  In these cases, signals may have been sent to
00339  *  preceding processes.
00340  */
00341 
00342 VALUE
00343 rb_f_kill(int argc, VALUE *argv)
00344 {
00345 #ifndef HAS_KILLPG
00346 #define killpg(pg, sig) kill(-(pg), sig)
00347 #endif
00348     int negative = 0;
00349     int sig;
00350     int i;
00351     const char *s;
00352 
00353     rb_secure(2);
00354     if (argc < 2)
00355         rb_raise(rb_eArgError, "wrong number of arguments (%d for at least 2)", argc);
00356     switch (TYPE(argv[0])) {
00357       case T_FIXNUM:
00358         sig = FIX2INT(argv[0]);
00359         break;
00360 
00361       case T_SYMBOL:
00362         s = rb_id2name(SYM2ID(argv[0]));
00363         if (!s) rb_raise(rb_eArgError, "bad signal");
00364         goto str_signal;
00365 
00366       case T_STRING:
00367         s = RSTRING_PTR(argv[0]);
00368         if (s[0] == '-') {
00369             negative++;
00370             s++;
00371         }
00372       str_signal:
00373         if (strncmp("SIG", s, 3) == 0)
00374             s += 3;
00375         if((sig = signm2signo(s)) == 0)
00376             rb_raise(rb_eArgError, "unsupported name `SIG%s'", s);
00377 
00378         if (negative)
00379             sig = -sig;
00380         break;
00381 
00382       default:
00383         {
00384             VALUE str;
00385 
00386             str = rb_check_string_type(argv[0]);
00387             if (!NIL_P(str)) {
00388                 s = RSTRING_PTR(str);
00389                 goto str_signal;
00390             }
00391             rb_raise(rb_eArgError, "bad signal type %s",
00392                      rb_obj_classname(argv[0]));
00393         }
00394         break;
00395     }
00396 
00397     if (sig < 0) {
00398         sig = -sig;
00399         for (i=1; i<argc; i++) {
00400             if (killpg(NUM2PIDT(argv[i]), sig) < 0)
00401                 rb_sys_fail(0);
00402         }
00403     }
00404     else {
00405         for (i=1; i<argc; i++) {
00406             if (kill(NUM2PIDT(argv[i]), sig) < 0)
00407                 rb_sys_fail(0);
00408         }
00409     }
00410     rb_thread_polling();
00411     return INT2FIX(i-1);
00412 }
00413 
00414 static struct {
00415     rb_atomic_t cnt[RUBY_NSIG];
00416     rb_atomic_t size;
00417 } signal_buff;
00418 
00419 #ifdef __dietlibc__
00420 #define sighandler_t sh_t
00421 #endif
00422 
00423 typedef RETSIGTYPE (*sighandler_t)(int);
00424 #ifdef USE_SIGALTSTACK
00425 typedef void ruby_sigaction_t(int, siginfo_t*, void*);
00426 #define SIGINFO_ARG , siginfo_t *info, void *ctx
00427 #else
00428 typedef RETSIGTYPE ruby_sigaction_t(int);
00429 #define SIGINFO_ARG
00430 #endif
00431 
00432 #ifdef POSIX_SIGNAL
00433 
00434 #ifdef USE_SIGALTSTACK
00435 #ifdef SIGSTKSZ
00436 #define ALT_STACK_SIZE (SIGSTKSZ*2)
00437 #else
00438 #define ALT_STACK_SIZE (4*1024)
00439 #endif
00440 /* alternate stack for SIGSEGV */
00441 void
00442 rb_register_sigaltstack(rb_thread_t *th)
00443 {
00444     stack_t newSS, oldSS;
00445 
00446     if (th->altstack) return;
00447 
00448     newSS.ss_sp = th->altstack = malloc(ALT_STACK_SIZE);
00449     if (newSS.ss_sp == NULL)
00450         /* should handle error */
00451         rb_bug("rb_register_sigaltstack. malloc error\n");
00452     newSS.ss_size = ALT_STACK_SIZE;
00453     newSS.ss_flags = 0;
00454 
00455     sigaltstack(&newSS, &oldSS); /* ignore error. */
00456 }
00457 #endif
00458 
00459 static sighandler_t
00460 ruby_signal(int signum, sighandler_t handler)
00461 {
00462     struct sigaction sigact, old;
00463 
00464 #if 0
00465     rb_trap_accept_nativethreads[signum] = 0;
00466 #endif
00467 
00468     sigemptyset(&sigact.sa_mask);
00469 #ifdef SA_SIGINFO
00470     sigact.sa_sigaction = (ruby_sigaction_t*)handler;
00471     sigact.sa_flags = SA_SIGINFO;
00472 #else
00473     sigact.sa_handler = handler;
00474     sigact.sa_flags = 0;
00475 #endif
00476 
00477 #ifdef SA_NOCLDWAIT
00478     if (signum == SIGCHLD && handler == SIG_IGN)
00479         sigact.sa_flags |= SA_NOCLDWAIT;
00480 #endif
00481 #if defined(SA_ONSTACK) && defined(USE_SIGALTSTACK)
00482     if (signum == SIGSEGV)
00483         sigact.sa_flags |= SA_ONSTACK;
00484 #endif
00485     if (sigaction(signum, &sigact, &old) < 0) {
00486         if (errno != 0 && errno != EINVAL) {
00487             rb_bug_errno("sigaction", errno);
00488         }
00489     }
00490     return old.sa_handler;
00491 }
00492 
00493 sighandler_t
00494 posix_signal(int signum, sighandler_t handler)
00495 {
00496     return ruby_signal(signum, handler);
00497 }
00498 
00499 #else /* !POSIX_SIGNAL */
00500 #define ruby_signal(sig,handler) (/* rb_trap_accept_nativethreads[sig] = 0,*/ signal((sig),(handler)))
00501 #if 0 /* def HAVE_NATIVETHREAD */
00502 static sighandler_t
00503 ruby_nativethread_signal(int signum, sighandler_t handler)
00504 {
00505     sighandler_t old;
00506 
00507     old = signal(signum, handler);
00508     rb_trap_accept_nativethreads[signum] = 1;
00509     return old;
00510 }
00511 #endif
00512 #endif
00513 
00514 static RETSIGTYPE
00515 sighandler(int sig)
00516 {
00517     ATOMIC_INC(signal_buff.cnt[sig]);
00518     ATOMIC_INC(signal_buff.size);
00519 #if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
00520     ruby_signal(sig, sighandler);
00521 #endif
00522 }
00523 
00524 int
00525 rb_signal_buff_size(void)
00526 {
00527     return signal_buff.size;
00528 }
00529 
00530 #if USE_TRAP_MASK
00531 # ifdef HAVE_SIGPROCMASK
00532 static sigset_t trap_last_mask;
00533 # else
00534 static int trap_last_mask;
00535 # endif
00536 #endif
00537 
00538 #if HAVE_PTHREAD_H
00539 #include <pthread.h>
00540 #endif
00541 
00542 void
00543 rb_disable_interrupt(void)
00544 {
00545 #if USE_TRAP_MASK
00546     sigset_t mask;
00547     sigfillset(&mask);
00548     sigdelset(&mask, SIGVTALRM);
00549     sigdelset(&mask, SIGSEGV);
00550     pthread_sigmask(SIG_SETMASK, &mask, NULL);
00551 #endif
00552 }
00553 
00554 void
00555 rb_enable_interrupt(void)
00556 {
00557 #if USE_TRAP_MASK
00558     sigset_t mask;
00559     sigemptyset(&mask);
00560     pthread_sigmask(SIG_SETMASK, &mask, NULL);
00561 #endif
00562 }
00563 
00564 int
00565 rb_get_next_signal(void)
00566 {
00567     int i, sig = 0;
00568 
00569     if (signal_buff.size != 0) {
00570         for (i=1; i<RUBY_NSIG; i++) {
00571             if (signal_buff.cnt[i] > 0) {
00572                 rb_disable_interrupt();
00573                 {
00574                     ATOMIC_DEC(signal_buff.cnt[i]);
00575                     ATOMIC_DEC(signal_buff.size);
00576                 }
00577                 rb_enable_interrupt();
00578                 sig = i;
00579                 break;
00580             }
00581         }
00582     }
00583     return sig;
00584 }
00585 
00586 #ifdef SIGBUS
00587 static RETSIGTYPE
00588 sigbus(int sig)
00589 {
00590     rb_bug("Bus Error");
00591 }
00592 #endif
00593 
00594 #ifdef SIGSEGV
00595 static int segv_received = 0;
00596 static RETSIGTYPE
00597 sigsegv(int sig SIGINFO_ARG)
00598 {
00599 #ifdef USE_SIGALTSTACK
00600     int ruby_stack_overflowed_p(const rb_thread_t *, const void *);
00601     NORETURN(void ruby_thread_stack_overflow(rb_thread_t *th));
00602     rb_thread_t *th = GET_THREAD();
00603     if (ruby_stack_overflowed_p(th, info->si_addr)) {
00604         ruby_thread_stack_overflow(th);
00605     }
00606 #endif
00607     if (segv_received) {
00608         fprintf(stderr, "SEGV received in SEGV handler\n");
00609         exit(EXIT_FAILURE);
00610     }
00611     else {
00612         extern int ruby_disable_gc_stress;
00613         segv_received = 1;
00614         ruby_disable_gc_stress = 1;
00615         rb_bug("Segmentation fault");
00616     }
00617 }
00618 #endif
00619 
00620 #ifdef SIGPIPE
00621 static RETSIGTYPE
00622 sigpipe(int sig)
00623 {
00624     /* do nothing */
00625 }
00626 #endif
00627 
00628 static void
00629 signal_exec(VALUE cmd, int safe, int sig)
00630 {
00631     VALUE signum = INT2NUM(sig);
00632     rb_eval_cmd(cmd, rb_ary_new3(1, signum), safe);
00633 }
00634 
00635 void
00636 rb_trap_exit(void)
00637 {
00638     rb_vm_t *vm = GET_VM();
00639     VALUE trap_exit = vm->trap_list[0].cmd;
00640 
00641     if (trap_exit) {
00642         vm->trap_list[0].cmd = 0;
00643         signal_exec(trap_exit, vm->trap_list[0].safe, 0);
00644     }
00645 }
00646 
00647 void
00648 rb_signal_exec(rb_thread_t *th, int sig)
00649 {
00650     rb_vm_t *vm = GET_VM();
00651     VALUE cmd = vm->trap_list[sig].cmd;
00652     int safe = vm->trap_list[sig].safe;
00653 
00654     if (cmd == 0) {
00655         switch (sig) {
00656           case SIGINT:
00657             rb_interrupt();
00658             break;
00659 #ifdef SIGHUP
00660           case SIGHUP:
00661 #endif
00662 #ifdef SIGQUIT
00663           case SIGQUIT:
00664 #endif
00665 #ifdef SIGTERM
00666           case SIGTERM:
00667 #endif
00668 #ifdef SIGALRM
00669           case SIGALRM:
00670 #endif
00671 #ifdef SIGUSR1
00672           case SIGUSR1:
00673 #endif
00674 #ifdef SIGUSR2
00675           case SIGUSR2:
00676 #endif
00677             rb_threadptr_signal_raise(th, sig);
00678             break;
00679         }
00680     }
00681     else if (cmd == Qundef) {
00682         rb_threadptr_signal_exit(th);
00683     }
00684     else {
00685         signal_exec(cmd, safe, sig);
00686     }
00687 }
00688 
00689 struct trap_arg {
00690 #if USE_TRAP_MASK
00691 # ifdef HAVE_SIGPROCMASK
00692     sigset_t mask;
00693 # else
00694     int mask;
00695 # endif
00696 #endif
00697     int sig;
00698     sighandler_t func;
00699     VALUE cmd;
00700 };
00701 
00702 static sighandler_t
00703 default_handler(int sig)
00704 {
00705     sighandler_t func;
00706     switch (sig) {
00707       case SIGINT:
00708 #ifdef SIGHUP
00709       case SIGHUP:
00710 #endif
00711 #ifdef SIGQUIT
00712       case SIGQUIT:
00713 #endif
00714 #ifdef SIGTERM
00715       case SIGTERM:
00716 #endif
00717 #ifdef SIGALRM
00718       case SIGALRM:
00719 #endif
00720 #ifdef SIGUSR1
00721       case SIGUSR1:
00722 #endif
00723 #ifdef SIGUSR2
00724       case SIGUSR2:
00725 #endif
00726         func = sighandler;
00727         break;
00728 #ifdef SIGBUS
00729       case SIGBUS:
00730         func = sigbus;
00731         break;
00732 #endif
00733 #ifdef SIGSEGV
00734       case SIGSEGV:
00735         func = (sighandler_t)sigsegv;
00736 # ifdef USE_SIGALTSTACK
00737         rb_register_sigaltstack(GET_THREAD());
00738 # endif
00739         break;
00740 #endif
00741 #ifdef SIGPIPE
00742       case SIGPIPE:
00743         func = sigpipe;
00744         break;
00745 #endif
00746       default:
00747         func = SIG_DFL;
00748         break;
00749     }
00750 
00751     return func;
00752 }
00753 
00754 static sighandler_t
00755 trap_handler(VALUE *cmd, int sig)
00756 {
00757     sighandler_t func = sighandler;
00758     VALUE command;
00759 
00760     if (NIL_P(*cmd)) {
00761         func = SIG_IGN;
00762     }
00763     else {
00764         command = rb_check_string_type(*cmd);
00765         if (NIL_P(command) && SYMBOL_P(*cmd)) {
00766             command = rb_id2str(SYM2ID(*cmd));
00767             if (!command) rb_raise(rb_eArgError, "bad handler");
00768         }
00769         if (!NIL_P(command)) {
00770             SafeStringValue(command);   /* taint check */
00771             *cmd = command;
00772             switch (RSTRING_LEN(command)) {
00773               case 0:
00774                 goto sig_ign;
00775                 break;
00776               case 14:
00777                 if (strncmp(RSTRING_PTR(command), "SYSTEM_DEFAULT", 14) == 0) {
00778                     func = SIG_DFL;
00779                     *cmd = 0;
00780                 }
00781                 break;
00782               case 7:
00783                 if (strncmp(RSTRING_PTR(command), "SIG_IGN", 7) == 0) {
00784 sig_ign:
00785                     func = SIG_IGN;
00786                     *cmd = 0;
00787                 }
00788                 else if (strncmp(RSTRING_PTR(command), "SIG_DFL", 7) == 0) {
00789 sig_dfl:
00790                     func = default_handler(sig);
00791                     *cmd = 0;
00792                 }
00793                 else if (strncmp(RSTRING_PTR(command), "DEFAULT", 7) == 0) {
00794                     goto sig_dfl;
00795                 }
00796                 break;
00797               case 6:
00798                 if (strncmp(RSTRING_PTR(command), "IGNORE", 6) == 0) {
00799                     goto sig_ign;
00800                 }
00801                 break;
00802               case 4:
00803                 if (strncmp(RSTRING_PTR(command), "EXIT", 4) == 0) {
00804                     *cmd = Qundef;
00805                 }
00806                 break;
00807             }
00808         }
00809         else {
00810             rb_proc_t *proc;
00811             GetProcPtr(*cmd, proc);
00812         }
00813     }
00814 
00815     return func;
00816 }
00817 
00818 static int
00819 trap_signm(VALUE vsig)
00820 {
00821     int sig = -1;
00822     const char *s;
00823 
00824     switch (TYPE(vsig)) {
00825       case T_FIXNUM:
00826         sig = FIX2INT(vsig);
00827         if (sig < 0 || sig >= NSIG) {
00828             rb_raise(rb_eArgError, "invalid signal number (%d)", sig);
00829         }
00830         break;
00831 
00832       case T_SYMBOL:
00833         s = rb_id2name(SYM2ID(vsig));
00834         if (!s) rb_raise(rb_eArgError, "bad signal");
00835         goto str_signal;
00836 
00837       default:
00838         s = StringValuePtr(vsig);
00839 
00840       str_signal:
00841         if (strncmp("SIG", s, 3) == 0)
00842             s += 3;
00843         sig = signm2signo(s);
00844         if (sig == 0 && strcmp(s, "EXIT") != 0)
00845             rb_raise(rb_eArgError, "unsupported signal SIG%s", s);
00846     }
00847     return sig;
00848 }
00849 
00850 static VALUE
00851 trap(struct trap_arg *arg)
00852 {
00853     sighandler_t oldfunc, func = arg->func;
00854     VALUE oldcmd, command = arg->cmd;
00855     int sig = arg->sig;
00856     rb_vm_t *vm = GET_VM();
00857 
00858     oldfunc = ruby_signal(sig, func);
00859     oldcmd = vm->trap_list[sig].cmd;
00860     switch (oldcmd) {
00861       case 0:
00862         if (oldfunc == SIG_IGN) oldcmd = rb_str_new2("IGNORE");
00863         else if (oldfunc == sighandler) oldcmd = rb_str_new2("DEFAULT");
00864         else oldcmd = Qnil;
00865         break;
00866       case Qundef:
00867         oldcmd = rb_str_new2("EXIT");
00868         break;
00869     }
00870 
00871     vm->trap_list[sig].cmd = command;
00872     vm->trap_list[sig].safe = rb_safe_level();
00873     /* enable at least specified signal. */
00874 #if USE_TRAP_MASK
00875 #ifdef HAVE_SIGPROCMASK
00876     sigdelset(&arg->mask, sig);
00877 #else
00878     arg->mask &= ~sigmask(sig);
00879 #endif
00880 #endif
00881     return oldcmd;
00882 }
00883 
00884 #if USE_TRAP_MASK
00885 static VALUE
00886 trap_ensure(struct trap_arg *arg)
00887 {
00888     /* enable interrupt */
00889     pthread_sigmask(SIG_SETMASK, &arg->mask, NULL);
00890     trap_last_mask = arg->mask;
00891     return 0;
00892 }
00893 #endif
00894 
00895 void
00896 rb_trap_restore_mask(void)
00897 {
00898 #if USE_TRAP_MASK
00899     pthread_sigmask(SIG_SETMASK, &trap_last_mask, NULL);
00900 #endif
00901 }
00902 
00903 /*
00904  * call-seq:
00905  *   Signal.trap( signal, command ) -> obj
00906  *   Signal.trap( signal ) {| | block } -> obj
00907  *
00908  * Specifies the handling of signals. The first parameter is a signal
00909  * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a
00910  * signal number. The characters ``SIG'' may be omitted from the
00911  * signal name. The command or block specifies code to be run when the
00912  * signal is raised.
00913  * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal
00914  * will be ignored.
00915  * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler
00916  * will be invoked.
00917  * If the command is ``EXIT'', the script will be terminated by the signal.
00918  * If the command is ``SYSTEM_DEFAULT'', the operating system's default
00919  * handler will be invoked.
00920  * Otherwise, the given command or block will be run.
00921  * The special signal name ``EXIT'' or signal number zero will be
00922  * invoked just prior to program termination.
00923  * trap returns the previous handler for the given signal.
00924  *
00925  *     Signal.trap(0, proc { puts "Terminating: #{$$}" })
00926  *     Signal.trap("CLD")  { puts "Child died" }
00927  *     fork && Process.wait
00928  *
00929  * produces:
00930  *     Terminating: 27461
00931  *     Child died
00932  *     Terminating: 27460
00933  */
00934 static VALUE
00935 sig_trap(int argc, VALUE *argv)
00936 {
00937     struct trap_arg arg;
00938 
00939     rb_secure(2);
00940     if (argc < 1 || argc > 2) {
00941         rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)", argc);
00942     }
00943 
00944     arg.sig = trap_signm(argv[0]);
00945     if (argc == 1) {
00946         arg.cmd = rb_block_proc();
00947         arg.func = sighandler;
00948     }
00949     else {
00950         arg.cmd = argv[1];
00951         arg.func = trap_handler(&arg.cmd, arg.sig);
00952     }
00953 
00954     if (OBJ_TAINTED(arg.cmd)) {
00955         rb_raise(rb_eSecurityError, "Insecure: tainted signal trap");
00956     }
00957 #if USE_TRAP_MASK
00958     {
00959       sigset_t fullmask;
00960 
00961       /* disable interrupt */
00962       sigfillset(&fullmask);
00963       pthread_sigmask(SIG_BLOCK, &fullmask, &arg.mask);
00964       
00965       return rb_ensure(trap, (VALUE)&arg, trap_ensure, (VALUE)&arg);
00966     }
00967 #else
00968     return trap(&arg);
00969 #endif
00970 }
00971 
00972 /*
00973  * call-seq:
00974  *   Signal.list -> a_hash
00975  *
00976  * Returns a list of signal names mapped to the corresponding
00977  * underlying signal numbers.
00978  *
00979  *   Signal.list   #=> {"EXIT"=>0, "HUP"=>1, "INT"=>2, "QUIT"=>3, "ILL"=>4, "TRAP"=>5, "IOT"=>6, "ABRT"=>6, "FPE"=>8, "KILL"=>9, "BUS"=>7, "SEGV"=>11, "SYS"=>31, "PIPE"=>13, "ALRM"=>14, "TERM"=>15, "URG"=>23, "STOP"=>19, "TSTP"=>20, "CONT"=>18, "CHLD"=>17, "CLD"=>17, "TTIN"=>21, "TTOU"=>22, "IO"=>29, "XCPU"=>24, "XFSZ"=>25, "VTALRM"=>26, "PROF"=>27, "WINCH"=>28, "USR1"=>10, "USR2"=>12, "PWR"=>30, "POLL"=>29}
00980  */
00981 static VALUE
00982 sig_list(void)
00983 {
00984     VALUE h = rb_hash_new();
00985     const struct signals *sigs;
00986 
00987     for (sigs = siglist; sigs->signm; sigs++) {
00988         rb_hash_aset(h, rb_str_new2(sigs->signm), INT2FIX(sigs->signo));
00989     }
00990     return h;
00991 }
00992 
00993 static void
00994 install_sighandler(int signum, sighandler_t handler)
00995 {
00996     sighandler_t old;
00997 
00998     old = ruby_signal(signum, handler);
00999     if (old != SIG_DFL) {
01000         ruby_signal(signum, old);
01001     }
01002 }
01003 
01004 #if defined(SIGCLD) || defined(SIGCHLD)
01005 static void
01006 init_sigchld(int sig)
01007 {
01008     sighandler_t oldfunc;
01009 #if USE_TRAP_MASK
01010 # ifdef HAVE_SIGPROCMASK
01011     sigset_t mask;
01012     sigset_t fullmask;
01013 # else
01014     int mask;
01015     int fullmask;
01016 # endif
01017 #endif
01018 
01019 #if USE_TRAP_MASK
01020     /* disable interrupt */
01021     sigfillset(&fullmask);
01022     pthread_sigmask(SIG_BLOCK, &fullmask, &mask);
01023 #endif
01024 
01025     oldfunc = ruby_signal(sig, SIG_DFL);
01026     if (oldfunc != SIG_DFL && oldfunc != SIG_IGN) {
01027         ruby_signal(sig, oldfunc);
01028     } else {
01029         GET_VM()->trap_list[sig].cmd = 0;
01030     }
01031 
01032 #if USE_TRAP_MASK
01033     sigdelset(&mask, sig);
01034     pthread_sigmask(SIG_SETMASK, &mask, NULL);
01035     trap_last_mask = mask;
01036 #endif
01037 }
01038 #endif
01039 
01040 void
01041 ruby_sig_finalize(void)
01042 {
01043     sighandler_t oldfunc;
01044 
01045     oldfunc = ruby_signal(SIGINT, SIG_IGN);
01046     if (oldfunc == sighandler) {
01047         ruby_signal(SIGINT, SIG_DFL);
01048     }
01049 }
01050 
01051 
01052 #ifdef RUBY_DEBUG_ENV
01053 int ruby_enable_coredump = 0;
01054 #endif
01055 
01056 /*
01057  * Many operating systems allow signals to be sent to running
01058  * processes. Some signals have a defined effect on the process, while
01059  * others may be trapped at the code level and acted upon. For
01060  * example, your process may trap the USR1 signal and use it to toggle
01061  * debugging, and may use TERM to initiate a controlled shutdown.
01062  *
01063  *     pid = fork do
01064  *       Signal.trap("USR1") do
01065  *         $debug = !$debug
01066  *         puts "Debug now: #$debug"
01067  *       end
01068  *       Signal.trap("TERM") do
01069  *         puts "Terminating..."
01070  *         shutdown()
01071  *       end
01072  *       # . . . do some work . . .
01073  *     end
01074  *
01075  *     Process.detach(pid)
01076  *
01077  *     # Controlling program:
01078  *     Process.kill("USR1", pid)
01079  *     # ...
01080  *     Process.kill("USR1", pid)
01081  *     # ...
01082  *     Process.kill("TERM", pid)
01083  *
01084  * produces:
01085  *     Debug now: true
01086  *     Debug now: false
01087  *    Terminating...
01088  *
01089  * The list of available signal names and their interpretation is
01090  * system dependent. Signal delivery semantics may also vary between
01091  * systems; in particular signal delivery may not always be reliable.
01092  */
01093 void
01094 Init_signal(void)
01095 {
01096     VALUE mSignal = rb_define_module("Signal");
01097 
01098     rb_define_global_function("trap", sig_trap, -1);
01099     rb_define_module_function(mSignal, "trap", sig_trap, -1);
01100     rb_define_module_function(mSignal, "list", sig_list, 0);
01101 
01102     rb_define_method(rb_eSignal, "initialize", esignal_init, -1);
01103     rb_define_method(rb_eSignal, "signo", esignal_signo, 0);
01104     rb_alias(rb_eSignal, rb_intern("signm"), rb_intern("message"));
01105     rb_define_method(rb_eInterrupt, "initialize", interrupt_init, -1);
01106 
01107     install_sighandler(SIGINT, sighandler);
01108 #ifdef SIGHUP
01109     install_sighandler(SIGHUP, sighandler);
01110 #endif
01111 #ifdef SIGQUIT
01112     install_sighandler(SIGQUIT, sighandler);
01113 #endif
01114 #ifdef SIGTERM
01115     install_sighandler(SIGTERM, sighandler);
01116 #endif
01117 #ifdef SIGALRM
01118     install_sighandler(SIGALRM, sighandler);
01119 #endif
01120 #ifdef SIGUSR1
01121     install_sighandler(SIGUSR1, sighandler);
01122 #endif
01123 #ifdef SIGUSR2
01124     install_sighandler(SIGUSR2, sighandler);
01125 #endif
01126 
01127 #ifdef RUBY_DEBUG_ENV
01128     if (!ruby_enable_coredump)
01129 #endif
01130     {
01131 #ifdef SIGBUS
01132     install_sighandler(SIGBUS, sigbus);
01133 #endif
01134 #ifdef SIGSEGV
01135 # ifdef USE_SIGALTSTACK
01136     rb_register_sigaltstack(GET_THREAD());
01137 # endif
01138     install_sighandler(SIGSEGV, (sighandler_t)sigsegv);
01139 #endif
01140     }
01141 #ifdef SIGPIPE
01142     install_sighandler(SIGPIPE, sigpipe);
01143 #endif
01144 
01145 #if defined(SIGCLD)
01146     init_sigchld(SIGCLD);
01147 #elif defined(SIGCHLD)
01148     init_sigchld(SIGCHLD);
01149 #endif
01150 }
01151 

Generated on Sat Jul 7 2012 15:29:23 for Ruby by  doxygen 1.7.1