From: Tomoyuki Chikanaga Date: 2011-10-02T22:05:49+09:00 Subject: [ruby-dev:44571] [Ruby 1.9 - Bug #5386] FiberオブジェクトのGC時にSEGV Issue #5386 has been updated by Tomoyuki Chikanaga. 以下でどうでしょうか? test-all の test_many_fibers_with_threads がSEGVするというのは起きなくなるのは確認しましたが、元々の再現スクリプトでは手元で SEGV を発生させられていないのでそちらは未確認です。 なお cont->saved_thread の構造体は cont->saved_thread.self が指しているオブジェクトが wrap している構造体のコピーで、アドレスは別物なのでそれぞれ別にマークしないといけない、ということなのかなぁと思いましたが、具体的に何がマーク漏れで困ってるのかはちゃんと確認していません。 diff --git a/cont.c b/cont.c index 3e68d89..22944d6 100644 --- a/cont.c +++ b/cont.c @@ -139,6 +139,7 @@ cont_mark(void *ptr) rb_context_t *cont = ptr; rb_gc_mark(cont->value); rb_thread_mark(&cont->saved_thread); + rb_gc_mark(cont->saved_thread.self); if (cont->vm_stack) { #ifdef CAPTURE_JUST_VALID_VM_STACK ---------------------------------------- Bug #5386: FiberオブジェクトのGC時にSEGV http://redmine.ruby-lang.org/issues/5386 Author: Kazuki Tsujimoto Status: Assigned Priority: Normal Assignee: Kazuki Tsujimoto Category: core Target version: ruby -v: ruby 1.9.4dev (2011-10-01 trunk 33368) [x86_64-linux] =begin 辻本です。 ポータブルな再現コードが作れていないのですが、 Ubuntu 10.04 x86_64にて以下のコードを実行すると FiberオブジェクトをGCする処理の中でSEGVします。 require 'fiber' 1.times { Fiber.new{} } 2.times.map {|i| Thread.new { Fiber.new{}.resume }.join }.each {|t| t.join } GC.start GC.stress = true 1.times { Fiber.new{} } バックトレースを添付します。 調べてみたところ、GC.stress設定後の1回目のマークフェーズで Breakpoint 2, fiber_mark (ptr=0xad7130) at cont.c:265 (gdb) rp ((rb_fiber_t*)ptr)->cont->saved_thread.self T_DATA(VM/thread): $1 = (struct RTypedData *) 0xaaf528 となっているFiberオブジェクトが、2回目のマークフェーズでは Breakpoint 2, fiber_mark (ptr=0xad7130) at cont.c:265 (gdb) rp ((rb_fiber_t*)ptr)->cont->saved_thread.self T_NONE: $2 = (struct RBasic *) 0xaaf528 となっており、saved_thread.selfのマーク漏れのようです。 以下の修正で直りました。 diff --git a/vm.c b/vm.c index 665351b..2ab2b92 100644 --- a/vm.c +++ b/vm.c @@ -1735,6 +1735,7 @@ rb_thread_mark(void *ptr) RUBY_MARK_UNLESS_NULL(th->first_proc); if (th->first_proc) RUBY_MARK_UNLESS_NULL(th->first_args); + RUBY_MARK_UNLESS_NULL(th->self); RUBY_MARK_UNLESS_NULL(th->thgroup); RUBY_MARK_UNLESS_NULL(th->value); RUBY_MARK_UNLESS_NULL(th->errinfo); =end -- http://redmine.ruby-lang.org