/* * call-seq: * Signal.trap( signal, command ) -> obj * Signal.trap( signal ) {| | block } -> obj * * Specifies the handling of signals. The first parameter is a signal * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a * signal number. The characters ``SIG'' may be omitted from the * signal name. The command or block specifies code to be run when the * signal is raised. * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal * will be ignored. * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler * will be invoked. * If the command is ``EXIT'', the script will be terminated by the signal. * If the command is ``SYSTEM_DEFAULT'', the operating system's default * handler will be invoked. * Otherwise, the given command or block will be run. * The special signal name ``EXIT'' or signal number zero will be * invoked just prior to program termination. * trap returns the previous handler for the given signal. * * Signal.trap(0, proc { puts "Terminating: #{$$}" }) * Signal.trap("CLD") { puts "Child died" } * fork && Process.wait * * produces: * Terminating: 27461 * Child died * Terminating: 27460 */ static VALUE sig_trap(int argc, VALUE *argv) { int sig; sighandler_t func; VALUE cmd; rb_secure(2); rb_check_arity(argc, 1, 2); sig = trap_signm(argv[0]); if (reserved_signal_p(sig)) { const char *name = signo2signm(sig); if (name) rb_raise(rb_eArgError, "can't trap reserved signal: SIG%s", name); else rb_raise(rb_eArgError, "can't trap reserved signal: %d", sig); } if (argc == 1) { cmd = rb_block_proc(); func = sighandler; } else { cmd = argv[1]; func = trap_handler(&cmd, sig); } if (OBJ_TAINTED(cmd)) { rb_raise(rb_eSecurityError, "Insecure: tainted signal trap"); } return trap(sig, func, cmd); }
static VALUE rb_signo2signm(int signo) { const char *const signm = signo2signm(signo); if (signm) { return rb_sprintf("SIG%s", signm); } else { return rb_sprintf("SIG%u", signo); } }
/* * call-seq: * Signal.signame(signo) -> string or nil * * Convert signal number to signal name. * Returns +nil+ if the signo is an invalid signal number. * * Signal.trap("INT") { |signo| puts Signal.signame(signo) } * Process.kill("INT", 0) * * <em>produces:</em> * * INT */ static mrb_value signal_signame(mrb_state *mrb, mrb_value mod) { mrb_int signo; const char *signame; mrb_get_args(mrb, "i", &signo); signame = signo2signm(signo); if (signame) return mrb_str_new_cstr(mrb, signame); else return mrb_nil_value(); }
static VALUE esignal_init(int argc, VALUE *argv, VALUE self) { int argnum = 1; VALUE sig = Qnil; int signo; const char *signm; if (argc > 0) { sig = rb_check_to_integer(argv[0], "to_int"); if (!NIL_P(sig)) argnum = 2; } if (argc < 1 || argnum < argc) { rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, argnum); } if (argnum == 2) { signo = NUM2INT(sig); if (signo < 0 || signo > NSIG) { rb_raise(rb_eArgError, "invalid signal number (%d)", signo); } if (argc > 1) { sig = argv[1]; } else { signm = signo2signm(signo); if (signm) { sig = rb_sprintf("SIG%s", signm); } else { sig = rb_sprintf("SIG%u", signo); } } } else { signm = SYMBOL_P(sig) ? rb_id2name(SYM2ID(sig)) : StringValuePtr(sig); if (strncmp(signm, "SIG", 3) == 0) signm += 3; signo = signm2signo(signm); if (!signo) { rb_raise(rb_eArgError, "unsupported name `SIG%s'", signm); } if (SYMBOL_P(sig)) { sig = rb_str_new2(signm); } } rb_call_super(1, &sig); rb_iv_set(self, "signo", INT2NUM(signo)); return self; }
static mrb_value trap(mrb_state *mrb, mrb_value mod, int sig, sighandler_t func, mrb_value command) { sighandler_t oldfunc; mrb_value oldcmd; mrb_value trap_list; mrb_sym id_trap_list; if (sig == 0) { /* EXIT */ oldfunc = SIG_ERR; } else { oldfunc = mrb_signal(mrb, sig, func); if (oldfunc == SIG_ERR) mrb_sys_fail(mrb, signo2signm(sig)); } id_trap_list = mrb_intern_lit(mrb, "trap_list"); trap_list = mrb_iv_get(mrb, mod, id_trap_list); oldcmd = mrb_ary_ref(mrb, trap_list, (mrb_int)sig); if (mrb_nil_p(oldcmd)) { if (oldfunc == sighandler) oldcmd = mrb_str_new_cstr(mrb, "DEFAULT"); else oldcmd = mrb_nil_value(); } else if (mrb_type(oldcmd) == MRB_TT_TRUE) { if (oldfunc == SIG_IGN) oldcmd = mrb_str_new_cstr(mrb, "IGNORE"); else if (oldfunc == SIG_DFL) oldcmd = mrb_str_new_cstr(mrb, "SYSTEM_DEFAULT"); else if (oldfunc == sighandler) oldcmd = mrb_str_new_cstr(mrb, "DEFAULT"); else oldcmd = mrb_nil_value(); } else if (mrb_undef_p(oldcmd)) { oldcmd = mrb_str_new_cstr(mrb, "EXIT"); } mrb_ary_set(mrb, trap_list, (mrb_int)sig, command); return oldcmd; }
/* * call-seq: * Signal.trap( signal, command ) -> obj * Signal.trap( signal ) {| | block } -> obj * * Specifies the handling of signals. The first parameter is a signal * name (a string such as ``SIGALRM'', ``SIGUSR1'', and so on) or a * signal number. The characters ``SIG'' may be omitted from the * signal name. The command or block specifies code to be run when the * signal is raised. * If the command is the string ``IGNORE'' or ``SIG_IGN'', the signal * will be ignored. * If the command is ``DEFAULT'' or ``SIG_DFL'', the Ruby's default handler * will be invoked. * If the command is ``EXIT'', the script will be terminated by the signal. * If the command is ``SYSTEM_DEFAULT'', the operating system's default * handler will be invoked. * Otherwise, the given command or block will be run. * The special signal name ``EXIT'' or signal number zero will be * invoked just prior to program termination. * trap returns the previous handler for the given signal. * * Signal.trap(0, proc { puts "Terminating: #{$$}" }) * Signal.trap("CLD") { puts "Child died" } * fork && Process.wait * * produces: * Terminating: 27461 * Child died * Terminating: 27460 */ static VALUE sig_trap(int argc, VALUE *argv) { struct trap_arg arg; rb_secure(2); rb_check_arity(argc, 1, 2); arg.sig = trap_signm(argv[0]); if (reserved_signal_p(arg.sig)) { const char *name = signo2signm(arg.sig); if (name) rb_raise(rb_eArgError, "can't trap reserved signal: SIG%s", name); else rb_raise(rb_eArgError, "can't trap reserved signal: %d", (int)arg.sig); } if (argc == 1) { arg.cmd = rb_block_proc(); arg.func = sighandler; } else { arg.cmd = argv[1]; arg.func = trap_handler(&arg.cmd, arg.sig); } if (OBJ_TAINTED(arg.cmd)) { rb_raise(rb_eSecurityError, "Insecure: tainted signal trap"); } #if USE_TRAP_MASK { sigset_t fullmask; /* disable interrupt */ sigfillset(&fullmask); pthread_sigmask(SIG_BLOCK, &fullmask, &arg.mask); return rb_ensure(trap, (VALUE)&arg, trap_ensure, (VALUE)&arg); } #else return trap(&arg); #endif }
void rb_signal_exec(rb_thread_t *th, int sig) { VALUE cmd = rb_get_trap_cmd(sig); if (cmd == 0) { switch (sig) { case SIGINT: rb_interrupt(); break; #ifdef SIGHUP case SIGHUP: #endif #ifdef SIGQUIT case SIGQUIT: #endif #ifdef SIGALRM case SIGALRM: #endif #ifdef SIGUSR1 case SIGUSR1: #endif #ifdef SIGUSR2 case SIGUSR2: #endif rb_thread_signal_raise(th, signo2signm(sig)); break; } } else if (cmd == Qundef) { rb_thread_signal_exit(th); } else { rb_proc_t *proc; VALUE signum = INT2FIX(sig); GetProcPtr(cmd, proc); th_invoke_proc(th, proc, proc->block.self, 1, &signum); } }
const char * ruby_signal_name(int no) { return signo2signm(no); }
/* * call-seq: * Signal.signame(signo) -> string * * convert signal number to signal name * * Signal.trap("INT") { |signo| puts Signal.signame(signo) } * Process.kill("INT", 0) * * <em>produces:</em> * * INT */ static VALUE sig_signame(VALUE recv, VALUE signo) { const char *signame = signo2signm(NUM2INT(signo)); return rb_str_new_cstr(signame); }