From: Nobuyoshi Nakada Date: 2007-03-10T06:36:27+09:00 Subject: [ruby-dev:30520] Re: [BUG?] SIGTERM の取り扱い なかだです。 ChangeLogエントリをつけてませんでした。 * eval.c (error_handle): no message when exiting by signal. * eval.c (ruby_cleanup): re-send signal. [ruby-dev:30516] * eval.c (rb_thread_interrupt): instantiate SignalException. * eval.c (rb_thread_signal_raise): now takes signal number instead of signal name. * intern.h (rb_thread_signal_raise, ruby_default_signal): prototypes. * signal.c (esignal_init): takes a signal number and an optional signal name. * signal.c (interrupt_init): pass SIGINT always. * signal.c (ruby_default_signal): invoke system default signal handler. * signal.c (rb_signal_exec, trap): handle SIGTERM. [ruby-dev:30505] ついでに1.9用。 * eval.c (ruby_cleanup): re-send signal. [ruby-dev:30516] * eval_error.h (error_handle): no message when exiting by signal. * intern.h (rb_thread_signal_raise, ruby_default_signal): prototypes. * signal.c (esignal_init): takes a signal number and an optional signal name. * signal.c (interrupt_init): pass SIGINT always. * signal.c (ruby_default_signal): invoke system default signal handler. * signal.c (rb_signal_exec, trap): handle SIGTERM. [ruby-dev:30505] * thread.c (rb_thread_signal_raise): now takes signal number instead of signal name. * thread.c (rb_thread_signal_exit): since rb_make_exception() calls #exception method, rb_class_new_instance() is not needed here. Index: eval.c =================================================================== --- eval.c (revision 12021) +++ eval.c (working copy) @@ -177,16 +177,18 @@ int ruby_cleanup(int ex) { - int state; + int state, exit_code = 0, signo = 0; volatile VALUE err = GET_THREAD()->errinfo; rb_vm_t *vm = GET_THREAD()->vm; /* th->errinfo contains a NODE while break'ing */ - if (RTEST(err) && (TYPE(err) != T_NODE) && - rb_obj_is_kind_of(err, rb_eSystemExit)) { - vm->exit_code = NUM2INT(rb_iv_get(err, "status")); - } - else { - vm->exit_code = 0; + if (RTEST(err) && (TYPE(err) != T_NODE)) { + if (rb_obj_is_kind_of(err, rb_eSystemExit)) { + exit_code = NUM2INT(rb_iv_get(err, "status")); + } + else if (rb_obj_is_kind_of(err, rb_eSignal)) { + signo = NUM2INT(rb_iv_get(err, "signo")); + } } + vm->exit_code = exit_code; GET_THREAD()->safe_level = 0; @@ -208,4 +210,7 @@ ruby_cleanup(int ex) POP_THREAD_TAG(); + if (signo) { + ruby_default_signal(signo); + } if (vm->exit_code) { return vm->exit_code; Index: eval_error.h =================================================================== --- eval_error.h (revision 12021) +++ eval_error.h (working copy) @@ -3,4 +3,7 @@ */ +#ifndef RUBY_EVAL_ERROR_H +#define RUBY_EVAL_ERROR_H + #define SET_CURRENT_SOURCE() ((void)0) @@ -200,4 +203,5 @@ error_handle(int ex) int status = EXIT_FAILURE; rb_thread_t *th = GET_THREAD(); + VALUE errinfo; if (thread_set_raised(th)) @@ -235,6 +239,10 @@ error_handle(int ex) case TAG_RAISE: case TAG_FATAL: - if (rb_obj_is_kind_of(GET_THREAD()->errinfo, rb_eSystemExit)) { - status = sysexit_status(GET_THREAD()->errinfo); + errinfo = GET_THREAD()->errinfo; + if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) { + status = sysexit_status(errinfo); + } + else if (rb_obj_is_instance_of(errinfo, rb_eSignal)) { + /* no message when exiting by signal */ } else { @@ -249,2 +257,4 @@ error_handle(int ex) return status; } + +#endif /* RUBY_EVAL_ERROR_H */ Index: intern.h =================================================================== --- intern.h (revision 12021) +++ intern.h (working copy) @@ -278,5 +278,5 @@ VALUE rb_thread_kill(VALUE); VALUE rb_thread_create(VALUE (*)(ANYARGS), void*); void rb_thread_trap_eval(VALUE, int, int); -void rb_thread_signal_raise(void *, const char*); /* should pass literal */ +void rb_thread_signal_raise(void *, int); void rb_thread_signal_exit(void *); int rb_thread_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); @@ -475,4 +475,5 @@ void rb_trap_exit(void); void rb_trap_exec(void); const char *ruby_signal_name(int); +void ruby_default_signal(int); /* sprintf.c */ VALUE rb_f_sprintf(int, const VALUE*); Index: signal.c =================================================================== --- signal.c (revision 12021) +++ signal.c (working copy) @@ -198,4 +198,82 @@ ruby_signal_name(int no) /* + * call-seq: + * SignalException.new(sig) => signal_exception + * + * Construct a new SignalException object. +sig+ should be a known + * signal name, or a signal number. + */ + +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 VALUE +interrupt_init(VALUE self, VALUE mesg) +{ + VALUE argv[2]; + + argv[0] = INT2FIX(SIGINT); + argv[1] = mesg; + return rb_call_super(2, argv); +} + +void +ruby_default_signal(int sig) +{ +#ifndef MACOS_UNUSE_SIGNAL + signal(sig, SIG_DFL); + kill(getpid(), sig); +#endif +} + +/* * call-seq: * Process.kill(signal, pid, ...) => fixnum @@ -499,4 +577,7 @@ rb_signal_exec(rb_thread_t *th, int sig) case SIGQUIT: #endif +#ifdef SIGTERM + case SIGTERM: +#endif #ifdef SIGALRM case SIGALRM: @@ -508,5 +589,5 @@ rb_signal_exec(rb_thread_t *th, int sig) case SIGUSR2: #endif - rb_thread_signal_raise(th, signo2signm(sig)); + rb_thread_signal_raise(th, sig); break; } @@ -639,4 +720,7 @@ trap(struct trap_arg *arg) case SIGQUIT: #endif +#ifdef SIGTERM + case SIGTERM: +#endif #ifdef SIGALRM case SIGALRM: @@ -899,4 +983,9 @@ Init_signal(void) rb_define_module_function(mSignal, "list", sig_list, 0); + rb_define_method(rb_eSignal, "initialize", esignal_init, -1); + rb_attr(rb_eSignal, rb_intern("signo"), 1, 0, 0); + rb_alias(rb_eSignal, rb_intern("signm"), rb_intern("message")); + rb_define_method(rb_eInterrupt, "initialize", interrupt_init, 1); + install_sighandler(SIGINT, sighandler); #ifdef SIGHUP Index: thread.c =================================================================== --- thread.c (revision 12021) +++ thread.c (working copy) @@ -753,16 +753,12 @@ rb_thread_raise(int argc, VALUE *argv, r void -rb_thread_signal_raise(void *thptr, const char *sig) +rb_thread_signal_raise(void *thptr, int sig) { - VALUE argv[1]; - char buf[BUFSIZ]; + VALUE argv[2]; rb_thread_t *th = thptr; - - if (sig == 0) { - return; /* should not happen */ - } - snprintf(buf, BUFSIZ, "SIG%s", sig); - argv[0] = rb_exc_new3(rb_eSignal, rb_str_new2(buf)); - rb_thread_raise(1, argv, th->vm->main_thread); + + argv[0] = rb_eSignal; + argv[1] = INT2FIX(sig); + rb_thread_raise(2, argv, th->vm->main_thread); } @@ -770,12 +766,10 @@ void rb_thread_signal_exit(void *thptr) { - VALUE argv[1]; - VALUE args[2]; + VALUE argv[2]; rb_thread_t *th = thptr; - - args[0] = INT2NUM(EXIT_SUCCESS); - args[1] = rb_str_new2("exit"); - argv[0] = rb_class_new_instance(2, args, rb_eSystemExit); - rb_thread_raise(1, argv, th->vm->main_thread); + + argv[0] = rb_eSystemExit; + argv[1] = rb_str_new2("exit"); + rb_thread_raise(2, argv, th->vm->main_thread); } -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦