celluloid / celluloid-io

UNMAINTAINED: See celluloid/celluloid#779 - Evented sockets for Celluloid actors
https://celluloid.io
MIT License
879 stars 93 forks source link

Ensure monitor is closed after task is resumed, fixes #121. #122

Closed ioquatix closed 9 years ago

ioquatix commented 9 years ago

I tried using "ensure" block but it caused segfault. Not sure why. I only tested locally with 2.0.0 which had the bug. Perhaps you can suggest how to write a failing spec for this edge case.

ioquatix commented 9 years ago

@tarcieri I'm pretty sure this is faulty without ensure since heaps of exceptions will get thrown back out, but I'm not sure if that's the correct behaviour or not. When I print out exceptions, I see the following before the segfault:

From the code:

    monitor = @selector.register(io, set)
    monitor.value = Task.current
    Task.suspend :iowait
  ensure
    puts "Exception: #{$!}"
    monitor.close
  end

I get:

Exception: task was terminated
/Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-io-0.16.1/lib/celluloid/io/reactor.rb:47: [BUG] Segmentation fault
ruby 2.0.0p576 (2014-09-19 revision 47628) [x86_64-darwin14.0.0]

-- Crash Report log information --------------------------------------------
   See Crash Report log file under the one of following:
     * ~/Library/Logs/CrashReporter
     * /Library/Logs/CrashReporter
     * ~/Library/Logs/DiagnosticReports
     * /Library/Logs/DiagnosticReports
   the more detail of.

-- Control frame information -----------------------------------------------
c:0018 p:---- s:0060 e:000059 CFUNC  :close
c:0017 p:0019 s:0057 e:000056 RESCUE /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-io-0.16.1/lib/celluloid/io/reactor.rb:47
c:0016 p:0193 s:0054 e:000052 METHOD /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-io-0.16.1/lib/celluloid/io/reactor.rb:47
c:0015 p:0011 s:0047 e:000046 METHOD /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-io-0.16.1/lib/celluloid/io/reactor.rb:21
c:0014 p:0050 s:0043 e:000042 METHOD /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-io-0.16.1/lib/celluloid/io.rb:53
c:0013 p:0018 s:0038 e:000037 METHOD /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-io-0.16.1/lib/celluloid/io/tcp_server.rb:19
c:0012 p:0012 s:0035 e:000033 BLOCK  /Users/samuel/Documents/Programming/Internet/rubydns/lib/rubydns/handler.rb:150 [FINISH]
c:0011 p:---- s:0032 e:000031 CFUNC  :loop
c:0010 p:0007 s:0029 e:000028 METHOD /Users/samuel/Documents/Programming/Internet/rubydns/lib/rubydns/handler.rb:150 [FINISH]
c:0009 p:---- s:0026 e:000025 CFUNC  :public_send
c:0008 p:0040 s:0021 e:000020 METHOD /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-0.16.0/lib/celluloid/calls.rb:26
c:0007 p:0031 s:0016 e:000015 METHOD /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-0.16.0/lib/celluloid/calls.rb:122
c:0006 p:0011 s:0011 e:000010 BLOCK  /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-0.16.0/lib/celluloid/cell.rb:60
c:0005 p:0041 s:0009 e:000008 BLOCK  /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-0.16.0/lib/celluloid/cell.rb:71
c:0004 p:0026 s:0007 e:000006 BLOCK  /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-0.16.0/lib/celluloid/actor.rb:357
c:0003 p:0073 s:0005 e:000004 BLOCK  /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-0.16.0/lib/celluloid/tasks.rb:57
c:0002 p:0060 s:0003 e:000002 BLOCK  /Users/samuel/.rvm/gems/ruby-2.0.0-p576/gems/celluloid-0.16.0/lib/celluloid/tasks/task_fiber.rb:15 [FINISH]
c:0001 p:---- s:0001 e:000000 ------
ioquatix commented 9 years ago

I'm wondering if this is because "task was exited" means that the reactor has already been shut down and the monitor is no longer valid?

tarcieri commented 9 years ago

This looks like a bug in the C extension of nio4r

ioquatix commented 9 years ago

@tarcieri Are you able to check nio4r and find out what is going on?

tarcieri commented 9 years ago

I can take a look tonight. Knowing the ordering of events or a simple repro of the crash would be helpful

ioquatix commented 9 years ago

RubyDNS has a spec which reproduces the crash systematically on Ruby 2.0.0 but not other versions.

https://github.com/ioquatix/rubydns/blob/master/spec/rubydns/celluloid_bug_spec.rb

ioquatix commented 9 years ago

@tarcieri Here is the requested PR. https://github.com/celluloid/celluloid-io/issues/121

@TiagoCardoso1983 are you able to test too?

I was considering that it would be nice if there was a better way of catching the TerminatedError. It sort of seems.. ugly..

ioquatix commented 9 years ago

@tarcieri I've added a spec which fails before the patch and passes afterwards, it's based on @TiagoCardoso1983's example, but it's structured using a module which you didn't like in the past, please feel free to modify to suit whatever structure you like.

ioquatix commented 9 years ago

I've run RubyDNS tests against this PR and they are all passing too which is a good sign since RubyDNS IMHO pushes Celluloid pretty hard.

ioquatix commented 9 years ago

Odd transient failing case on Travis: https://travis-ci.org/celluloid/celluloid-io/jobs/43071935

  1) Celluloid::IO behaves like a Celluloid Actor using Threads timers schedules recurring timers which fire in the future
     Failure/Error: actor.fired.should be 3
     fatal:
       No live threads left. Deadlock?
     Shared Example Group: "a Celluloid Actor" called from ./spec/celluloid/io/actor_spec.rb:4
     # /home/travis/.rvm/rubies/ruby-2.0.0-p594/lib/ruby/2.0.0/thread.rb:72:in `sleep'
     # /home/travis/.rvm/rubies/ruby-2.0.0-p594/lib/ruby/2.0.0/thread.rb:72:in `block (2 levels) in wait'
     # /home/travis/.rvm/rubies/ruby-2.0.0-p594/lib/ruby/2.0.0/thread.rb:68:in `handle_interrupt'
     # /home/travis/.rvm/rubies/ruby-2.0.0-p594/lib/ruby/2.0.0/thread.rb:68:in `block in wait'
     # /home/travis/.rvm/rubies/ruby-2.0.0-p594/lib/ruby/2.0.0/thread.rb:66:in `handle_interrupt'
     # /home/travis/.rvm/rubies/ruby-2.0.0-p594/lib/ruby/2.0.0/thread.rb:66:in `wait'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/mailbox.rb:62:in `block in check'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/timers-4.0.1/lib/timers/wait.rb:14:in `for'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/mailbox.rb:57:in `check'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/mailbox.rb:75:in `block in receive'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/timers-4.0.1/lib/timers/wait.rb:14:in `for'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/mailbox.rb:74:in `receive'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/calls.rb:113:in `block in wait'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/calls.rb:112:in `loop'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/calls.rb:112:in `wait'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid.rb:117:in `suspend'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/calls.rb:104:in `response'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/calls.rb:108:in `value'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/proxies/sync_proxy.rb:33:in `method_missing'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/bundler/gems/celluloid-c31d1e9277db/lib/celluloid/rspec/actor_examples.rb:857:in `block (3 levels) in <top (required)>'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:114:in `instance_eval'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:114:in `block in run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:254:in `with_around_each_hooks'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:111:in `run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:390:in `block in run_examples'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:386:in `map'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:386:in `run_examples'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:371:in `run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `block in run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `map'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `block in run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `map'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `block in run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `map'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:28:in `block (2 levels) in run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:28:in `map'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:28:in `block in run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/reporter.rb:58:in `report'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:25:in `run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:80:in `run'
     # /home/travis/.rvm/gems/ruby-2.0.0-p594/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:17:in `block in autorun'
HoneyryderChuck commented 9 years ago

@ioquatix , I'm on it.

HoneyryderChuck commented 9 years ago

@ioquatix , I've rewritten your spec, but cannot push to your branch. Can one "pull-request" to a "pull-request"? :)

HoneyryderChuck commented 9 years ago

github, still amazing me...

ioquatix commented 9 years ago

Thansks to @TiagoCardoso1983 we now have a better spec.

ioquatix commented 9 years ago

@tarcieri I believe we are good to go on this one.