I'm working on updating a gem to be compatible with Ruby 2.0 and am currently using Ruby 2.0.0-preview2. I'm running into trouble with a class which inherits from GServer and I think it's related to this bug and subsequent patch <https://bugs.ruby-lang.org/issues/6416>. Please look at the gist:https://gist.github.com/4424479 Using Ruby <= 1.9.3, when sending an interrupt signal this code would exit cleanly. Using Ruby 2.0, an exception is thrown on launcher.stop: ~/.rvm/rubies/ruby-2.0.0-preview2/lib/ruby/2.0.0/gserver.rb:116:in `synchronize': can't be called from trap context (ThreadError) from ~/.rvm/rubies/ruby-2.0.0-preview2/lib/ruby/2.0.0/gserver.rb:116:in `stop' As you can see, I am not explicitly calling 'join' in the trap context but 'synchronize' is called as part of GServer#close gserver.rb 114 # Stop the server 115 def stop 116 @connectionsMutex.synchronize { 117 if @tcpServerThread 118 @tcpServerThread.raise "stop" 119 end 120 } 121 end I'm open to any ideas or suggestions. Thanks!
on 2013-01-01 17:21
on 2013-01-04 14:45
On Tue, Jan 1, 2013 at 4:20 PM, Joe Leo <joseph.leo3@gmail.com> wrote: > `synchronize': can't be called from trap context (ThreadError) > from > ~/.rvm/rubies/ruby-2.0.0-preview2/lib/ruby/2.0.0/gserver.rb:116:in > `stop' > I can confirm this is new behaviour in 2.0.0-preview2 - it also happens when you use Queue#enq from within a trap handler (which is an issue for me unfortunately). You could use a variant of the self-pipe trick to signal a thread as in the example below. Regards, Sean. # CODE require "gserver" # example server class MyServer < GServer def initialize(port=10001, *args) super(port, *args) end def serve(io) io.puts(Time.now.to_s) end end class Launcher def initialize(servers) @servers = servers end def start @servers.each { |server| server.start } end def join @servers.each { |server| server.join } end def stop @servers.each { |server| server.stop } end end servers = [MyServer.new] launcher = Launcher.new(servers) # create self-pipe p_read, p_write = IO.pipe Thread.start(launcher, p_read) do |l, pr| pr.read # blocks until write end closed pr.close l.stop exit end launcher.start trap("SIGINT") { p_write.close } # close pipe to signal thread launcher.join
on 2013-01-05 01:51
Wow, this is a really interesting (and effective) solution. Reading the docs on IO.pipe (http://www.ruby-doc.org/core-1.9.3/IO.html) this looks pretty safe. And it works on Ruby 1.9.3 and 2.0.0-preview2. My objective was to clean up my resources when the program receives a SIGTERM. (As a counter example, calling "exit!" inside the original trap context in my gist would have successfully killed my program without throwing an exception but would not have cleaned up the utilized resources.) There is the ominous "does not work on all systems" warning with this method, but if I can test it out on some of the major ones successfully, I'll go with it. For what it's worth, I've filed my issue with ruby-core here: http://bugs.ruby-lang.org/issues/7648. It hasn't gained any traction yet, but if you want to post your own experience with Queue#enq it might be an addendum to this bug report or a new bug altogether. Thanks for your help! This was educational. Joe
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
Log in with Google account | Log in with Yahoo account
No account? Register here.