Forum: Ruby-dev [Ruby 1.9 - Bug #5368][Open] ensure節でsleepするようなThreadがあるとインタプリタが終了しない

Posted by Masaki Matsushita (Guest)
on 2011-09-26 06:51
(Received via mailing list)
Issue #5368 has been reported by Masaki Matsushita.

----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
http://redmine.ruby-lang.org/issues/5368

Author: Masaki Matsushita
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 1.9.x
ruby -v: ruby 1.9.4dev (2011-09-26 trunk 33338) [x86_64-linux]


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by SASADA Koichi (Guest)
on 2011-09-26 07:24
(Received via mailing list)
(2011/09/25 21:51), Masaki Matsushita wrote:
> 
現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。
 ここで,バグとは何でしょうか.

(1) CPU 使用率がはねあがる
(2) プロセスが死なない


 (1) が問題というのは理解できます.あまり文句がないんで放置している部分
です.直そうと思えば,正しく他のスレッドを待ち合わせをすればできると思っ
ています.

 (2) については仕様です.ご提案の修正方法では,とにかく生きていたら殺
す,ということをしていますが,例えば他のスレッドで何か時間のかかる終了処
理をしていた場合(例えば,終了時にネットワークで外部に情報を送る,という
ようなことをしている場合),それを強制的に止めてしまうため,まずいことに
なります.

 ということで,これに関しては,現状だと仕様かな,と思いますが,もっと良
い仕様があれば,ご提案頂けと助かります.
Posted by KOSAKI Motohiro (Guest)
on 2011-09-26 15:41
(Received via mailing list)
2011$BG/(B9$B7n(B26$BF|(B14:24 SASADA Koichi <ko1@atdot.net>:
>>
>
> $B!!(B(2) $B$K$D$$$F$O;EMM$G$9!%$4Ds0F$N=$@5J}K!$G$O!$$H$K$+$/@8$-$F$$$?$i;&(B
> $B$9!$$H$$$&$3$H$r$7$F$$$^$9$,!$Nc$($PB>$N%9%l%C%I$G2?$+;~4V$N$+$+$k=*N;=h(B
> $BM}$r$7$F$$$?>l9g!JNc$($P!$=*N;;~$K%M%C%H%o!<%/$G30It$K>pJs$rAw$k!$$H$$$&(B
> $B$h$&$J$3$H$r$7$F$$$k>l9g!K!$$=$l$r6/@)E*$K;_$a$F$7$^$&$?$a!$$^$:$$$3$H$K(B
> $B$J$j$^$9!%(B
>
> $B!!$H$$$&$3$H$G!$$3$l$K4X$7$F$O!$8=>u$@$H;EMM$+$J!$$H;W$$$^$9$,!$$b$C$HNI(B
> $B$$;EMM$,$"$l$P!$$4Ds0FD:$1$H=u$+$j$^$9!%(B

C$B8@8l$@$C$F(Bat_exit()$B$G(Bsleep()$B$7$?$i;`$J$J$$$7!"(BC++$B$@$C$F%G%9%H%i%/%?$G(Bsleep()$B$7$?$i(B
$B;`$J$J$$$7$M$(!#(B
$B%W%m%0%i%_%s%08@8l$O%"%[$J%3!<%I$K$?$$$7$F%"%[$J?6$kIq$$$r$9$k$N$O$=$&$$$&$b$N$H$$$&5$$,$7$^$9!#8D?ME*$K$O!#(B

ensure$B$K(Bsleep$B$r=q$/$3$H$,Hr$1$k$3$H$,IT2DG=!#$H$$$&OC$K$J$k$H$^$?$A$g$C$HOC$,JQ$o$C$F$/$k$+$H(B
$B;W$$$^$9$,!"$=$&$$$&Nc$O;W$$$D$-$^$;$s$G$7$?!#(B
Posted by m_takao (Guest)
on 2011-09-26 16:04
(Received via mailing list)
$B9bHx$H?=$7$^$9!#(B

> $B!!(B(2) $B$K$D$$$F$O;EMM$G$9!%$4Ds0F$N=$@5J}K!$G$O!$$H$K$+$/@8$-$F$$$?$i;&(B
> $B$9!$$H$$$&$3$H$r$7$F$$$^$9$,!$Nc$($PB>$N%9%l%C%I$G2?$+;~4V$N$+$+$k=*N;=h(B
> $BM}$r$7$F$$$?>l9g!JNc$($P!$=*N;;~$K%M%C%H%o!<%/$G30It$K>pJs$rAw$k!$$H$$$&(B
> $B$h$&$J$3$H$r$7$F$$$k>l9g!K!$$=$l$r6/@)E*$K;_$a$F$7$^$&$?$a!$$^$:$$$3$H$K(B
> $B$J$j$^$9!%(B

$B$3$l$O!V(Bensure$B@a$N<B9TCf$K;_$a$k$N$O(BNG$B!W$H$$$&$3$H$G$9$h$M(B?
$B$$$^$N<BAu(B (rev.33339) 
$B$G$O!"(Bensure$B@a$N<B9TCf$G$"$C$F$b!"(Bterminate$B$5$l$?$i(B
($B30B&$K$5$i$J$k(Bensure$B@a$,$J$1$l$P(B) 
$B$U$D$&$K=*N;$9$k$N$G!"DTjm$,9g$o$J$$5$$,$7$^$9!#(B
Posted by SASADA Koichi (Guest)
on 2011-09-26 16:53
(Received via mailing list)
(2011/09/26 7:03), m_takao wrote:
> $B$3$l$O!V(Bensure$B@a$N<B9TCf$K;_$a$k$N$O(BNG$B!W$H$$$&$3$H$G$9$h$M(B?
> $B$$$^$N<BAu(B (rev.33339) 
$B$G$O!"(Bensure$B@a$N<B9TCf$G$"$C$F$b!"(Bterminate$B$5$l$?$i(B
> ($B30B&$K$5$i$J$k(Bensure$B@a$,$J$1$l$P(B) 
$B$U$D$&$K=*N;$9$k$N$G!"DTjm$,9g$o$J$$5$$,$7$^$9!#(B

$B!!$4;XE&$NDL$j!$!V:G=i$N(B1$B2s$@$1$OI,$:(B ensure 
$BCf$G$b6/@)E*$K;_$a$F$7$^(B
$B$&!W$H$$$&;EMM$K$J$C$F$$$^$9$M!%8=>u$G$O!$(Bensure 
$BCf!J8e=hM}Cf!K$G$O$J$$(B
$B$3$H$r4|BT$7$F$$$^$9!%%U%!%$%J%i%$%6<B9TCf$G$b!$6/@)E*$K%-%c%s%;%k$5$l$k(B
$B$N$G!$2?$+8e=hM}$r$7$F$$$k:GCf$K;_$a$i$l$k$N$OIT2DHr$G$9!%(B

# 
$B:#$^$GJ86g$,L5$+$C$?$H$$$&$N$O!$3NN(E*$K$3$&$$$&%1!<%9$,5/$-$E$i$$!$(B
# $B$H$$$&$3$H$G$7$g$&$+$M!%(B

$B!!??LLL\$K$d$k$J$i!$$9$G$K2?EY$+Ds0F$,$"$k!$$3$&$$$&3d$j9~$_$r@)8f$9$k$?(B
$B$a$N;EAH$_$rE}0lE*$K@0Hw$9$k$C$F$3$H$K$J$k$H;W$$$^$9!%$&!<$s!$$;$a$F%U%!(B
$B%$%J%i%$%6$N=hM}$O(B main thread 
$B$N$_$G9T$&$h$&$K$7$?$[$&$,$$$$$s$@$m$&$+!%(B

$B!!$b$7$/$O!$$3$&$$$&=hM}$r9T$&$3$H$,$"$k$N$J$i!$$A$c$s$H(B join 
$B$7$F$+$i;`(B
$B$K$^$7$g$&!$$H3+$-D>$C$F!$:G=i$N$4Ds0F$NDL$j!$3N<B$K;&$9!$$H$$$&$U$&$K?6(B
$B$k$N$+$J$!!%$=$l$O$=$l$GITJX$=$&$K;W$&$N$@$1$I!%(B

$B!!7kO@$b=P$F$^$;$s$,!$8=>u$O$J$s$H$J$/$&$^$/F0$/$3$H$,B?$$!$2~A1$9$k$K$O(B
$B$7$s$I$=$&!$$H$$$&$3$H$G!$$J$s$H$J$/8=>u$N;EMM$K$J$C$F$$$k!$$H$$$&$3$H$+(B
$B$H;W$$$^$9!%(B

$B!!$b$7$&$^$$<j$,$"$l$P65$($F$/$@$5$$!%(B
Posted by Nobuyoshi Nakada (nobu)
on 2011-09-29 13:21
(Received via mailing list)
$B$J$+$@$G$9!#(B

At Mon, 26 Sep 2011 23:52:19 +0900,
SASADA Koichi wrote in [ruby-dev:44552]:
> (2011/09/26 7:03), m_takao wrote:
>> $B$3$l$O!V(Bensure$B@a$N<B9TCf$K;_$a$k$N$O(BNG$B!W$H$$$&$3$H$G$9$h$M(B?
>> $B$$$^$N<BAu(B (rev.33339) 
$B$G$O!"(Bensure$B@a$N<B9TCf$G$"$C$F$b!"(Bterminate$B$5$l$?$i(B
>> ($B30B&$K$5$i$J$k(Bensure$B@a$,$J$1$l$P(B) 
$B$U$D$&$K=*N;$9$k$N$G!"DTjm$,9g$o$J$$5$$,$7$^$9!#(B
>
> $B!!$4;XE&$NDL$j!$!V:G=i$N(B1$B2s$@$1$OI,$:(B ensure 
$BCf$G$b6/@)E*$K;_$a$F$7$^(B
> $B$&!W$H$$$&;EMM$K$J$C$F$$$^$9$M!%8=>u$G$O!$(Bensure $BCf!J8e=hM}Cf!K$G$O$J$$(B
> $B$3$H$r4|BT$7$F$$$^$9!%%U%!%$%J%i%$%6<B9TCf$G$b!$6/@)E*$K%-%c%s%;%k$5$l$k(B
> $B$N$G!$2?$+8e=hM}$r$7$F$$$k:GCf$K;_$a$i$l$k$N$OIT2DHr$G$9!%(B

ensure$B$G(Bsleep$B$5$l$?$i;_$^$k$N$O;EJ}$,$J$$$K$;$h!"$=$3$G3d$j9~$_$r<u$1$?(B
$B$i$d$O$jH4$1$k$[$&$,$$$$$N$G$O$J$$$G$7$g$&$+!#(B


diff --git i/thread.c w/thread.c
index d9d497a..0e3d096 100644
--- i/thread.c
+++ w/thread.c
@@ -333,6 +333,7 @@ typedef struct rb_mutex_struct

 static void rb_mutex_abandon_all(rb_mutex_t *mutexes);
 static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t 
volatile *th);
+static int vm_living_thread_num(rb_vm_t *vm);

 void
 rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th)
@@ -369,14 +370,20 @@ rb_thread_terminate_all(void)
     st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
     vm->inhibit_thread_creation = 1;

-    while (!rb_thread_alone()) {
+
+    if (th->vm->living_threads && vm_living_thread_num(th->vm) > 1) {
+  int state;
+  const double sleep_time = 3600.0; /* should not be too long to
+             * get rid of overflow */
   PUSH_TAG();
-  if (EXEC_TAG() == 0) {
-      rb_thread_schedule();
-  }
-  else {
-      /* ignore exception */
+  state = EXEC_TAG();
+  while (state == 0 || !rb_thread_alone()) {
+      if (state) {
+    st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
+      }
+      sleep_wait_for_interrupt(th, sleep_time);
   }
+  /* ignore exception */
   POP_TAG();
     }
 }
@@ -445,6 +452,8 @@ thread_start_func_2(rb_thread_t *th, VALUE 
*stack_start, VALUE *register_stack_s

     gvl_acquire(th->vm, th);
     {
+  int terminating = 0;
+
   thread_debug("thread start (get lock): %p\n", (void *)th);
   rb_thread_set_current(th);

@@ -469,6 +478,7 @@ thread_start_func_2(rb_thread_t *th, VALUE 
*stack_start, VALUE *register_stack_s
       if (NIL_P(errinfo)) errinfo = rb_errinfo();
       if (state == TAG_FATAL) {
     /* fatal error within this thread, need to stop whole script */
+    terminating = (errinfo == eTerminateSignal);
       }
       else if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
     if (th->safe_level >= 4) {
@@ -509,13 +519,23 @@ thread_start_func_2(rb_thread_t *th, VALUE 
*stack_start, VALUE *register_stack_s
   /* delete self other than main thread from living_threads */
   if (th != main_th) {
       st_delete_wrap(th->vm->living_threads, th->self);
+      if (terminating) {
+    if (vm_living_thread_num(th->vm) == 1) {
+        rb_threadptr_interrupt(main_th);
+    }
+    else {
+        terminating = 0;
+    }
+      }
   }

   /* wake up joining threads */
   join_th = th->join_list_head;
   while (join_th) {
-      if (join_th == main_th) errinfo = Qnil;
-      rb_threadptr_interrupt(join_th);
+      if ((join_th != main_th) || (errinfo = Qnil, !terminating)) {
+    /* main thread is already interrupted when terminating */
+    rb_threadptr_interrupt(join_th);
+      }
       switch (join_th->status) {
         case THREAD_STOPPED: case THREAD_STOPPED_FOREVER:
     join_th->status = THREAD_RUNNABLE;
Posted by KOSAKI Motohiro (Guest)
on 2011-09-29 14:15
(Received via mailing list)
2011$BG/(B9$B7n(B29$BF|(B20:20 Nobuyoshi Nakada <nobu@ruby-lang.org>:
>> $B$&!W$H$$$&;EMM$K$J$C$F$$$^$9$M!%8=>u$G$O!$(Bensure $BCf!J8e=hM}Cf!K$G$O$J$$(B
>> $B$3$H$r4|BT$7$F$$$^$9!%%U%!%$%J%i%$%6<B9TCf$G$b!$6/@)E*$K%-%c%s%;%k$5$l$k(B
>> $B$N$G!$2?$+8e=hM}$r$7$F$$$k:GCf$K;_$a$i$l$k$N$OIT2DHr$G$9!%(B
>
> ensure$B$G(Bsleep$B$5$l$?$i;_$^$k$N$O;EJ}$,$J$$$K$;$h!"$=$3$G3d$j9~$_$r<u$1$?(B
> $B$i$d$O$jH4$1$k$[$&$,$$$$$N$G$O$J$$$G$7$g$&$+!#(B

$B8=:_$N(Bensure$BCf$NHsF14|Nc30$N07$$$O;EMM%P%0$G$"$k$H$$$&G'<1$J$N$G!"$3$&$$$&(B
$B%o!<%/%"%i%&%s%I$K$O$"$^$j$$$$0u>]$r;}$A$^$;$s!#(B
$B<BMQE*$K$bLdBj$,$"$k$H;W$C$F$$$F!"(BC-c 
$B$rF|>oE*$K#2!]#32sO"BG$9$kJJ$N$"$k$R$H$O(B
$B$$$k$N$G!"$=$&$$$&?M$+$i$9$k$H%W%m%;%9=*N;=hM}$,$A$c$s$H9T$o$l$J$/$J$k(Bregression
$B$K8+$($k$N$G$O$J$$$G$7$g$&$+!#(B
Posted by Shyouhei Urabe (Guest)
on 2011-09-29 18:32
(Received via mailing list)
Issue #5368 has been updated by Shyouhei Urabe.


提案されている workaround はいまいち、という点には同意します。

ただ、じゃあどうなるべきなの? というところのコンセンサスは足りていないでしょう。

というわけで結論を急がずに少し議論したほうがいいんじゃないでしょうか。
----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
http://redmine.ruby-lang.org/issues/5368

Author: Masaki Matsushita
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 1.9.x
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by Koichi Sasada (Guest)
on 2012-03-11 08:06
(Received via mailing list)
Issue #5368 has been updated by Koichi Sasada.

Assignee set to Koichi Sasada

今日,非同期例外の話が出たので,それと交えて考えます.
多分.
----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368

Author: Masaki Matsushita
Status: Open
Priority: Normal
Assignee: Koichi Sasada
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by ko1 (Koichi Sasada) (Guest)
on 2012-11-26 01:44
(Received via mailing list)
Issue #5368 has been updated by ko1 (Koichi Sasada).

Assignee changed from ko1 (Koichi Sasada) to kosaki (Motohiro KOSAKI)
Priority changed from Normal to High

ticket の詳細が思い出せないので小崎先生に振ってみます.
control_interrupt じゃ解決しないんだよな,多分.
----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33915

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: High
Assignee: kosaki (Motohiro KOSAKI)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by kosaki (Motohiro KOSAKI) (Guest)
on 2012-11-26 04:27
(Received via mailing list)
Issue #5368 has been updated by kosaki (Motohiro KOSAKI).


読み返しました。[Feature #1952] とちょっと似た話で終了途中で例外食われてしまったら、という話のようですね。論点をまとめると

 - ensure節の中でsleep等、無限待ちが記述されているとハングしてしまう。これはバグではないか (Glass_saga)
 - この場合止まっているのはサブスレッドなので、Ctrl-cは意味が無い。メインスレッドが食って無視してしまう
 - しかし、タイムアウト等をつくると終了処理に時間のかかるスクリプトが壊れてしまう (ko1)
 - ensure節実行中にterminateされたらensure抜けてしまうので言語仕様としてつじつまがあってない (高尾さん)
 - sleepで寝ていても、もう一度例外が上がってきたら抜けるべきでは? (← これよくわからないが 
Ctrl-Cうけたらメインスレッドがthread terminateを再送しろということ?)
 - Ctrl-c 二連打で、終了処理がスッポ抜けるのって本当にうれしい?(こさき)
 - 現在、main threadがsub 
threadの終了を待つロジックがビジーループなのでCPU100%になってしまう。スレッドが終了するまでちゃんと寝るべきではないのか
   (やや脱線)

ぐらいですかね。

----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33934

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: High
Assignee: kosaki (Motohiro KOSAKI)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by kosaki (Motohiro KOSAKI) (Guest)
on 2012-11-26 14:41
(Received via mailing list)
Issue #5368 has been updated by kosaki (Motohiro KOSAKI).


なお、#1952 ですでに指摘されているように Ctrl-c 
が押された時にサブスレッドを待たずに終了してしまうという案はSEGVを引き起こすのでNG。
----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33957

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: High
Assignee: kosaki (Motohiro KOSAKI)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by kosaki (Motohiro KOSAKI) (Guest)
on 2012-11-26 15:00
(Received via mailing list)
Issue #5368 has been updated by kosaki (Motohiro KOSAKI).

Status changed from Closed to Assigned
Assignee changed from kosaki (Motohiro KOSAKI) to matz (Yukihiro 
Matsumoto)
Priority changed from High to Normal

現状、ささださんが 
#1にてCPU使用率が跳ね上がるのだけがバグで、終わらない、かつCtrl-Cも効かなくなるのは仕様という見解を出しているのでそれにそって、r37865でCPU使用率問題を直しました。
さて、このまま閉じてしまっていいのかまったく分からないので、まつもとさん意見をください。

元の起票バグだとensureで無限sleepというちょっとありえなさそうなスクリプトですが、IO.read 
などでも同様の「終了しない+Ctrl-C効かない」が起こります。これはCtrl-Cが絶対メインスレッドに飛ぶのでサブスレッドが起きれないから。それでも構わないということであれば 
closeしてください。

だめだと思っている場合は、どのような動作がいいと思っているか教えてください

[Feature #1952] の #12でmameさんが選択肢をいくつか列挙してくれていて

>    捕捉できない例外を投げる
>    - サブスレッドの ensure が実行されない危険が緩和されるが
>      本質的に解決はしない。あとダサい
>
> くらいを思いつきましたが、どれも問題がある or 面倒ですね。

とかいうコメントがついています。[Feature #1952]全体を一度読みなおしてからコメントいただけるとなおありがたい

----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33960

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by kosaki (Motohiro KOSAKI) (Guest)
on 2012-11-26 17:16
(Received via mailing list)
Issue #5368 has been updated by kosaki (Motohiro KOSAKI).


1.8 だと、Ctrl-C 
でsleepを抜けてくれるようです。うーん、この挙動のほうがいいんかなあ。1.8がどういう理屈でこう動いているのかよくわからないんだけど、ようするにInterruptがmain 
threadではなく、たまたまその時動いていたThreadに飛ぶようなシロモノだったということだろうか(推測)
----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33966

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by kosaki (Motohiro KOSAKI) (Guest)
on 2012-11-26 17:26
(Received via mailing list)
Issue #5368 has been updated by kosaki (Motohiro KOSAKI).

% Done changed from 100 to 50


----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33967

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by tarui (Masaya Tarui) (Guest)
on 2012-11-26 21:12
(Received via mailing list)
Issue #5368 has been updated by tarui (Masaya Tarui).


1.8の挙動の方がバグっぽいですけれどねぇ
Ctrl-Cでensureの実行が保証されず、終わってしまうのは大きな問題だと思います。
現にTimeoutでensureが飛ばされるので困ってcontrol_interruptをなどを導入しようと
しているのだと理解しています。kill -KILLしないと死なないプロセスは良くある事で、
これはensureを必ず実行しようとする事とのトレードオフだと思います。

デフォルトでの挙動ではCtrl-CでIntrrupt例外を再送するようにして、
ensure節中ではIntrrupt例外に対して:on_blockingにしておいてやると、
ユーザーが望めば:neverにする事が出来て実行が保証でき、かつ普通にensureを書いてる分には
Ctrl-C連打で上記sleepやio待ちもキャンセル出来て良いんじゃないでしょうか?
(:immediateだと設定を変えようとしてる間に例外が飛んで来て飛ばされる可能性があるので)

----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33979

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by kosaki (Motohiro KOSAKI) (Guest)
on 2012-11-27 00:14
(Received via mailing list)
Issue #5368 has been updated by kosaki (Motohiro KOSAKI).


[Feature #1952]の対策として、r37875でCtrl-Cが押されるたびに 
eTerminateSignalを最送出するようにしたので、現状1.8と同等の動きをするようになってます。

----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33988

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by kosaki (Motohiro KOSAKI) (Guest)
on 2012-11-27 00:17
(Received via mailing list)
Issue #5368 has been updated by kosaki (Motohiro KOSAKI).


1.8と同等と書いたのは

Thread.new do
  begin
    sleep
  ensure
    sleep
  end
end

というプログラムが一度ensure節のsleepで寝てしまうが、Ctrl-Cにより終わることは出来る。という挙動を指しており、
このスクリプト以外の細かい挙動について、不整合はあると思います。


----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-33990

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by kosaki (Motohiro KOSAKI) (Guest)
on 2012-11-27 18:08
(Received via mailing list)
Issue #5368 has been updated by kosaki (Motohiro KOSAKI).


> なお、#1952 ですでに指摘されているように Ctrl-c が押された時にサブスレッドを待たずに終了してしまうという案はSEGVを引き起こすのでNG。

もうちょっとまじめに書くと、SEGVを引き起こすのは終了処理でまじめに1つ1つリソース解放処理をしてるからで、いきなりexit()するという選択肢はあるだろう。しかしそれは当然MVMにしたときに問題を引き起こす。
SEGVしないように各所にNULLチェックを入れるという案については、pthread_cond_destruct()が別スレッドがリソース使用中に呼び出されるとEBUSYで失敗するためうまくいかない
----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-34052

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 2.0.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Posted by ko1 (Koichi Sasada) (Guest)
on 2013-02-17 07:26
(Received via mailing list)
Issue #5368 has been updated by ko1 (Koichi Sasada).

Assignee changed from matz (Yukihiro Matsumoto) to kosaki (Motohiro 
KOSAKI)
Target version changed from 2.0.0 to 2.1.0

2.1 で結論を付けたいところ。
多分、まつもとさんはこの辺気にしないと思うので、小崎さん、たるいさん(と私かなぁ)で決めると良いと思います。
----------------------------------------
Bug #5368: ensure節でsleepするようなThreadがあるとインタプリタが終了しない
https://bugs.ruby-lang.org/issues/5368#change-36400

Author: Glass_saga (Masaki Matsushita)
Status: Assigned
Priority: Normal
Assignee: kosaki (Motohiro KOSAKI)
Category: core
Target version: 2.1.0
ruby -v: -


=begin
次のコードを実行するとCPU使用率が跳ね上がった状態になりインタプリタが終了しません。

 Thread.new do
   begin
     sleep
   ensure
     sleep
   end
 end

現在のrb_thread_terminate_allでは最初に1回だけ生きているスレッドに対してterminate_iを実行していますが、ensure節でsleepするようなThreadがあると、そのThreadは寝たままになってしまいwhile(!rb_thread_alone())が無限ループになってしまいます。

while(!rb_thread_alone())の毎回のループでカレントスレッドがメインスレッドであった場合に、生きているスレッドに対してterminate_iを実行するようなpatchを書いたところ、このバグは再現しなくなりました。
patchを添付します。patchの適用後もtest-allをパスします。
=end
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.