https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112012-11-28T15:58:26ZRuby Issue Tracking SystemBackport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=340722012-11-28T15:58:26Zmrkn (Kenta Murata)muraken@gmail.com
<ul></ul><p>このバグに対する再現テストの書き方が分からないので知ってる人がいたら教えて下さい!!</p> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=340752012-11-28T16:34:41ZauthorNari (Narihiro Nakamura)authorNari@gmail.com
<ul></ul><p>メインスレッドにファイナライザを登録できないようなパッチになっているようですが、ファイナライザ実行後に止まってしまうことが問題の本質のように思います。<br>
なんで止まってしまうのでしょうね…。</p> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=340762012-11-28T16:47:20ZauthorNari (Narihiro Nakamura)authorNari@gmail.com
<ul></ul><p>authorNari (Narihiro Nakamura) wrote:</p>
<blockquote>
<p>メインスレッドにファイナライザを登録できないようなパッチになっているようですが</p>
</blockquote>
<p>ああっ、すいません、パッチを読み違えてました…。<br>
ファイナライザは実行後にメインスレッドだけfree-listには追加しないようにするパッチなんですね。</p> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=340782012-11-28T17:04:15Zmrkn (Kenta Murata)muraken@gmail.com
<ul></ul><blockquote>
<p>ファイナライザは実行後にメインスレッドだけfree-listには追加しないようにするパッチなんですね。</p>
</blockquote>
<p>そのとおりです。</p>
<p>笹田さんに修正方法が場当たり的だと指摘されて、自分もそう思っているのですが、<br>
残念ながら今のところエレガントな解決方法を考えられていません。</p> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=340812012-11-28T21:42:38ZauthorNari (Narihiro Nakamura)authorNari@gmail.com
<ul></ul><p>バグの原因がわかりました。<br>
ファイナライザに登録したメインスレッドはRubyプロセス終了時のファイナライザ実行時(rb_objspace_call_finalizer)でfreelistに追加されてしまっているようです。</p>
<p>(gdbのバックトレース)<br>
#0 add_slot_local_freelist (objspace=0x5555559ed8f0, p=0x555555a5be48) at gc.c:819<br>
#1 0x00005555555c7f42 in finalize_list (objspace=0x5555559ed8f0, p=0x555555a5be48) at gc.c:1423<br>
#2 0x00005555555c7fd5 in finalize_deferred (objspace=0x5555559ed8f0) at gc.c:1443<br>
#3 0x00005555555c81ee in rb_objspace_call_finalizer (objspace=0x5555559ed8f0) at gc.c:1509<br>
#4 0x00005555555c81a6 in rb_gc_call_finalizer_at_exit () at gc.c:1493<br>
#5 0x00005555555b1b5a in ruby_finalize_1 () at eval.c:127<br>
<a class="issue tracker-1 status-5 priority-4 priority-default closed behind-schedule" title="Bug: sprintf() of %f on Windows(MSVCRT) (Closed)" href="https://bugs.ruby-lang.org/issues/6">#6</a> 0x00005555555b1dbb in ruby_cleanup (ex=0) at eval.c:193<br>
#7 0x00005555555b20a7 in ruby_run_node (n=0x555555a581e8) at eval.c:307<br>
#8 0x00005555555746b9 in main (argc=3, argv=0x7fffffffd248) at main.c:36</p>
<p>rb_objspace_call_finalizer()呼び出し後にruby_vm_destruct(VMのデストラクタ)が動き、そのデストラクタではメインスレッドを使うのですが、上記の通りfreeされてしまっているのでうまくいかないようですね。<br>
これはメインスレッドに限った話ではなく、rb_objspace_call_finalizer()呼び出し後に触る可能性があるオブジェクトにファイナライザを登録するのがまずいみたいです。</p>
<p>ややad-hocですが、こんな感じでなおしてみました。<br>
<a href="https://gist.github.com/4160845" class="external">https://gist.github.com/4160845</a><br>
VMから見えているものはとりあえずマークしておいて、通常のファイナライズは回避し、強制的なファイナライズでそれらを実行させるようにしています。</p>
<p>もしかしたら以下のパッチのようにほとんど強制的なファイナライズにしてもいいかなあと思いますが、こっちはちょっと自信がないです。<br>
Rubyのファイナライズ周りに詳しい方の意見を伺いたいところです。。。</p>
<p>diff --git a/gc.c b/gc.c<br>
index 63869a0..8d68e38 100644<br>
--- a/gc.c<br>
+++ b/gc.c<br>
@@ -1505,15 +1505,9 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)<br>
if (ATOMIC_EXCHANGE(finalizing, 1)) return;</p>
<pre><code> /* run finalizers */
</code></pre>
<ul>
<li>do {</li>
<li>
<pre><code> finalize_deferred(objspace);
</code></pre>
</li>
<li>
<pre><code> /* mark reachable objects from finalizers */
</code></pre>
</li>
<li>
<pre><code> /* They might be not referred from any place here */
</code></pre>
</li>
<li>
<pre><code> mark_tbl(objspace, finalizer_table);
</code></pre>
</li>
<li>
<pre><code> gc_mark_stacked_objects(objspace);
</code></pre>
</li>
<li>
<pre><code> st_foreach(finalizer_table, chain_finalized_object,
</code></pre>
</li>
<li>
<pre><code> (st_data_t)&deferred_final_list);
</code></pre>
</li>
<li>} while (deferred_final_list);</li>
</ul>
<ul>
<li>finalize_deferred(objspace);</li>
<li>assert(deferred_final_list == 0);</li>
<li>/* force to run finalizer */<br>
while (finalizer_table->num_entries) {<br>
struct force_finalize_list *list = 0;</li>
</ul> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=341352012-11-29T18:23:32Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>(12/11/28 21:42), authorNari (Narihiro Nakamura) wrote:</p>
<blockquote>
<p>ややad-hocですが、こんな感じでなおしてみました。<br>
<a href="https://gist.github.com/4160845" class="external">https://gist.github.com/4160845</a><br>
VMから見えているものはとりあえずマークしておいて、通常のファイナライズは回避し、強制的なファイナライズでそれらを実行させるようにしています。</p>
</blockquote>
<p>VMから見えているものがfinalizeされてしまうというのは単純なマーク漏れのバグと考えていいんじゃないですかね。</p>
<p>--<br>
--- 僕の前にBugはない。<br>
--- 僕の後ろにBugはできる。<br>
中田 伸悦</p> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=341652012-11-30T07:57:15ZauthorNari (Narihiro Nakamura)authorNari@gmail.com
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li></ul><p>This issue was solved with changeset r38010.<br>
Kenta, thank you for reporting this issue.<br>
Your contribution to Ruby is greatly appreciated.<br>
May Ruby be with you.</p>
<hr>
<ul>
<li>
<p>gc.c (rb_objspace_call_finalizer): finalize_deferred may free up<br>
a object which is reachable from a part after this function,<br>
e.g. ruby_vm_destruct(). <a href="/issues/7452">[ruby-dev:46647]</a> [Bug <a class="issue tracker-4 status-5 priority-4 priority-default closed" title="Backport: Main thread is stopped after running finalizers if the main thread has a finalizer (Closed)" href="https://bugs.ruby-lang.org/issues/7452">#7452</a>]</p>
</li>
<li>
<p>test/ruby/test_gc.rb (test_finalizing_main_thread): add a test<br>
for above.</p>
</li>
</ul> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=341662012-11-30T08:24:05ZauthorNari (Narihiro Nakamura)authorNari@gmail.com
<ul></ul><p>2012年11月29日 18:01 Nobuyoshi Nakada <a href="mailto:nobu@ruby-lang.org" class="email">nobu@ruby-lang.org</a>:</p>
<blockquote>
<p>(12/11/28 21:42), authorNari (Narihiro Nakamura) wrote:</p>
<blockquote>
<p>ややad-hocですが、こんな感じでなおしてみました。<br>
<a href="https://gist.github.com/4160845" class="external">https://gist.github.com/4160845</a><br>
VMから見えているものはとりあえずマークしておいて、通常のファイナライズは回避し、強制的なファイナライズでそれらを実行させるようにしています。</p>
</blockquote>
<p>VMから見えているものがfinalizeされてしまうというのは単純なマーク漏れのバグと考えていいんじゃないですかね。</p>
</blockquote>
<p>rb_objspace_call_finalizerではマークがすべてのオブジェクトに付いてない状態で実行されるんですよね。<br>
なので、もしかするとここでVMから見えるものだけマークするだけじゃなく、gc_marksとか読んだほうがいいのかもですが…。</p>
<p>とりあえずは、「ほとんど強制的なファイナライズ」の方でコミットしてみました。<br>
test-allなどは通ったのでとりあえずこれで様子を見たいとおもいます。</p>
<p>--<br>
Narihiro Nakamura (nari)</p> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=353502013-01-11T17:40:25Zmrkn (Kenta Murata)muraken@gmail.com
<ul><li><strong>Tracker</strong> changed from <i>Bug</i> to <i>Backport</i></li><li><strong>Project</strong> changed from <i>Ruby master</i> to <i>Backport193</i></li><li><strong>Category</strong> deleted (<del><i>core</i></del>)</li><li><strong>Status</strong> changed from <i>Closed</i> to <i>Assigned</i></li><li><strong>Assignee</strong> changed from <i>authorNari (Narihiro Nakamura)</i> to <i>usa (Usaku NAKAMURA)</i></li><li><strong>Target version</strong> deleted (<del><i>2.0.0</i></del>)</li></ul><p>1.9.3 でも再現するのでバックポートして頂けませんか。</p> Backport193 - Backport #7452: Main thread is stopped after running finalizers if the main thread has a finalizerhttps://bugs.ruby-lang.org/issues/7452?journal_id=354312013-01-15T16:29:43Zusa (Usaku NAKAMURA)usa@garbagecollect.jp
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li></ul><p>This issue was solved with changeset r38831.<br>
Kenta, thank you for reporting this issue.<br>
Your contribution to Ruby is greatly appreciated.<br>
May Ruby be with you.</p>
<hr>
<p>merge revision(s) 38010: [Backport <a class="issue tracker-4 status-5 priority-4 priority-default closed" title="Backport: Main thread is stopped after running finalizers if the main thread has a finalizer (Closed)" href="https://bugs.ruby-lang.org/issues/7452">#7452</a>]</p>
<pre><code>* gc.c (rb_objspace_call_finalizer): finalize_deferred may free up
a object which is reachable from a part after this function,
e.g. ruby_vm_destruct(). <a href="/issues/7452">[ruby-dev:46647]</a> [Bug #7452]
* test/ruby/test_gc.rb (test_finalizing_main_thread): add a test
for above.
* test/rdoc/test_rdoc_servlet.rb: Tets for above
</code></pre>