From: SASADA Koichi Date: 2007-08-13T03:03:31+09:00 Subject: [ruby-dev:31384] Re: simultaneous exceptions dump core  ささだです。 Yusuke ENDOH wrote: > 同じスレッドにほぼ同時に複数の例外が発生するとき落ちるようです。 > timeout を使うコードを Ctrl+C で止めるとたまに発生するので気が付きました。 > > > 少し追ってみましたが、状況がややこしくてどこからどこまでが想定外の挙動なのか > わかりませんでした。以下のようなことが起きているようです。 > > - 1 発目の raise で rb_longjmp が呼ばれる > - rb_longjmp 中の rb_exc_new (eval.c:660 あたり) でコンテキストスイッチする > - 別スレッドから 2 発目の raise で rb_longjmp に再入する > - JUMP_TAG(TAG_FATAL); が実行される (eval.c:654 あたり) > - rb_ivar_get(err, idThrowState) が実行される (insnhelper.ci:1303 あたり) > - #__ThrowState__ は初期化されておらず、警告とともに Qnil が返る > - th->state = FIX2INT(Qnil) が実行される (insnhelper.ci:1303 あたり) > - Stack consistency error になる  詳細に追っていただいてありがとうございました。「Thread#raise に よって複数のスレッドから例外を投げた時の挙動」は、1.8 以前ではなかっ たものなんですよね。まず、この仕様をどうするべきかの議論が必要かと思 います。  いくつかの案を上げてみます。 (1) すでに対象スレッドに例外が投げられていた場合、ブロック (2) すでに対象スレッドに例外が投げられていた場合、キューイング (3) すでに対象スレッドに例外が投げられていた場合、例外  (3) はあんまり、(2) は、結局投げた例外が無駄になる可能性がある、と いうことで、1.8 と同じ挙動となる (1) がいいのではないかと思っています。  以下は (1) のパッチです。上記プログラムは、一応問題がなくなりまし た。しかし、Ctrl+C の問題は解決しなさそうな気がする...。 Index: thread.c =================================================================== --- thread.c (リビジョン 12920) +++ thread.c (作業コピー) @@ -758,12 +758,16 @@ { VALUE exc; + again: if (rb_thread_dead(th)) { return Qnil; } + if (th->thrown_errinfo != Qnil) { + rb_thread_schedule(); + goto again; + } exc = rb_make_exception(argc, argv); - /* TODO: need synchronization if run threads in parallel */ th->thrown_errinfo = exc; rb_thread_ready(th); return Qnil; -- // SASADA Koichi at atdot dot net