Bug #3182
multi-irb may run parallelly
| Status: | Closed | Start date: | 04/21/2010 | |
|---|---|---|---|---|
| Priority: | Normal | Due date: | ||
| Assignee: | % Done: | 100% |
||
| Category: | lib | |||
| Target version: | 1.9.2 | |||
| ruby -v: | ruby 1.9.2dev (2010-04-21 trunk 27432) [i686-linux] |
Description
いしつかさん
遠藤です。
#3139 で、irb が SEGV するという報告が上がっています。
こんな感じで再現するらしいです。
irb String
irb Array
kill String
jobs
jobs
jobs #=> SEGV
私の環境で再現はしないのですが、同じ手順を実行すると、kill したあとで、
キー入力が不思議な挙動になりました。
irb(main):001:0> irb String
irb#1(String):001:0> irb Array
irb#2(Array):001:0> kill String
=> #<IRB::Irb: @context=#<IRB::Context:0x84096bc>, @signal_status=:IN_EVAL, @scanner=#<RubyLex:0x84080a0>>
irb(main):002:0> => [String]
irb#2(Array):002:0> j
NameError: undefined local variable or method `j' for main:Object
from (irb):2
from ../ruby-trunk-local/bin/irb:12:in `<main>'
irb(main):003:0> obs
NameError: undefined local variable or method `obs' for main:Object
from (irb):3
from ../ruby-trunk-local/bin/irb:12:in `<main>'
調べてみたところ、multi-irb で複数の irb のスレッドが同時に走り出して
いて、複数のスレッドから Readline.readline を呼ぶため入力の奪い合いに
なっているようです。
たぶん、これが報告者の環境では SEGV になったのではないかと予想します
(再現しないのでわからないですが) 。
SEGV はおいといて、複数の irb スレッドが走りだすのは multi-irb のバグ
だと思います。
irb が終了したときに、親の irb スレッドを run するコードがありますが、
kill された時は kill した irb スレッドがすでに走っているので、親を run
させるべきでないと思います。
以下のように、kill された irb 一覧を保持しておいて、kill された irb の
終了時には親を起こさないようにしたところ、不思議な挙動はなくなりました。
diff --git a/lib/irb/ext/multi-irb.rb b/lib/irb/ext/multi-irb.rb
index 7bb1a7c..df9c789 100644
--- a/lib/irb/ext/multi-irb.rb
+++ b/lib/irb/ext/multi-irb.rb
@@ -19,6 +19,7 @@ module IRB
def initialize
# @jobs = [[thread, irb],...]
@jobs = []
+ @killed_irbs = {}
@current_job = nil
end
@@ -64,6 +65,7 @@ module IRB
for key in keys
th, irb = search(key)
IRB.fail IrbAlreadyDead unless th.alive?
+ @killed_irbs[irb] = true
th.exit
end
end
@@ -104,6 +106,7 @@ module IRB
end
until assoc = @jobs.pop; end unless @jobs.empty?
@jobs.push assoc
+ @killed_irbs.delete(key)
end
def inspect
@@ -171,7 +174,7 @@ module IRB
#fail
ensure
unless system_exit
- @JobManager.delete(irb)
+ unless @JobManager.delete(irb)
if parent_thread.alive?
@JobManager.current_job = @JobManager.irb(parent_thread)
parent_thread.run
@@ -179,6 +182,7 @@ module IRB
@JobManager.current_job = @JobManager.main_irb
@JobManager.main_thread.run
end
+ end
end
end
end
--
Yusuke Endoh <mame@tsg.ne.jp>
Related issues
Associated revisions
* lib/irb/ext/multi-irb.rb: fix multi-irb running
parallelly. [ruby-dev:41031] [Bug #3182]
* lib/irb/ext/multi-irb.rb: fix multi-irb running
parallelly. [ruby-dev:41031] [Bug #3182]
History
Updated by keiju (Keiju Ishitsuka) about 2 years ago
けいじゅ@いしつかです. In [ruby-dev:41031] the message: "[ruby-dev:41031] [Bug #3182] multi-irb may run parallelly", on Apr/21 20:54(JST) Yusuke Endoh writes: >いしつかさん >遠藤です。 >私の環境で再現はしないのですが、同じ手順を実行すると、kill したあとで、 >キー入力が不思議な挙動になりました。 > > irb(main):001:0> irb String > irb#1(String):001:0> irb Array > irb#2(Array):001:0> kill String > => #<IRB::Irb: @context=#<IRB::Context:0x84096bc>, @signal_status=:IN_EVAL, @scanner=#<RubyLex:0x84080a0>> > irb(main):002:0> => [String] > irb#2(Array):002:0> j > NameError: undefined local variable or method `j' for main:Object > from (irb):2 > from ../ruby-trunk-local/bin/irb:12:in `<main>' > irb(main):003:0> obs > NameError: undefined local variable or method `obs' for main:Object > from (irb):3 > from ../ruby-trunk-local/bin/irb:12:in `<main>' >SEGV はおいといて、複数の irb スレッドが走りだすのは multi-irb のバグ >だと思います。 確かに. >irb が終了したときに、親の irb スレッドを run するコードがありますが、 >kill された時は kill した irb スレッドがすでに走っているので、親を run >させるべきでないと思います。 > >以下のように、kill された irb 一覧を保持しておいて、kill された irb の >終了時には親を起こさないようにしたところ、不思議な挙動はなくなりまし >た。 確かにこれでもよい気がしますが, 単純に その終了するsubirbがカレントジョ ブの時のみカレントジョブの置き換えをするようにするで十分なようです. こ ちらのパッチを採用したいと思います. --- lib/irb/ext/multi-irb.rb (リビジョン 27443) +++ lib/irb/ext/multi-irb.rb (作業コピー) @@ -172,12 +172,14 @@ ensure unless system_exit @JobManager.delete(irb) - if parent_thread.alive? - @JobManager.current_job = @JobManager.irb(parent_thread) - parent_thread.run - else - @JobManager.current_job = @JobManager.main_irb - @JobManager.main_thread.run + if @JobManager.current_job == irb + if parent_thread.alive? + @JobManager.current_job = @JobManager.irb(parent_thread) + parent_thread.run + else + @JobManager.current_job = @JobManager.main_irb + @JobManager.main_thread.run + end end end end __ ---------------------------------------------------->> 石塚 圭樹 <<--- ---------------------------------->> e-mail: keiju@ishitsuka.com <<---
Updated by keiju (Keiju Ishitsuka) about 2 years ago
- Status changed from Open to Closed
- % Done changed from 0 to 100
This issue was solved with changeset r27444. Yusuke, thank you for reporting this issue. Your contribution to Ruby is greatly appreciated. May Ruby be with you.