1 /**********************************************************************
6 created at: Tue Dec 20 10:13:44 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
12 **********************************************************************/
14 #include "ruby/ruby.h"
15 #include "ruby/signal.h"
16 #include "ruby/node.h"
25 #if defined HAVE_SIGPROCMASK || defined HAVE_SIGSETMASK
26 #define USE_TRAP_MASK 1
28 #define USE_TRAP_MASK 0
35 # define NSIG (_SIGMAX + 1) /* For QNX */
39 static const struct signals
{
128 {"VTALRM", SIGVTALRM
},
155 {"DANGER", SIGDANGER
},
158 {"MIGRATE", SIGMIGRATE
},
167 {"RETRACT", SIGRETRACT
},
179 signm2signo(const char *nm
)
181 const struct signals
*sigs
;
183 for (sigs
= siglist
; sigs
->signm
; sigs
++)
184 if (strcmp(sigs
->signm
, nm
) == 0)
192 const struct signals
*sigs
;
194 for (sigs
= siglist
; sigs
->signm
; sigs
++)
195 if (sigs
->signo
== no
)
201 ruby_signal_name(int no
)
203 return signo2signm(no
);
208 * SignalException.new(sig) => signal_exception
210 * Construct a new SignalException object. +sig+ should be a known
211 * signal name, or a signal number.
215 esignal_init(int argc
, VALUE
*argv
, VALUE self
)
223 sig
= rb_check_to_integer(argv
[0], "to_int");
224 if (!NIL_P(sig
)) argnum
= 2;
227 if (argc
< 1 || argnum
< argc
) {
228 rb_raise(rb_eArgError
, "wrong number of arguments (%d for %d)",
232 signo
= NUM2INT(sig
);
233 if (signo
< 0 || signo
> NSIG
) {
234 rb_raise(rb_eArgError
, "invalid signal number (%d)", signo
);
240 signm
= signo2signm(signo
);
242 sig
= rb_sprintf("SIG%s", signm
);
245 sig
= rb_sprintf("SIG%u", signo
);
250 signm
= SYMBOL_P(sig
) ? rb_id2name(SYM2ID(sig
)) : StringValuePtr(sig
);
251 if (strncmp(signm
, "SIG", 3) == 0) signm
+= 3;
252 signo
= signm2signo(signm
);
254 rb_raise(rb_eArgError
, "unsupported name `SIG%s'", signm
);
256 sig
= rb_sprintf("SIG%s", signm
);
258 rb_call_super(1, &sig
);
259 rb_iv_set(self
, "signo", INT2NUM(signo
));
266 * signal_exception.signo => num
268 * Returns a signal number.
272 esignal_signo(VALUE self
)
274 return rb_iv_get(self
, "signo");
278 interrupt_init(int argc
, VALUE
*argv
, VALUE self
)
282 args
[0] = INT2FIX(SIGINT
);
283 rb_scan_args(argc
, argv
, "01", &args
[1]);
284 return rb_call_super(2, args
);
288 ruby_default_signal(int sig
)
290 #ifndef MACOS_UNUSE_SIGNAL
291 signal(sig
, SIG_DFL
);
298 * Process.kill(signal, pid, ...) => fixnum
300 * Sends the given signal to the specified process id(s), or to the
301 * current process if _pid_ is zero. _signal_ may be an
302 * integer signal number or a POSIX signal name (either with or without
303 * a +SIG+ prefix). If _signal_ is negative (or starts
304 * with a minus sign), kills process groups instead of
305 * processes. Not all signals are available on all platforms.
308 * Signal.trap("HUP") { puts "Ouch!"; exit }
309 * # ... do some work ...
312 * Process.kill("HUP", pid)
321 rb_f_kill(int argc
, VALUE
*argv
)
324 #define killpg(pg, sig) kill(-(pg), sig)
333 rb_raise(rb_eArgError
, "wrong number of arguments -- kill(sig, pid...)");
334 switch (TYPE(argv
[0])) {
336 sig
= FIX2INT(argv
[0]);
340 s
= rb_id2name(SYM2ID(argv
[0]));
341 if (!s
) rb_raise(rb_eArgError
, "bad signal");
345 s
= RSTRING_PTR(argv
[0]);
351 if (strncmp("SIG", s
, 3) == 0)
353 if((sig
= signm2signo(s
)) == 0)
354 rb_raise(rb_eArgError
, "unsupported name `SIG%s'", s
);
364 str
= rb_check_string_type(argv
[0]);
366 s
= RSTRING_PTR(str
);
369 rb_raise(rb_eArgError
, "bad signal type %s",
370 rb_obj_classname(argv
[0]));
377 for (i
=1; i
<argc
; i
++) {
378 if (killpg(NUM2PIDT(argv
[i
]), sig
) < 0)
383 for (i
=1; i
<argc
; i
++) {
384 if (kill(NUM2PIDT(argv
[i
]), sig
) < 0)
396 static rb_atomic_t trap_pending_list
[NSIG
];
398 static char rb_trap_accept_nativethreads
[NSIG
];
400 rb_atomic_t rb_trap_pending
;
401 rb_atomic_t rb_trap_immediate
;
402 int rb_prohibit_interrupt
= 1;
405 rb_get_trap_cmd(int sig
)
407 return trap_list
[sig
].cmd
;
411 rb_gc_mark_trap_list(void)
413 #ifndef MACOS_UNUSE_SIGNAL
416 for (i
=0; i
<NSIG
; i
++) {
417 if (trap_list
[i
].cmd
)
418 rb_gc_mark(trap_list
[i
].cmd
);
420 #endif /* MACOS_UNUSE_SIGNAL */
424 #define sighandler_t sh_t
427 typedef RETSIGTYPE (*sighandler_t
)(int);
431 ruby_signal(int signum
, sighandler_t handler
)
433 struct sigaction sigact
, old
;
436 rb_trap_accept_nativethreads
[signum
] = 0;
439 sigemptyset(&sigact
.sa_mask
);
441 sigact
.sa_sigaction
= (void (*)(int, siginfo_t
*, void*))handler
;
442 sigact
.sa_flags
= SA_SIGINFO
;
444 sigact
.sa_handler
= handler
;
449 if (signum
== SIGCHLD
&& handler
== SIG_IGN
)
450 sigact
.sa_flags
|= SA_NOCLDWAIT
;
452 sigaction(signum
, &sigact
, &old
);
453 return old
.sa_handler
;
457 posix_signal(int signum
, sighandler_t handler
)
459 return ruby_signal(signum
, handler
);
462 #else /* !POSIX_SIGNAL */
463 #define ruby_signal(sig,handler) (/* rb_trap_accept_nativethreads[sig] = 0,*/ signal((sig),(handler)))
464 #if 0 /* def HAVE_NATIVETHREAD */
466 ruby_nativethread_signal(int signum
, sighandler_t handler
)
470 old
= signal(signum
, handler
);
471 rb_trap_accept_nativethreads
[signum
] = 1;
480 rb_vm_t
*vm
= GET_VM(); /* fix me for Multi-VM */
481 ATOMIC_INC(vm
->signal_buff
[sig
]);
482 ATOMIC_INC(vm
->buffered_signal_size
);
484 #if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
485 ruby_signal(sig
, sighandler
);
490 # ifdef HAVE_SIGPROCMASK
491 static sigset_t trap_last_mask
;
493 static int trap_last_mask
;
502 rb_disable_interrupt(void)
507 sigdelset(&mask
, SIGVTALRM
);
508 sigdelset(&mask
, SIGSEGV
);
509 pthread_sigmask(SIG_SETMASK
, &mask
, NULL
);
514 rb_enable_interrupt(void)
519 pthread_sigmask(SIG_SETMASK
, &mask
, NULL
);
524 rb_get_next_signal(rb_vm_t
*vm
)
528 for (i
=1; i
<RUBY_NSIG
; i
++) {
529 if (vm
->signal_buff
[i
] > 0) {
530 rb_disable_interrupt();
532 ATOMIC_DEC(vm
->signal_buff
[i
]);
533 ATOMIC_DEC(vm
->buffered_signal_size
);
535 rb_enable_interrupt();
552 static int segv_received
= 0;
557 fprintf(stderr
, "SEGV recieved in SEGV handler\n");
561 extern int ruby_disable_gc_stress
;
563 ruby_disable_gc_stress
= 1;
564 rb_bug("Segmentation fault");
578 signal_exec(VALUE cmd
, int sig
)
581 VALUE signum
= INT2FIX(sig
);
583 if (TYPE(cmd
) == T_STRING
) {
584 rb_eval_cmd(cmd
, rb_ary_new3(1, signum
), trap_list
[sig
].safe
);
587 GetProcPtr(cmd
, proc
);
588 vm_invoke_proc(GET_THREAD(), proc
, proc
->block
.self
, 1, &signum
, 0);
594 #ifndef MACOS_UNUSE_SIGNAL
595 if (trap_list
[0].cmd
) {
596 VALUE trap_exit
= trap_list
[0].cmd
;
598 trap_list
[0].cmd
= 0;
599 signal_exec(trap_exit
, 0);
605 rb_signal_exec(rb_thread_t
*th
, int sig
)
607 VALUE cmd
= rb_get_trap_cmd(sig
);
632 rb_thread_signal_raise(th
, sig
);
636 else if (cmd
== Qundef
) {
637 rb_thread_signal_exit(th
);
640 signal_exec(cmd
, sig
);
647 #ifndef MACOS_UNUSE_SIGNAL
650 for (i
=0; i
<NSIG
; i
++) {
651 if (trap_pending_list
[i
]) {
652 trap_pending_list
[i
] = 0;
653 rb_signal_exec(GET_THREAD(), i
);
656 #endif /* MACOS_UNUSE_SIGNAL */
662 # ifdef HAVE_SIGPROCMASK
674 default_handler(int sig
)
723 trap_handler(VALUE
*cmd
, int sig
)
725 sighandler_t func
= sighandler
;
732 command
= rb_check_string_type(*cmd
);
733 if (!NIL_P(command
)) {
734 SafeStringValue(command
); /* taint check */
736 switch (RSTRING_LEN(command
)) {
741 if (strncmp(RSTRING_PTR(command
), "SYSTEM_DEFAULT", 14) == 0) {
747 if (strncmp(RSTRING_PTR(command
), "SIG_IGN", 7) == 0) {
752 else if (strncmp(RSTRING_PTR(command
), "SIG_DFL", 7) == 0) {
754 func
= default_handler(sig
);
757 else if (strncmp(RSTRING_PTR(command
), "DEFAULT", 7) == 0) {
762 if (strncmp(RSTRING_PTR(command
), "IGNORE", 6) == 0) {
767 if (strncmp(RSTRING_PTR(command
), "EXIT", 4) == 0) {
775 GetProcPtr(*cmd
, proc
);
783 trap_signm(VALUE vsig
)
788 switch (TYPE(vsig
)) {
791 if (sig
< 0 || sig
>= NSIG
) {
792 rb_raise(rb_eArgError
, "invalid signal number (%d)", sig
);
797 s
= rb_id2name(SYM2ID(vsig
));
798 if (!s
) rb_raise(rb_eArgError
, "bad signal");
802 s
= StringValuePtr(vsig
);
805 if (strncmp("SIG", s
, 3) == 0)
807 sig
= signm2signo(s
);
808 if (sig
== 0 && strcmp(s
, "EXIT") != 0)
809 rb_raise(rb_eArgError
, "unsupported signal SIG%s", s
);
815 trap(struct trap_arg
*arg
)
817 sighandler_t oldfunc
, func
= arg
->func
;
818 VALUE oldcmd
, command
= arg
->cmd
;
821 oldfunc
= ruby_signal(sig
, func
);
822 oldcmd
= trap_list
[sig
].cmd
;
825 if (oldfunc
== SIG_IGN
) oldcmd
= rb_str_new2("IGNORE");
826 else if (oldfunc
== sighandler
) oldcmd
= rb_str_new2("DEFAULT");
830 oldcmd
= rb_str_new2("EXIT");
834 trap_list
[sig
].cmd
= command
;
835 trap_list
[sig
].safe
= rb_safe_level();
836 /* enable at least specified signal. */
838 #ifdef HAVE_SIGPROCMASK
839 sigdelset(&arg
->mask
, sig
);
841 arg
->mask
&= ~sigmask(sig
);
849 trap_ensure(struct trap_arg
*arg
)
851 /* enable interrupt */
852 #ifdef HAVE_SIGPROCMASK
853 sigprocmask(SIG_SETMASK
, &arg
->mask
, NULL
);
855 sigsetmask(arg
->mask
);
857 trap_last_mask
= arg
->mask
;
863 rb_trap_restore_mask(void)
866 # ifdef HAVE_SIGPROCMASK
867 sigprocmask(SIG_SETMASK
, &trap_last_mask
, NULL
);
869 sigsetmask(trap_last_mask
);
876 * Signal.trap( signal, command ) => obj
877 * Signal.trap( signal ) {| | block } => obj
879 * Specifies the handling of signals. The first parameter is a signal
880 * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a
881 * signal number. The characters ``SIG'' may be omitted from the
882 * signal name. The command or block specifies code to be run when the
884 * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal
886 * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler
888 * If the command is ``EXIT'', the script will be terminated by the signal.
889 * If the command is ``SYSTEM_DEFAULT'', the operating system's default
890 * handler will be invoked.
891 * Otherwise, the given command or block will be run.
892 * The special signal name ``EXIT'' or signal number zero will be
893 * invoked just prior to program termination.
894 * trap returns the previous handler for the given signal.
896 * Signal.trap(0, proc { puts "Terminating: #{$$}" })
897 * Signal.trap("CLD") { puts "Child died" }
898 * fork && Process.wait
906 sig_trap(int argc
, VALUE
*argv
)
911 if (argc
== 0 || argc
> 2) {
912 rb_raise(rb_eArgError
, "wrong number of arguments -- trap(sig, cmd)/trap(sig){...}");
915 arg
.sig
= trap_signm(argv
[0]);
917 arg
.cmd
= rb_block_proc();
918 arg
.func
= sighandler
;
920 else if (argc
== 2) {
922 arg
.func
= trap_handler(&arg
.cmd
, arg
.sig
);
925 if (OBJ_TAINTED(arg
.cmd
)) {
926 rb_raise(rb_eSecurityError
, "Insecure: tainted signal trap");
929 /* disable interrupt */
930 # ifdef HAVE_SIGPROCMASK
931 sigfillset(&arg
.mask
);
932 sigprocmask(SIG_BLOCK
, &arg
.mask
, &arg
.mask
);
934 arg
.mask
= sigblock(~0);
937 return rb_ensure(trap
, (VALUE
)&arg
, trap_ensure
, (VALUE
)&arg
);
945 * Signal.list => a_hash
947 * Returns a list of signal names mapped to the corresponding
948 * underlying signal numbers.
950 * 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}
955 VALUE h
= rb_hash_new();
956 const struct signals
*sigs
;
958 for (sigs
= siglist
; sigs
->signm
; sigs
++) {
959 rb_hash_aset(h
, rb_str_new2(sigs
->signm
), INT2FIX(sigs
->signo
));
965 install_sighandler(int signum
, sighandler_t handler
)
969 old
= ruby_signal(signum
, handler
);
970 if (old
!= SIG_DFL
) {
971 ruby_signal(signum
, old
);
975 #if defined(SIGCLD) || defined(SIGCHLD)
977 init_sigchld(int sig
)
979 sighandler_t oldfunc
;
981 # ifdef HAVE_SIGPROCMASK
989 /* disable interrupt */
990 # ifdef HAVE_SIGPROCMASK
992 sigprocmask(SIG_BLOCK
, &mask
, &mask
);
998 oldfunc
= ruby_signal(sig
, SIG_DFL
);
999 if (oldfunc
!= SIG_DFL
&& oldfunc
!= SIG_IGN
) {
1000 ruby_signal(sig
, oldfunc
);
1002 trap_list
[sig
].cmd
= 0;
1006 #ifdef HAVE_SIGPROCMASK
1007 sigdelset(&mask
, sig
);
1008 sigprocmask(SIG_SETMASK
, &mask
, NULL
);
1010 mask
&= ~sigmask(sig
);
1013 trap_last_mask
= mask
;
1021 sighandler_t oldfunc
;
1023 oldfunc
= ruby_signal(SIGINT
, SIG_IGN
);
1024 if (oldfunc
== sighandler
) {
1025 ruby_signal(SIGINT
, SIG_DFL
);
1030 #ifdef RUBY_DEBUG_ENV
1031 int ruby_enable_coredump
= 0;
1035 * Many operating systems allow signals to be sent to running
1036 * processes. Some signals have a defined effect on the process, while
1037 * others may be trapped at the code level and acted upon. For
1038 * example, your process may trap the USR1 signal and use it to toggle
1039 * debugging, and may use TERM to initiate a controlled shutdown.
1042 * Signal.trap("USR1") do
1044 * puts "Debug now: #$debug"
1046 * Signal.trap("TERM") do
1047 * puts "Terminating..."
1050 * # . . . do some work . . .
1053 * Process.detach(pid)
1055 * # Controlling program:
1056 * Process.kill("USR1", pid)
1058 * Process.kill("USR1", pid)
1060 * Process.kill("TERM", pid)
1067 * The list of available signal names and their interpretation is
1068 * system dependent. Signal delivery semantics may also vary between
1069 * systems; in particular signal delivery may not always be reliable.
1074 #ifndef MACOS_UNUSE_SIGNAL
1075 VALUE mSignal
= rb_define_module("Signal");
1077 rb_define_global_function("trap", sig_trap
, -1);
1078 rb_define_module_function(mSignal
, "trap", sig_trap
, -1);
1079 rb_define_module_function(mSignal
, "list", sig_list
, 0);
1081 rb_define_method(rb_eSignal
, "initialize", esignal_init
, -1);
1082 rb_define_method(rb_eSignal
, "signo", esignal_signo
, 0);
1083 rb_alias(rb_eSignal
, rb_intern("signm"), rb_intern("message"));
1084 rb_define_method(rb_eInterrupt
, "initialize", interrupt_init
, -1);
1086 install_sighandler(SIGINT
, sighandler
);
1088 install_sighandler(SIGHUP
, sighandler
);
1091 install_sighandler(SIGQUIT
, sighandler
);
1094 install_sighandler(SIGTERM
, sighandler
);
1097 install_sighandler(SIGALRM
, sighandler
);
1100 install_sighandler(SIGUSR1
, sighandler
);
1103 install_sighandler(SIGUSR2
, sighandler
);
1106 #ifdef RUBY_DEBUG_ENV
1107 if (!ruby_enable_coredump
)
1111 install_sighandler(SIGBUS
, sigbus
);
1114 install_sighandler(SIGSEGV
, sigsegv
);
1118 install_sighandler(SIGPIPE
, sigpipe
);
1122 init_sigchld(SIGCLD
);
1123 #elif defined(SIGCHLD)
1124 init_sigchld(SIGCHLD
);
1127 #endif /* MACOS_UNUSE_SIGNAL */