From: Nobuyoshi Nakada Date: 2007-03-10T06:14:45+09:00 Subject: [ruby-dev:30519] Re: [BUG?] SIGTERM の取り扱い なかだです。 At Fri, 9 Mar 2007 10:42:22 +0900, Hidetoshi NAGAI wrote in [ruby-dev:30516]: > > > |> # メッセージが "ruby: SIGTERM (SignalException)" となってしまうのが > > > |> # 少し格好悪い気もしますが... > > > | > > > |どうなるのがいいんでしょう。トップレベルまで抜けたところで、 > > > |SIG_DFLに戻して再度kill()? > > > > > > トップレベルで例外がrb_eSignalのとき、メッセージを出さずに終 > > > 了するのがよいのではないかと。 > > > > 親プロセスではWIFSIGNALEDとかWTERMSIGが取れることを期待している > > のではないかと思ったんですが、そこまでは必要なし? > > 必要なのでしょうね. > 最初は _exit(SIGTERM) でもいいのかなとも思いましたが (^_^;, > 確かに SIG_DFL で始末してもらわないと具合いが悪そうです. > > # 「じゃあ HUP, QUIT はいいのか?」って話もありますが... SignalExceptionとInterruptの関係が微妙ですが。 $ trap ":" 2 $ for sig in HUP INT QUIT TERM; do > echo $sig; ./ruby -esleep & usleep 100000; kill -$sig $!; fg > echo $?; echo ---------- > done HUP [1] 25936 ./ruby -esleep ハングアップ 129 ---------- INT [1] 25938 ./ruby -esleep -e:1:in `sleep': Interrupt from -e:1 130 ---------- QUIT [1] 25940 ./ruby -esleep 終了 (core dumped) 131 ---------- TERM [1] 25943 ./ruby -esleep 終了しました 143 ---------- Index: intern.h =================================================================== --- intern.h (revision 12021) +++ intern.h (working copy) @@ -212,5 +212,5 @@ VALUE rb_thread_create _((VALUE (*)(ANYA void rb_thread_interrupt _((void)); void rb_thread_trap_eval _((VALUE, int, int)); -void rb_thread_signal_raise _((char*)); +void rb_thread_signal_raise _((int)); void rb_thread_signal_exit _((void)); int rb_thread_select _((int, fd_set *, fd_set *, fd_set *, struct timeval *)); @@ -395,4 +395,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, VALUE*)); Index: eval.c =================================================================== --- eval.c (revision 12021) +++ eval.c (working copy) @@ -1493,4 +1493,7 @@ error_handle(ex) status = sysexit_status(ruby_errinfo); } + else if (rb_obj_is_instance_of(ruby_errinfo, rb_eSignal)) { + /* no message when exiting by signal */ + } else { error_print(); @@ -1580,7 +1583,13 @@ ruby_cleanup(ex) POP_TAG(); - if (err && rb_obj_is_kind_of(err, rb_eSystemExit)) { - VALUE st = rb_iv_get(err, "status"); - return NUM2INT(st); + if (err) { + if (rb_obj_is_kind_of(err, rb_eSystemExit)) { + VALUE st = rb_iv_get(err, "status"); + return NUM2INT(st); + } + else if (rb_obj_is_kind_of(err, rb_eSignal)) { + VALUE sig = rb_iv_get(err, "signo"); + ruby_default_signal(NUM2INT(sig)); + } } return ex; @@ -10156,5 +10165,4 @@ static NODE *th_raise_node; static VALUE th_cmd; static int th_sig, th_safe; -static char *th_signm; #define RESTORE_NORMAL 1 @@ -10262,5 +10270,5 @@ rb_thread_switch(n) break; case RESTORE_SIGNAL: - rb_raise(rb_eSignal, "SIG%s", th_signm); + rb_thread_signal_raise(th_sig); break; case RESTORE_EXIT: @@ -12263,11 +12271,13 @@ rb_thread_interrupt() void rb_thread_signal_raise(sig) - char *sig; + int sig; { - if (sig == 0) return; /* should not happen */ rb_thread_critical = 0; if (curr_thread == main_thread) { + VALUE argv[1]; + rb_thread_ready(curr_thread); - rb_raise(rb_eSignal, "SIG%s", sig); + argv[0] = INT2FIX(sig); + rb_exc_raise(rb_class_new_instance(1, argv, rb_eSignal)); } rb_thread_ready(main_thread); @@ -12277,5 +12287,5 @@ rb_thread_signal_raise(sig) } } - th_signm = sig; + th_sig = sig; curr_thread = main_thread; rb_thread_restore_context(curr_thread, RESTORE_SIGNAL); Index: signal.c =================================================================== --- signal.c (revision 12021) +++ signal.c (working copy) @@ -171,5 +171,5 @@ static struct signals { static int signm2signo(nm) - char *nm; + const char *nm; { struct signals *sigs; @@ -201,4 +201,91 @@ ruby_signal_name(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(argc, argv, self) + int argc; + VALUE *argv; + VALUE self; +{ + int argnum = 1; + VALUE sig = Qnil; + int signo; + const char *signm; + char tmpnm[(sizeof(int)*CHAR_BIT)/3+4]; + + if (argc > 0) { + sig = argv[0]; + if (FIXNUM_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 = FIX2INT(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) { + snprintf(tmpnm, sizeof(tmpnm), "SIG%s", signm); + } + else { + snprintf(tmpnm, sizeof(tmpnm), "SIG%u", signo); + } + sig = rb_str_new2(signm = tmpnm); + } + } + 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(self, mesg) + VALUE self, mesg; +{ + VALUE argv[2]; + + argv[0] = INT2FIX(SIGINT); + argv[1] = mesg; + return rb_call_super(2, argv); +} + +void +ruby_default_signal(sig) + int sig; +{ +#ifndef MACOS_UNUSE_SIGNAL + extern rb_pid_t getpid _((void)); + + signal(sig, SIG_DFL); + kill(getpid(), sig); +#endif +} + +/* * call-seq: * Process.kill(signal, pid, ...) => fixnum @@ -414,4 +501,7 @@ signal_exec(sig) case SIGQUIT: #endif +#ifdef SIGTERM + case SIGTERM: +#endif #ifdef SIGALRM case SIGALRM: @@ -423,5 +513,5 @@ signal_exec(sig) case SIGUSR2: #endif - rb_thread_signal_raise(signo2signm(sig)); + rb_thread_signal_raise(sig); break; } @@ -681,4 +771,7 @@ trap(arg) case SIGQUIT: #endif +#ifdef SIGTERM + case SIGTERM: +#endif #ifdef SIGALRM case SIGALRM: @@ -976,4 +1069,9 @@ Init_signal() 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 -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦