Bug #595

Fiber ignores ensure clause

Added by ko1 (Koichi Sasada) over 3 years ago. Updated 2 months ago.

[ruby-dev:36511]
Status:Assigned Start date:09/24/2008
Priority:Normal Due date:10/25/2008
Assignee:ko1 (Koichi Sasada) % Done:

0%

Category:core
Target version:3.0
ruby -v:-

Description

Ruby プロセス終了時,Fiber が ensure を無視します.
これは,前から直そうと思って手がついていなかった問題です.
10月末までには直そうと思います.結構複雑なので,後回しにしていましました.

fib = Fiber.new{
  begin
    Fiber.yield :ok
  ensure
    puts "should be print out"
  end
}
p fib.resume

ensure_fiber.patch (2.1 kB) wanabe (_ wanabe), 01/13/2010 06:45 pm


Related issues

duplicates ruby-trunk - RubySpec #2460: RubySpecでFiberのSpecがおちる Closed 12/08/2009

History

Updated by yugui (Yuki Sonoda) over 3 years ago

  • Target version set to 1.9.1 Release Candidate

Updated by rogerdpack (Roger Pack) over 3 years ago

Help me out--shouldn't this print out only when you call fib.resume twice?

fib = Fiber.new{
  begin
    Fiber.yield :ok
  ensure
    puts "should be print out"
  end
}
p fib.resume
p fib.resume


prints out all right.

Updated by yugui (Yuki Sonoda) over 3 years ago

  • Target version changed from 1.9.1 Release Candidate to 2.0.0

Updated by yugui (Yuki Sonoda) over 3 years ago

パッチを書くか、もしくはドキュメントにKNOWN BUGとして書く、ということで。

Updated by wanabe (_ wanabe) almost 3 years ago

ワナベと申します。

かなり前のチケットですが、題名の件についてパッチを書きました。
もしまだどなたもパッチを書かれていないようならご検討ください。

Index: thread.c
===================================================================
--- thread.c	(リビジョン 23617)
+++ thread.c	(作業コピー)
@@ -293,6 +293,8 @@

 static void rb_mutex_unlock_all(mutex_t *mutex, rb_thread_t *th);

+void rb_fiber_terminate_all(rb_thread_t *th);
+
 void
 rb_thread_terminate_all(void)
 {
@@ -310,6 +312,7 @@

     thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)th);
     st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
+    rb_fiber_terminate_all(th);

     while (!rb_thread_alone()) {
 	PUSH_TAG();
@@ -1210,6 +1213,7 @@
 	    thread_debug("rb_thread_execute_interrupts: %ld\n", err);

 	    if (err == eKillSignal || err == eTerminateSignal) {
+		rb_fiber_terminate_all(th);
 		th->errinfo = INT2FIX(TAG_FATAL);
 		TH_JUMP_TAG(th, TAG_FATAL);
 	    }
Index: cont.c
===================================================================
--- cont.c	(リビジョン 23617)
+++ cont.c	(作業コピー)
@@ -534,6 +534,7 @@
       case 0:
 	return Qnil;
       case 1:
+      case -1:
 	return argv[0];
       default:
 	return rb_ary_new4(argc, argv);
@@ -946,6 +947,36 @@
     return fib->status != TERMINATED ? Qtrue : Qfalse;
 }

+static VALUE
+terminate_all_i(VALUE fibval)
+{
+    if (rb_fiber_alive_p(fibval)) {
+	VALUE value = rb_exc_new2(rb_eSystemExit, "terminate");
+	return fiber_switch(fibval, -1, &value, 0);
+    }
+}
+
+void
+rb_fiber_terminate_all(rb_thread_t *th)
+{
+    VALUE fibval;
+    rb_fiber_t *fib, *root_fib;
+    rb_thread_t *_th = GET_THREAD();
+
+    rb_thread_set_current(th);
+    fibval = th->root_fiber;
+    if (!RTEST(fibval)) return;
+    GetFiberPtr(fibval, root_fib);
+
+    fib = root_fib->prev_fiber;
+    while (fib != root_fib) {
+	rb_rescue2(terminate_all_i, fib->cont.self,
+		   0, 0, rb_eSystemExit);
+	fib = fib->prev_fiber;
+    }
+    rb_thread_set_current(_th);
+}
+
 /*
  *  call-seq:
  *     fiber.resume(args, ...) -> obj


-- 
ワナベ

Updated by ko1 (Koichi Sasada) almost 3 years ago

 ささだです.

 返事が随分遅くなってしまってすみません.

wanabe wrote::
> かなり前のチケットですが、題名の件についてパッチを書きました。
> もしまだどなたもパッチを書かれていないようならご検討ください。

 実は,以前似たようなものを作ったのですが,さくっと SEGV の嵐で,面倒く
さいなぁ,と思って放置していたのでした.このパッチですと,たとえば
test-all とかはどうでした?

-- 
// SASADA Koichi at atdot dot net

Updated by wanabe (_ wanabe) almost 3 years ago

ワナベです。

2009/06/15 6:33 に SASADA Koichi<ko1@atdot.net> さんは書きました:
> wanabe wrote::
>> かなり前のチケットですが、題名の件についてパッチを書きました。
>> もしまだどなたもパッチを書かれていないようならご検討ください。
>
> 実は,以前似たようなものを作ったのですが,さくっと SEGV の嵐で,面倒く
> さいなぁ,と思って放置していたのでした.このパッチですと,たとえば
> test-all とかはどうでした?

ruby 1.9.2dev (2009-06-14 trunk 23691) [i386-mingw32] では
make test-all で SEGV が出てしまいました。
TestFiber#test_many_fibers_with_threads が E で終わった直後の
TestFiber#test_normal で落ちているようです。
ですがなぜか test_fiber.rb を直接起動するとエラーなしで完走します。

またパッチはLinux環境で書いたのですが、その時のmake test-allでは問題はなく、
今改めて ruby 1.9.2dev (2009-06-15 trunk 23692) [i686-linux] で試してみても
SEGV は発生しませんでした。

どういう事かよく分かりませんが、不安定であることは間違いないので
このパッチは役に立たなさそうです。申し訳ありません。

-- 
ワナベ

Updated by ko1 (Koichi Sasada) almost 3 years ago

 ささだです.

wanabe wrote::
> ruby 1.9.2dev (2009-06-14 trunk 23691) [i386-mingw32] では
> make test-all で SEGV が出てしまいました。
> TestFiber#test_many_fibers_with_threads が E で終わった直後の
> TestFiber#test_normal で落ちているようです。
> ですがなぜか test_fiber.rb を直接起動するとエラーなしで完走します。
> 
> またパッチはLinux環境で書いたのですが、その時のmake test-allでは問題はなく、
> 今改めて ruby 1.9.2dev (2009-06-15 trunk 23692) [i686-linux] で試してみても
> SEGV は発生しませんでした。
> 
> どういう事かよく分かりませんが、不安定であることは間違いないので
> このパッチは役に立たなさそうです。申し訳ありません。

 いえいえ.もうちょっと追跡すればなんとかなると思うのですが,ここはどう
にも難しいですよね.Fiber の集合を保存する,私が最後にあわてて突っ込んだ
部分にバグがあるような気がしています.

 1.9.2 には間に合わせたいところ.

-- 
// SASADA Koichi at atdot dot net

Updated by wanabe (_ wanabe) over 2 years ago

以前このチケットについて書いたパッチが SEGV すると書きましたが、
パッチの問題ではなく Bug #1325 の影響だったようです。
改めて確認したところ make test-all では SEGV しませんでした。

それとは別の問題として、例外でジャンプさせると rescue される恐れがあったので
throw/catch を使うように変更したパッチを添付します。
ご検討くだされば幸いです。

Updated by wanabe (_ wanabe) over 2 years ago

  • File deleted (ensure_fiber.patch)

Updated by wanabe (_ wanabe) about 2 years ago

ささださん

このチケットおよびパッチについてコメントいただければ幸いです。
この対処で問題ないかどうか、もし問題ないとしたら 
1.9.2 リリース前に入れるべきかどうかが気になっています。
そもそもアプローチがまずいようでしたら別の方法を考えます。

Updated by mame (Yusuke Endoh) about 2 years ago

遠藤です。

2010年4月10日23:20 _ wanabe <redmine@ruby-lang.org>:
> ささださん
>
> このチケットおよびパッチについてコメントいただければ幸いです。
> この対処で問題ないかどうか、もし問題ないとしたら
> 1.9.2 リリース前に入れるべきかどうかが気になっています。
> そもそもアプローチがまずいようでしたら別の方法を考えます。

ささださんではないですが勝手にコメントします。


1) プロセス終了時でなく、Fiber が GC で回収される時に ensure 節が
実行されません。

  1000.times do
    Fiber.new do
      begin
        Fiber.yield
      ensure
        puts "foo!"
      end
    end.resume
    GC.start
  end

  # foo! が 1 個しか出ない (期待は 1000 個)
  $ ./ruby t.rb
  foo!

実行中の Thread と同様に、yield 中の Fiber は GC しないようにする
くらいしか思いつきません。


2) Fiber を作ったスレッドが終了した場合、Fiber の ensure 節が実行
されません。

  Thread.new do
    Fiber.new do
      begin
        Fiber.yield
      ensure
        puts "foo!"
      end
    end.resume
  end
  sleep 1
  puts "end"

  # foo! が出ない
  $ ./ruby t.rb
  end

プロセスの終了時でなく、スレッドの終了時に Fiber を起こさないと
行けない?


どちらも仕様レベルで検討しないといけないことのような気がします。
まだ結構大変そうなので、1.9.2 は見送った方がいいんじゃないかなと
思います。早くコメントしていれば、wanabe さんなら余裕で直せたと
思うので残念ですが。

-- 
Yusuke Endoh <mame@tsg.ne.jp>

Updated by ko1 (Koichi Sasada) about 2 years ago

(2010/04/21 23:55), Yusuke ENDOH wrote::
> どちらも仕様レベルで検討しないといけないことのような気がします。
> まだ結構大変そうなので、1.9.2 は見送った方がいいんじゃないかなと
> 思います。早くコメントしていれば、wanabe さんなら余裕で直せたと
> 思うので残念ですが。

 返事が出来ていなくてすみません.最近,色々と余裕がなくて,じっくり考え
て返事が出来ず.

-- 
// SASADA Koichi at atdot dot net

Updated by shyouhei (Shyouhei Urabe) over 1 year ago

  • Status changed from Open to Assigned

Updated by ko1 (Koichi Sasada) 12 months ago

未だに考え中ですが,これは 1.9.3 には仕様変更になるので入りませんよね?

Updated by matz (Yukihiro Matsumoto) 12 months ago

  • ruby -v changed from ruby 1.9.2dev (2010-01-13) [i386-mingw32] to -

Updated by matz (Yukihiro Matsumoto) 12 months ago

まつもと ゆきひろです In message "Re: [ruby-dev:43715] [Ruby 1.9 - Bug #595] Fiber ignores ensure clause" on Sat, 11 Jun 2011 14:52:03 +0900, Koichi Sasada <redmine@ruby-lang.org> writes: |未だに考え中ですが,これは 1.9.3 には仕様変更になるので入りませんよね? この動作はバグだと考えているので、Yuguiさんが拒絶しない限り、 直せるのであれば1.9.3で直せばよいと思います。間に合わないな らしょうがない。

Updated by naruse (Yui NARUSE) 12 months ago

RubySpec 的にバグ扱いになってますね。 core/fiber/resume_spec.rb

Updated by nahi (Hiroshi Nakamura) 11 months ago

  • Target version changed from 2.0.0 to 1.9.3

Updated by kosaki (Motohiro KOSAKI) 11 months ago

  • Status changed from Assigned to Closed

Updated by naruse (Yui NARUSE) 2 months ago

  • Status changed from Closed to Assigned
  • Target version changed from 1.9.3 to 3.0

Also available in: Atom PDF