Trap in 1.9

e$B$J$+$@$G$9!#e(B

[ruby-dev:30820]e$B$r;n$7$F$$$F5$$E$$$?$N$G$9$,!"e(B1.9e$B$G0J2<$N%3!<%Ie(B
e$B$,e(BSEGVe$B$7$^$9!#e(BQundefe$B$rJV$7$F$$$k$h$&$G$9!#e(B

p trap(:INT, trap(:INT, “EXIT”))

e$B$^$?!"e(Btrap(:EXIT)e$B$@$1$OG$0U$NJ8;zNs$rEO$;$k$^$^$K$J$C$F$$$^$9$,!"e(B
e$B$d$O$je(BSEGVe$B$7$^$9!#e(B

trap(:EXIT, “p”)

e$B$D$$$G$K!"0z?t$N%A%’%C%/$r@h$K:Q$^$9$h$&$K$7$F$_$^$7$?!#e(B

Index: signal.c

— signal.c (revision 12396)
+++ signal.c (working copy)
@@ -375,5 +375,4 @@ rb_f_kill(int argc, VALUE *argv)
static struct {
VALUE cmd;

  • int safe;
    } trap_list[NSIG];
    static rb_atomic_t trap_pending_list[NSIG];
    @@ -545,4 +544,13 @@ sigpipe(int sig)
    #endif

+static void
+signal_exec(VALUE cmd, int sig)
+{

  • rb_proc_t *proc;
  • VALUE signum = INT2FIX(sig);
  • GetProcPtr(cmd, proc);
  • th_invoke_proc(GET_THREAD(), proc, proc->block.self, 1, &signum);
    +}

void
rb_trap_exit(void)
@@ -553,5 +561,5 @@ rb_trap_exit(void)

trap_list[0].cmd = 0;

  • rb_eval_cmd(trap_exit, rb_ary_new3(1, INT2FIX(0)),
    trap_list[0].safe);
  • signal_exec(trap_exit, 0);
    }
    #endif
    @@ -594,8 +602,5 @@ rb_signal_exec(rb_thread_t *th, int sig)
    }
    else {
  • rb_proc_t *proc;
  • VALUE signum = INT2FIX(sig);
  • GetProcPtr(cmd, proc);
  • th_invoke_proc(th, proc, proc->block.self, 1, &signum);
  • signal_exec(cmd, sig);
    }
    }
    @@ -625,21 +630,20 @@ struct trap_arg {

endif

#endif

  • VALUE sig, cmd;
  • int sig;
  • sighandler_t func;
  • VALUE cmd;
    };

-static VALUE
-trap(struct trap_arg *arg)
+static sighandler_t
+trap_handler(VALUE *cmd)
{

  • sighandler_t func, oldfunc;
  • VALUE command, oldcmd;
  • int sig = -1;
  • const char *s;
  • sighandler_t func = 0;
  • VALUE command;
  • func = sighandler;
  • if (NIL_P(arg->cmd)) {
  • if (NIL_P(*cmd)) {
    func = SIG_IGN;
    }
    else {
  • command = rb_check_string_type(arg->cmd);
  • command = rb_check_string_type(cmd);
    if (!NIL_P(command)) {
    SafeStringValue(command); /
    taint check */
    @@ -666,29 +670,47 @@ trap(struct trap_arg *arg)
    case 4:
    if (strncmp(RSTRING_PTR(command), “EXIT”, 4) == 0) {
  •    arg->cmd = Qundef;
    
  •    func = sighandler;
    
  •    *cmd = Qundef;
    
    }
    break;
    }
  •  if (!func) {
    
  • rb_raise(rb_eArgError, “wrong trap - %s”, RSTRING_PTR(command));
  •  }
    
  • }
  • else {
  •  rb_proc_t *proc;
    
  •  GetProcPtr(*cmd, proc);
    
  •  func = sighandler;
    
    }
    }
    if (func == SIG_IGN || func == SIG_DFL) {
  • command = 0;
  • }
  • else {
  • command = arg->cmd;
  • *cmd = 0;
    }
  • switch (TYPE(arg->sig)) {
  • return func;
    +}

+static int
+trap_signm(VALUE vsig)
+{

  • int sig = -1;
  • const char *s;
  • switch (TYPE(vsig)) {
    case T_FIXNUM:
  • sig = FIX2INT(arg->sig);
  • sig = FIX2INT(vsig);

  • if (sig < 0 || sig >= NSIG) {

  •  rb_raise(rb_eArgError, "invalid signal number (%d)", sig);
    
  • }
    break;

    case T_SYMBOL:
    
  • s = rb_id2name(SYM2ID(arg->sig));
  • s = rb_id2name(SYM2ID(vsig));
    if (!s) rb_raise(rb_eArgError, “bad signal”);
    goto str_signal;
  •  case T_STRING:
    
  • s = RSTRING_PTR(arg->sig);
  •  default:
    
  • s = StringValuePtr(vsig);

    str_signal:
    

@@ -700,7 +722,4 @@ trap(struct trap_arg *arg)
}

  • if (sig < 0 || sig >= NSIG) {
  • rb_raise(rb_eArgError, “invalid signal number (%d)”, sig);
  • }
    #if defined(HAVE_SETITIMER)
    if (sig == SIGVTALRM) {
    @@ -708,4 +727,10 @@ trap(struct trap_arg *arg)
    }
    #endif
  • return sig;
    +}

+static sighandler_t
+default_handler(sighandler_t func, int sig)
+{
if (func == SIG_DFL) {
switch (sig) {
@@ -748,14 +773,29 @@ trap(struct trap_arg *arg)
}
}
+

  • return func;
    +}

+static VALUE
+trap(struct trap_arg *arg)
+{

  • sighandler_t oldfunc, func = arg->func;
  • VALUE oldcmd, command = arg->cmd;
  • int sig = arg->sig;
  • oldfunc = ruby_signal(sig, func);
    oldcmd = trap_list[sig].cmd;
  • if (!oldcmd) {
  • switch (oldcmd) {

  •  case 0:
    

    if (oldfunc == SIG_IGN) oldcmd = rb_str_new2(“IGNORE”);
    else if (oldfunc == sighandler) oldcmd = rb_str_new2(“DEFAULT”);
    else oldcmd = Qnil;

  • break;

  •  case Qundef:
    
  • oldcmd = rb_str_new2(“EXIT”);

  • break;
    }

    trap_list[sig].cmd = command;

  • trap_list[sig].safe = rb_safe_level();
    /* enable at least specified signal. */
    #ifndef _WIN32
    @@ -834,10 +874,12 @@ sig_trap(int argc, VALUE *argv)
    }

  • arg.sig = argv[0];

  • arg.sig = trap_signm(argv[0]);
    if (argc == 1) {
    arg.cmd = rb_block_proc();
  • arg.func = sighandler;
    }
    else if (argc == 2) {
    arg.cmd = argv[1];
  • arg.func = default_handler(trap_handler(&arg.cmd), arg.sig);
    }