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)
395 static rb_atomic_t trap_pending_list
[NSIG
];
397 static char rb_trap_accept_nativethreads
[NSIG
];
399 rb_atomic_t rb_trap_pending
;
400 rb_atomic_t rb_trap_immediate
;
401 int rb_prohibit_interrupt
= 1;
404 rb_get_trap_cmd(int sig
)
406 return trap_list
[sig
].cmd
;
410 rb_gc_mark_trap_list(void)
412 #ifndef MACOS_UNUSE_SIGNAL
415 for (i
=0; i
<NSIG
; i
++) {
416 if (trap_list
[i
].cmd
)
417 rb_gc_mark(trap_list
[i
].cmd
);
419 #endif /* MACOS_UNUSE_SIGNAL */
423 #define sighandler_t sh_t
426 typedef RETSIGTYPE (*sighandler_t
)(int);
430 ruby_signal(int signum
, sighandler_t handler
)
432 struct sigaction sigact
, old
;
435 rb_trap_accept_nativethreads
[signum
] = 0;
438 sigemptyset(&sigact
.sa_mask
);
440 sigact
.sa_sigaction
= (void (*)(int, siginfo_t
*, void*))handler
;
441 sigact
.sa_flags
= SA_SIGINFO
;
443 sigact
.sa_handler
= handler
;
448 if (signum
== SIGCHLD
&& handler
== SIG_IGN
)
449 sigact
.sa_flags
|= SA_NOCLDWAIT
;
451 sigaction(signum
, &sigact
, &old
);
452 return old
.sa_handler
;
456 posix_signal(int signum
, sighandler_t handler
)
458 return ruby_signal(signum
, handler
);
461 #else /* !POSIX_SIGNAL */
462 #define ruby_signal(sig,handler) (/* rb_trap_accept_nativethreads[sig] = 0,*/ signal((sig),(handler)))
463 #if 0 /* def HAVE_NATIVETHREAD */
465 ruby_nativethread_signal(int signum
, sighandler_t handler
)
469 old
= signal(signum
, handler
);
470 rb_trap_accept_nativethreads
[signum
] = 1;
479 rb_vm_t
*vm
= GET_VM(); /* fix me for Multi-VM */
480 ATOMIC_INC(vm
->signal_buff
[sig
]);
481 ATOMIC_INC(vm
->buffered_signal_size
);
483 #if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
484 ruby_signal(sig
, sighandler
);
489 # ifdef HAVE_SIGPROCMASK
490 static sigset_t trap_last_mask
;
492 static int trap_last_mask
;
501 rb_disable_interrupt(void)
506 sigdelset(&mask
, SIGVTALRM
);
507 sigdelset(&mask
, SIGSEGV
);
508 pthread_sigmask(SIG_SETMASK
, &mask
, NULL
);
513 rb_enable_interrupt(void)
518 pthread_sigmask(SIG_SETMASK
, &mask
, NULL
);
523 rb_get_next_signal(rb_vm_t
*vm
)
527 for (i
=1; i
<RUBY_NSIG
; i
++) {
528 if (vm
->signal_buff
[i
] > 0) {
529 rb_disable_interrupt();
531 ATOMIC_DEC(vm
->signal_buff
[i
]);
532 ATOMIC_DEC(vm
->buffered_signal_size
);
534 rb_enable_interrupt();
551 static int segv_received
= 0;
556 fprintf(stderr
, "SEGV recieved in SEGV handler\n");
560 extern int ruby_disable_gc_stress
;
562 ruby_disable_gc_stress
= 1;
563 rb_bug("Segmentation fault");
577 signal_exec(VALUE cmd
, int sig
)
580 VALUE signum
= INT2FIX(sig
);
581 GetProcPtr(cmd
, proc
);
582 vm_invoke_proc(GET_THREAD(), proc
, proc
->block
.self
, 1, &signum
, 0);
588 #ifndef MACOS_UNUSE_SIGNAL
589 if (trap_list
[0].cmd
) {
590 VALUE trap_exit
= trap_list
[0].cmd
;
592 trap_list
[0].cmd
= 0;
593 signal_exec(trap_exit
, 0);
599 rb_signal_exec(rb_thread_t
*th
, int sig
)
601 VALUE cmd
= rb_get_trap_cmd(sig
);
626 rb_thread_signal_raise(th
, sig
);
630 else if (cmd
== Qundef
) {
631 rb_thread_signal_exit(th
);
634 signal_exec(cmd
, sig
);
641 #ifndef MACOS_UNUSE_SIGNAL
644 for (i
=0; i
<NSIG
; i
++) {
645 if (trap_pending_list
[i
]) {
646 trap_pending_list
[i
] = 0;
647 rb_signal_exec(GET_THREAD(), i
);
650 #endif /* MACOS_UNUSE_SIGNAL */
656 # ifdef HAVE_SIGPROCMASK
668 default_handler(int sig
)
722 trap_handler(VALUE
*cmd
, int sig
)
724 sighandler_t func
= wrong_trap
;
731 command
= rb_check_string_type(*cmd
);
732 if (!NIL_P(command
)) {
733 SafeStringValue(command
); /* taint check */
734 switch (RSTRING_LEN(command
)) {
739 if (strncmp(RSTRING_PTR(command
), "SYSTEM_DEFAULT", 14) == 0) {
745 if (strncmp(RSTRING_PTR(command
), "SIG_IGN", 7) == 0) {
750 else if (strncmp(RSTRING_PTR(command
), "SIG_DFL", 7) == 0) {
752 func
= default_handler(sig
);
755 else if (strncmp(RSTRING_PTR(command
), "DEFAULT", 7) == 0) {
760 if (strncmp(RSTRING_PTR(command
), "IGNORE", 6) == 0) {
765 if (strncmp(RSTRING_PTR(command
), "EXIT", 4) == 0) {
771 if (func
== wrong_trap
) {
772 rb_raise(rb_eArgError
, "wrong trap - %s", RSTRING_PTR(command
));
777 GetProcPtr(*cmd
, proc
);
786 trap_signm(VALUE vsig
)
791 switch (TYPE(vsig
)) {
794 if (sig
< 0 || sig
>= NSIG
) {
795 rb_raise(rb_eArgError
, "invalid signal number (%d)", sig
);
800 s
= rb_id2name(SYM2ID(vsig
));
801 if (!s
) rb_raise(rb_eArgError
, "bad signal");
805 s
= StringValuePtr(vsig
);
808 if (strncmp("SIG", s
, 3) == 0)
810 sig
= signm2signo(s
);
811 if (sig
== 0 && strcmp(s
, "EXIT") != 0)
812 rb_raise(rb_eArgError
, "unsupported signal SIG%s", s
);
818 trap(struct trap_arg
*arg
)
820 sighandler_t oldfunc
, func
= arg
->func
;
821 VALUE oldcmd
, command
= arg
->cmd
;
824 oldfunc
= ruby_signal(sig
, func
);
825 oldcmd
= trap_list
[sig
].cmd
;
828 if (oldfunc
== SIG_IGN
) oldcmd
= rb_str_new2("IGNORE");
829 else if (oldfunc
== sighandler
) oldcmd
= rb_str_new2("DEFAULT");
833 oldcmd
= rb_str_new2("EXIT");
837 trap_list
[sig
].cmd
= command
;
838 /* enable at least specified signal. */
840 #ifdef HAVE_SIGPROCMASK
841 sigdelset(&arg
->mask
, sig
);
843 arg
->mask
&= ~sigmask(sig
);
851 trap_ensure(struct trap_arg
*arg
)
853 /* enable interrupt */
854 #ifdef HAVE_SIGPROCMASK
855 sigprocmask(SIG_SETMASK
, &arg
->mask
, NULL
);
857 sigsetmask(arg
->mask
);
859 trap_last_mask
= arg
->mask
;
865 rb_trap_restore_mask(void)
868 # ifdef HAVE_SIGPROCMASK
869 sigprocmask(SIG_SETMASK
, &trap_last_mask
, NULL
);
871 sigsetmask(trap_last_mask
);
878 * Signal.trap( signal, command ) => obj
879 * Signal.trap( signal ) {| | block } => obj
881 * Specifies the handling of signals. The first parameter is a signal
882 * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a
883 * signal number. The characters ``SIG'' may be omitted from the
884 * signal name. The command or block specifies code to be run when the
886 * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal
888 * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler
890 * If the command is ``EXIT'', the script will be terminated by the signal.
891 * If the command is ``SYSTEM_DEFAULT'', the operating system's default
892 * handler will be invoked.
893 * Otherwise, the given command or block will be run.
894 * The special signal name ``EXIT'' or signal number zero will be
895 * invoked just prior to program termination.
896 * trap returns the previous handler for the given signal.
898 * Signal.trap(0, proc { puts "Terminating: #{$$}" })
899 * Signal.trap("CLD") { puts "Child died" }
900 * fork && Process.wait
908 sig_trap(int argc
, VALUE
*argv
)
913 if (argc
== 0 || argc
> 2) {
914 rb_raise(rb_eArgError
, "wrong number of arguments -- trap(sig, cmd)/trap(sig){...}");
917 arg
.sig
= trap_signm(argv
[0]);
919 arg
.cmd
= rb_block_proc();
920 arg
.func
= sighandler
;
922 else if (argc
== 2) {
924 arg
.func
= trap_handler(&arg
.cmd
, arg
.sig
);
927 if (OBJ_TAINTED(arg
.cmd
)) {
928 rb_raise(rb_eSecurityError
, "Insecure: tainted signal trap");
931 /* disable interrupt */
932 # ifdef HAVE_SIGPROCMASK
933 sigfillset(&arg
.mask
);
934 sigprocmask(SIG_BLOCK
, &arg
.mask
, &arg
.mask
);
936 arg
.mask
= sigblock(~0);
939 return rb_ensure(trap
, (VALUE
)&arg
, trap_ensure
, (VALUE
)&arg
);
947 * Signal.list => a_hash
949 * Returns a list of signal names mapped to the corresponding
950 * underlying signal numbers.
952 * 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}
957 VALUE h
= rb_hash_new();
958 const struct signals
*sigs
;
960 for (sigs
= siglist
; sigs
->signm
; sigs
++) {
961 rb_hash_aset(h
, rb_str_new2(sigs
->signm
), INT2FIX(sigs
->signo
));
967 install_sighandler(int signum
, sighandler_t handler
)
971 old
= ruby_signal(signum
, handler
);
972 if (old
!= SIG_DFL
) {
973 ruby_signal(signum
, old
);
977 #if defined(SIGCLD) || defined(SIGCHLD)
979 init_sigchld(int sig
)
981 sighandler_t oldfunc
;
983 # ifdef HAVE_SIGPROCMASK
991 /* disable interrupt */
992 # ifdef HAVE_SIGPROCMASK
994 sigprocmask(SIG_BLOCK
, &mask
, &mask
);
1000 oldfunc
= ruby_signal(sig
, SIG_DFL
);
1001 if (oldfunc
!= SIG_DFL
&& oldfunc
!= SIG_IGN
) {
1002 ruby_signal(sig
, oldfunc
);
1004 trap_list
[sig
].cmd
= 0;
1008 #ifdef HAVE_SIGPROCMASK
1009 sigdelset(&mask
, sig
);
1010 sigprocmask(SIG_SETMASK
, &mask
, NULL
);
1012 mask
&= ~sigmask(sig
);
1015 trap_last_mask
= mask
;
1023 sighandler_t oldfunc
;
1025 oldfunc
= ruby_signal(SIGINT
, SIG_IGN
);
1026 if (oldfunc
== sighandler
) {
1027 ruby_signal(SIGINT
, SIG_DFL
);
1032 #ifdef RUBY_DEBUG_ENV
1033 int ruby_enable_coredump
= 0;
1037 * Many operating systems allow signals to be sent to running
1038 * processes. Some signals have a defined effect on the process, while
1039 * others may be trapped at the code level and acted upon. For
1040 * example, your process may trap the USR1 signal and use it to toggle
1041 * debugging, and may use TERM to initiate a controlled shutdown.
1044 * Signal.trap("USR1") do
1046 * puts "Debug now: #$debug"
1048 * Signal.trap("TERM") do
1049 * puts "Terminating..."
1052 * # . . . do some work . . .
1055 * Process.detach(pid)
1057 * # Controlling program:
1058 * Process.kill("USR1", pid)
1060 * Process.kill("USR1", pid)
1062 * Process.kill("TERM", pid)
1069 * The list of available signal names and their interpretation is
1070 * system dependent. Signal delivery semantics may also vary between
1071 * systems; in particular signal delivery may not always be reliable.
1076 #ifndef MACOS_UNUSE_SIGNAL
1077 VALUE mSignal
= rb_define_module("Signal");
1079 rb_define_global_function("trap", sig_trap
, -1);
1080 rb_define_module_function(mSignal
, "trap", sig_trap
, -1);
1081 rb_define_module_function(mSignal
, "list", sig_list
, 0);
1083 rb_define_method(rb_eSignal
, "initialize", esignal_init
, -1);
1084 rb_define_method(rb_eSignal
, "signo", esignal_signo
, 0);
1085 rb_alias(rb_eSignal
, rb_intern("signm"), rb_intern("message"));
1086 rb_define_method(rb_eInterrupt
, "initialize", interrupt_init
, -1);
1088 install_sighandler(SIGINT
, sighandler
);
1090 install_sighandler(SIGHUP
, sighandler
);
1093 install_sighandler(SIGQUIT
, sighandler
);
1096 install_sighandler(SIGTERM
, sighandler
);
1099 install_sighandler(SIGALRM
, sighandler
);
1102 install_sighandler(SIGUSR1
, sighandler
);
1105 install_sighandler(SIGUSR2
, sighandler
);
1108 #ifdef RUBY_DEBUG_ENV
1109 if (!ruby_enable_coredump
)
1113 install_sighandler(SIGBUS
, sigbus
);
1116 install_sighandler(SIGSEGV
, sigsegv
);
1120 install_sighandler(SIGPIPE
, sigpipe
);
1124 init_sigchld(SIGCLD
);
1125 #elif defined(SIGCHLD)
1126 init_sigchld(SIGCHLD
);
1129 #endif /* MACOS_UNUSE_SIGNAL */