• 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     for (i=1; i<RUBY_NSIG; i++) {
00570         if (signal_buff.cnt[i] > 0) {
00571             rb_disable_interrupt();
00572             {
00573                 ATOMIC_DEC(signal_buff.cnt[i]);
00574                 ATOMIC_DEC(signal_buff.size);
00575             }
00576             rb_enable_interrupt();
00577             sig = i;
00578             break;
00579         }
00580     }
00581     return sig;
00582 }
00583 
00584 #ifdef SIGBUS
00585 static RETSIGTYPE
00586 sigbus(int sig)
00587 {
00588     rb_bug("Bus Error");
00589 }
00590 #endif
00591 
00592 #ifdef SIGSEGV
00593 static int segv_received = 0;
00594 static RETSIGTYPE
00595 sigsegv(int sig SIGINFO_ARG)
00596 {
00597 #ifdef USE_SIGALTSTACK
00598     int ruby_stack_overflowed_p(const rb_thread_t *, const void *);
00599     NORETURN(void ruby_thread_stack_overflow(rb_thread_t *th));
00600     rb_thread_t *th = GET_THREAD();
00601     if (ruby_stack_overflowed_p(th, info->si_addr)) {
00602         ruby_thread_stack_overflow(th);
00603     }
00604 #endif
00605     if (segv_received) {
00606         fprintf(stderr, "SEGV received in SEGV handler\n");
00607         exit(EXIT_FAILURE);
00608     }
00609     else {
00610         extern int ruby_disable_gc_stress;
00611         segv_received = 1;
00612         ruby_disable_gc_stress = 1;
00613         rb_bug("Segmentation fault");
00614     }
00615 }
00616 #endif
00617 
00618 #ifdef SIGPIPE
00619 static RETSIGTYPE
00620 sigpipe(int sig)
00621 {
00622     /* do nothing */
00623 }
00624 #endif
00625 
00626 static void
00627 signal_exec(VALUE cmd, int safe, int sig)
00628 {
00629     VALUE signum = INT2NUM(sig);
00630     rb_eval_cmd(cmd, rb_ary_new3(1, signum), safe);
00631 }
00632 
00633 void
00634 rb_trap_exit(void)
00635 {
00636     rb_vm_t *vm = GET_VM();
00637     VALUE trap_exit = vm->trap_list[0].cmd;
00638 
00639     if (trap_exit) {
00640         vm->trap_list[0].cmd = 0;
00641         signal_exec(trap_exit, vm->trap_list[0].safe, 0);
00642     }
00643 }
00644 
00645 void
00646 rb_signal_exec(rb_thread_t *th, int sig)
00647 {
00648     rb_vm_t *vm = GET_VM();
00649     VALUE cmd = vm->trap_list[sig].cmd;
00650     int safe = vm->trap_list[sig].safe;
00651 
00652     if (cmd == 0) {
00653         switch (sig) {
00654           case SIGINT:
00655             rb_interrupt();
00656             break;
00657 #ifdef SIGHUP
00658           case SIGHUP:
00659 #endif
00660 #ifdef SIGQUIT
00661           case SIGQUIT:
00662 #endif
00663 #ifdef SIGTERM
00664           case SIGTERM:
00665 #endif
00666 #ifdef SIGALRM
00667           case SIGALRM:
00668 #endif
00669 #ifdef SIGUSR1
00670           case SIGUSR1:
00671 #endif
00672 #ifdef SIGUSR2
00673           case SIGUSR2:
00674 #endif
00675             rb_threadptr_signal_raise(th, sig);
00676             break;
00677         }
00678     }
00679     else if (cmd == Qundef) {
00680         rb_threadptr_signal_exit(th);
00681     }
00682     else {
00683         signal_exec(cmd, safe, sig);
00684     }
00685 }
00686 
00687 struct trap_arg {
00688 #if USE_TRAP_MASK
00689 # ifdef HAVE_SIGPROCMASK
00690     sigset_t mask;
00691 # else
00692     int mask;
00693 # endif
00694 #endif
00695     int sig;
00696     sighandler_t func;
00697     VALUE cmd;
00698 };
00699 
00700 static sighandler_t
00701 default_handler(int sig)
00702 {
00703     sighandler_t func;
00704     switch (sig) {
00705       case SIGINT:
00706 #ifdef SIGHUP
00707       case SIGHUP:
00708 #endif
00709 #ifdef SIGQUIT
00710       case SIGQUIT:
00711 #endif
00712 #ifdef SIGTERM
00713       case SIGTERM:
00714 #endif
00715 #ifdef SIGALRM
00716       case SIGALRM:
00717 #endif
00718 #ifdef SIGUSR1
00719       case SIGUSR1:
00720 #endif
00721 #ifdef SIGUSR2
00722       case SIGUSR2:
00723 #endif
00724         func = sighandler;
00725         break;
00726 #ifdef SIGBUS
00727       case SIGBUS:
00728         func = sigbus;
00729         break;
00730 #endif
00731 #ifdef SIGSEGV
00732       case SIGSEGV:
00733         func = (sighandler_t)sigsegv;
00734 # ifdef USE_SIGALTSTACK
00735         rb_register_sigaltstack(GET_THREAD());
00736 # endif
00737         break;
00738 #endif
00739 #ifdef SIGPIPE
00740       case SIGPIPE:
00741         func = sigpipe;
00742         break;
00743 #endif
00744       default:
00745         func = SIG_DFL;
00746         break;
00747     }
00748 
00749     return func;
00750 }
00751 
00752 static sighandler_t
00753 trap_handler(VALUE *cmd, int sig)
00754 {
00755     sighandler_t func = sighandler;
00756     VALUE command;
00757 
00758     if (NIL_P(*cmd)) {
00759         func = SIG_IGN;
00760     }
00761     else {
00762         command = rb_check_string_type(*cmd);
00763         if (NIL_P(command) && SYMBOL_P(*cmd)) {
00764             command = rb_id2str(SYM2ID(*cmd));
00765             if (!command) rb_raise(rb_eArgError, "bad handler");
00766         }
00767         if (!NIL_P(command)) {
00768             SafeStringValue(command);   /* taint check */
00769             *cmd = command;
00770             switch (RSTRING_LEN(command)) {
00771               case 0:
00772                 goto sig_ign;
00773                 break;
00774               case 14:
00775                 if (strncmp(RSTRING_PTR(command), "SYSTEM_DEFAULT", 14) == 0) {
00776                     func = SIG_DFL;
00777                     *cmd = 0;
00778                 }
00779                 break;
00780               case 7:
00781                 if (strncmp(RSTRING_PTR(command), "SIG_IGN", 7) == 0) {
00782 sig_ign:
00783                     func = SIG_IGN;
00784                     *cmd = 0;
00785                 }
00786                 else if (strncmp(RSTRING_PTR(command), "SIG_DFL", 7) == 0) {
00787 sig_dfl:
00788                     func = default_handler(sig);
00789                     *cmd = 0;
00790                 }
00791                 else if (strncmp(RSTRING_PTR(command), "DEFAULT", 7) == 0) {
00792                     goto sig_dfl;
00793                 }
00794                 break;
00795               case 6:
00796                 if (strncmp(RSTRING_PTR(command), "IGNORE", 6) == 0) {
00797                     goto sig_ign;
00798                 }
00799                 break;
00800               case 4:
00801                 if (strncmp(RSTRING_PTR(command), "EXIT", 4) == 0) {
00802                     *cmd = Qundef;
00803                 }
00804                 break;
00805             }
00806         }
00807         else {
00808             rb_proc_t *proc;
00809             GetProcPtr(*cmd, proc);
00810         }
00811     }
00812 
00813     return func;
00814 }
00815 
00816 static int
00817 trap_signm(VALUE vsig)
00818 {
00819     int sig = -1;
00820     const char *s;
00821 
00822     switch (TYPE(vsig)) {
00823       case T_FIXNUM:
00824         sig = FIX2INT(vsig);
00825         if (sig < 0 || sig >= NSIG) {
00826             rb_raise(rb_eArgError, "invalid signal number (%d)", sig);
00827         }
00828         break;
00829 
00830       case T_SYMBOL:
00831         s = rb_id2name(SYM2ID(vsig));
00832         if (!s) rb_raise(rb_eArgError, "bad signal");
00833         goto str_signal;
00834 
00835       default:
00836         s = StringValuePtr(vsig);
00837 
00838       str_signal:
00839         if (strncmp("SIG", s, 3) == 0)
00840             s += 3;
00841         sig = signm2signo(s);
00842         if (sig == 0 && strcmp(s, "EXIT") != 0)
00843             rb_raise(rb_eArgError, "unsupported signal SIG%s", s);
00844     }
00845     return sig;
00846 }
00847 
00848 static VALUE
00849 trap(struct trap_arg *arg)
00850 {
00851     sighandler_t oldfunc, func = arg->func;
00852     VALUE oldcmd, command = arg->cmd;
00853     int sig = arg->sig;
00854     rb_vm_t *vm = GET_VM();
00855 
00856     oldfunc = ruby_signal(sig, func);
00857     oldcmd = vm->trap_list[sig].cmd;
00858     switch (oldcmd) {
00859       case 0:
00860         if (oldfunc == SIG_IGN) oldcmd = rb_str_new2("IGNORE");
00861         else if (oldfunc == sighandler) oldcmd = rb_str_new2("DEFAULT");
00862         else oldcmd = Qnil;
00863         break;
00864       case Qundef:
00865         oldcmd = rb_str_new2("EXIT");
00866         break;
00867     }
00868 
00869     vm->trap_list[sig].cmd = command;
00870     vm->trap_list[sig].safe = rb_safe_level();
00871     /* enable at least specified signal. */
00872 #if USE_TRAP_MASK
00873 #ifdef HAVE_SIGPROCMASK
00874     sigdelset(&arg->mask, sig);
00875 #else
00876     arg->mask &= ~sigmask(sig);
00877 #endif
00878 #endif
00879     return oldcmd;
00880 }
00881 
00882 #if USE_TRAP_MASK
00883 static VALUE
00884 trap_ensure(struct trap_arg *arg)
00885 {
00886     /* enable interrupt */
00887     pthread_sigmask(SIG_SETMASK, &arg->mask, NULL);
00888     trap_last_mask = arg->mask;
00889     return 0;
00890 }
00891 #endif
00892 
00893 void
00894 rb_trap_restore_mask(void)
00895 {
00896 #if USE_TRAP_MASK
00897     pthread_sigmask(SIG_SETMASK, &trap_last_mask, NULL);
00898 #endif
00899 }
00900 
00901 /*
00902  * call-seq:
00903  *   Signal.trap( signal, command ) -> obj
00904  *   Signal.trap( signal ) {| | block } -> obj
00905  *
00906  * Specifies the handling of signals. The first parameter is a signal
00907  * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a
00908  * signal number. The characters ``SIG'' may be omitted from the
00909  * signal name. The command or block specifies code to be run when the
00910  * signal is raised.
00911  * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal
00912  * will be ignored.
00913  * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler
00914  * will be invoked.
00915  * If the command is ``EXIT'', the script will be terminated by the signal.
00916  * If the command is ``SYSTEM_DEFAULT'', the operating system's default
00917  * handler will be invoked.
00918  * Otherwise, the given command or block will be run.
00919  * The special signal name ``EXIT'' or signal number zero will be
00920  * invoked just prior to program termination.
00921  * trap returns the previous handler for the given signal.
00922  *
00923  *     Signal.trap(0, proc { puts "Terminating: #{$$}" })
00924  *     Signal.trap("CLD")  { puts "Child died" }
00925  *     fork && Process.wait
00926  *
00927  * produces:
00928  *     Terminating: 27461
00929  *     Child died
00930  *     Terminating: 27460
00931  */
00932 static VALUE
00933 sig_trap(int argc, VALUE *argv)
00934 {
00935     struct trap_arg arg;
00936 
00937     rb_secure(2);
00938     if (argc < 1 || argc > 2) {
00939         rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)", argc);
00940     }
00941 
00942     arg.sig = trap_signm(argv[0]);
00943     if (argc == 1) {
00944         arg.cmd = rb_block_proc();
00945         arg.func = sighandler;
00946     }
00947     else {
00948         arg.cmd = argv[1];
00949         arg.func = trap_handler(&arg.cmd, arg.sig);
00950     }
00951 
00952     if (OBJ_TAINTED(arg.cmd)) {
00953         rb_raise(rb_eSecurityError, "Insecure: tainted signal trap");
00954     }
00955 #if USE_TRAP_MASK
00956     {
00957       sigset_t fullmask;
00958 
00959       /* disable interrupt */
00960       sigfillset(&fullmask);
00961       pthread_sigmask(SIG_BLOCK, &fullmask, &arg.mask);
00962       
00963       return rb_ensure(trap, (VALUE)&arg, trap_ensure, (VALUE)&arg);
00964     }
00965 #else
00966     return trap(&arg);
00967 #endif
00968 }
00969 
00970 /*
00971  * call-seq:
00972  *   Signal.list -> a_hash
00973  *
00974  * Returns a list of signal names mapped to the corresponding
00975  * underlying signal numbers.
00976  *
00977  *   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}
00978  */
00979 static VALUE
00980 sig_list(void)
00981 {
00982     VALUE h = rb_hash_new();
00983     const struct signals *sigs;
00984 
00985     for (sigs = siglist; sigs->signm; sigs++) {
00986         rb_hash_aset(h, rb_str_new2(sigs->signm), INT2FIX(sigs->signo));
00987     }
00988     return h;
00989 }
00990 
00991 static void
00992 install_sighandler(int signum, sighandler_t handler)
00993 {
00994     sighandler_t old;
00995 
00996     old = ruby_signal(signum, handler);
00997     if (old != SIG_DFL) {
00998         ruby_signal(signum, old);
00999     }
01000 }
01001 
01002 #if defined(SIGCLD) || defined(SIGCHLD)
01003 static void
01004 init_sigchld(int sig)
01005 {
01006     sighandler_t oldfunc;
01007 #if USE_TRAP_MASK
01008 # ifdef HAVE_SIGPROCMASK
01009     sigset_t mask;
01010     sigset_t fullmask;
01011 # else
01012     int mask;
01013     int fullmask;
01014 # endif
01015 #endif
01016 
01017 #if USE_TRAP_MASK
01018     /* disable interrupt */
01019     sigfillset(&fullmask);
01020     pthread_sigmask(SIG_BLOCK, &fullmask, &mask);
01021 #endif
01022 
01023     oldfunc = ruby_signal(sig, SIG_DFL);
01024     if (oldfunc != SIG_DFL && oldfunc != SIG_IGN) {
01025         ruby_signal(sig, oldfunc);
01026     } else {
01027         GET_VM()->trap_list[sig].cmd = 0;
01028     }
01029 
01030 #if USE_TRAP_MASK
01031     sigdelset(&mask, sig);
01032     pthread_sigmask(SIG_SETMASK, &mask, NULL);
01033     trap_last_mask = mask;
01034 #endif
01035 }
01036 #endif
01037 
01038 void
01039 ruby_sig_finalize(void)
01040 {
01041     sighandler_t oldfunc;
01042 
01043     oldfunc = ruby_signal(SIGINT, SIG_IGN);
01044     if (oldfunc == sighandler) {
01045         ruby_signal(SIGINT, SIG_DFL);
01046     }
01047 }
01048 
01049 
01050 #ifdef RUBY_DEBUG_ENV
01051 int ruby_enable_coredump = 0;
01052 #endif
01053 
01054 /*
01055  * Many operating systems allow signals to be sent to running
01056  * processes. Some signals have a defined effect on the process, while
01057  * others may be trapped at the code level and acted upon. For
01058  * example, your process may trap the USR1 signal and use it to toggle
01059  * debugging, and may use TERM to initiate a controlled shutdown.
01060  *
01061  *     pid = fork do
01062  *       Signal.trap("USR1") do
01063  *         $debug = !$debug
01064  *         puts "Debug now: #$debug"
01065  *       end
01066  *       Signal.trap("TERM") do
01067  *         puts "Terminating..."
01068  *         shutdown()
01069  *       end
01070  *       # . . . do some work . . .
01071  *     end
01072  *
01073  *     Process.detach(pid)
01074  *
01075  *     # Controlling program:
01076  *     Process.kill("USR1", pid)
01077  *     # ...
01078  *     Process.kill("USR1", pid)
01079  *     # ...
01080  *     Process.kill("TERM", pid)
01081  *
01082  * produces:
01083  *     Debug now: true
01084  *     Debug now: false
01085  *    Terminating...
01086  *
01087  * The list of available signal names and their interpretation is
01088  * system dependent. Signal delivery semantics may also vary between
01089  * systems; in particular signal delivery may not always be reliable.
01090  */
01091 void
01092 Init_signal(void)
01093 {
01094     VALUE mSignal = rb_define_module("Signal");
01095 
01096     rb_define_global_function("trap", sig_trap, -1);
01097     rb_define_module_function(mSignal, "trap", sig_trap, -1);
01098     rb_define_module_function(mSignal, "list", sig_list, 0);
01099 
01100     rb_define_method(rb_eSignal, "initialize", esignal_init, -1);
01101     rb_define_method(rb_eSignal, "signo", esignal_signo, 0);
01102     rb_alias(rb_eSignal, rb_intern("signm"), rb_intern("message"));
01103     rb_define_method(rb_eInterrupt, "initialize", interrupt_init, -1);
01104 
01105     install_sighandler(SIGINT, sighandler);
01106 #ifdef SIGHUP
01107     install_sighandler(SIGHUP, sighandler);
01108 #endif
01109 #ifdef SIGQUIT
01110     install_sighandler(SIGQUIT, sighandler);
01111 #endif
01112 #ifdef SIGTERM
01113     install_sighandler(SIGTERM, sighandler);
01114 #endif
01115 #ifdef SIGALRM
01116     install_sighandler(SIGALRM, sighandler);
01117 #endif
01118 #ifdef SIGUSR1
01119     install_sighandler(SIGUSR1, sighandler);
01120 #endif
01121 #ifdef SIGUSR2
01122     install_sighandler(SIGUSR2, sighandler);
01123 #endif
01124 
01125 #ifdef RUBY_DEBUG_ENV
01126     if (!ruby_enable_coredump)
01127 #endif
01128     {
01129 #ifdef SIGBUS
01130     install_sighandler(SIGBUS, sigbus);
01131 #endif
01132 #ifdef SIGSEGV
01133 # ifdef USE_SIGALTSTACK
01134     rb_register_sigaltstack(GET_THREAD());
01135 # endif
01136     install_sighandler(SIGSEGV, (sighandler_t)sigsegv);
01137 #endif
01138     }
01139 #ifdef SIGPIPE
01140     install_sighandler(SIGPIPE, sigpipe);
01141 #endif
01142 
01143 #if defined(SIGCLD)
01144     init_sigchld(SIGCLD);
01145 #elif defined(SIGCHLD)
01146     init_sigchld(SIGCHLD);
01147 #endif
01148 }
01149 

Generated on Thu Sep 8 2011 03:50:46 for Ruby by  doxygen 1.7.1