From: "akr (Akira Tanaka)" Date: 2013-08-15T13:42:06+09:00 Subject: [ruby-dev:47628] [ruby-trunk - Bug #8749] Readline.readline stops STDOUT? Issue #8749 has been updated by akr (Akira Tanaka). File readline-release-gvl-2.patch added no6v (Nobuhiro IMAI) wrote: > > 今回問題にした挙動は r42525 で一旦直って r42527 でまた壊れはしたものの > r42528 でまた直っているようです。これはたまたまでしょうか。 readline_getc で、rl_getc を呼び出すか、rb_io_getbyte を呼び出すかという条件判断が問題で、 前者なら GVL を離さないので他のスレッドは動けず、後者なら動けます。 r42525 で直ったのは、ifp->stdio_file に代入したので、readline_getc 内の if (rl_instream != ifp->stdio_file) return rl_getc(input); という条件が成立しなくなったためでしょう。 しかし、[ruby-dev:47608] で述べたように、ifp->stdio_file に readline 側で 作った FILE 構造体を代入すると、IO#close で解放されてしまって、ひいては SEGV になる可能性が出てきます。 r42527 は if 文で上記の ifp->stdio_file への代入をガードしていますが、 [ruby-dev:47609] で述べたように、その条件は決して成り立たないので、実質、 r42525 の revert のようなものです。 r42528 は if (rl_instream != ifp->stdio_file) return rl_getc(input); という文を削除していて、そのため、rl_getc じゃなくて下のほうに制御が行って、 rb_io_getbyte を呼び出すようになったのでしょう。 ここで rb_io_getbyte は readline_instream という IO オブジェクトから読むので、 それが input という FILE 構造体と対応しているのかという疑問があるわけで、 だからこそ対応していなかったら input から読むという処理が入っているのだと思いますが、 どういう理由かは知りませんが、消してしまっているようです。 > もちろん attachment:readline-release-gvl.patch を当てても動きます。 > (コンパイル時に以下の警告が出ました) > > compiling ../../../../git/ruby/ext/readline/readline.c > ../../../../git/ruby/ext/readline/readline.c: In function ‘check_ints’: > ../../../../git/ruby/ext/readline/readline.c:148:1: warning: no return statement in function returning non-void [-Wreturn-type] > } > ^ おっと、return NULL; を忘れていました。 つけたのを readline-release-gvl-2.patch として添付します。 ---------------------------------------- Bug #8749: Readline.readline stops STDOUT? https://bugs.ruby-lang.org/issues/8749#change-41168 Author: no6v (Nobuhiro IMAI) Status: Open Priority: Normal Assignee: kouji (Kouji Takao) Category: ext Target version: ruby -v: ruby 2.1.0dev (2013-08-06 trunk 42402) [x86_64-linux] Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN =begin r42402 で、以下のようなスクリプトの挙動が変わっています。 (Enter を押すかどうかは関係なくて、)Readline.readline を実行中に標準出力への出力が出来なくなっているように見えます。 $ cat rl.rb require "readline" th = Thread.new do p Readline.readline("> ") end loop do p :hi sleep 2 break unless th.alive? end $ ruby -v rl.rb ruby 2.1.0dev (2013-08-06 trunk 42401) [x86_64-linux] :hi > :hi :hi :hi :hi # しばらく放置してここで Enter "" $ ruby -v rl.rb $ /tmp/ruby/bin/ruby -v /tmp/r.rb ruby 2.1.0dev (2013-08-06 trunk 42402) [x86_64-linux] :hi > # しばらく放置してここで Enter "" $ =end -- http://bugs.ruby-lang.org/