Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FiberError: dead fiber called (when non-main threads are killed) #2778

Closed
e2 opened this issue Mar 30, 2015 · 2 comments
Closed

FiberError: dead fiber called (when non-main threads are killed) #2778

e2 opened this issue Mar 30, 2015 · 2 comments

Comments

@e2
Copy link

e2 commented Mar 30, 2015

Actual code that likely caused #2773

On jruby-head, the following either throws a "FiberError (dead fiber error)" exception, or never runs the second fiber:

class Task
  def resume
    fiber = Fiber.new { fail NotImplementedError }
    fiber.resume
  end
end

begin
  STDERR.print "resuming... "
  Task.new.resume
rescue NotImplementedError
  STDERR.puts "OK"
end

extra_threads = Thread.list.reject { |th| th == Thread.main }
extra_threads.map(&:kill) # NOTE: extra thread only on JRuby (fiber thread)

begin
  STDERR.print "resuming... "
  Task.new.resume
rescue NotImplementedError
  STDERR.puts "OK"
end

Expected (e.g. on MRI):

$ ruby fiber.rb
resuming... OK
resuming... OK

Actual (on jruby-head):

$ ruby fiber.rb
resuming... OK
resuming... 

The problem: Fibers on JRuby are implemented with threads, but these fiber-related threads shouldn't be exposed through Thread.list (or Thread.main or Thread.current).

@headius
Copy link
Member

headius commented Apr 2, 2015

It is not currently possible for us to implement fibers without exposing a Ruby thread, because thread-level structures are used to coordinate communication between fibers. So you may have to accept that fiber threads are going to be present in Thread.list.

What is this code for? Killing all threads in the system seems like an incredibly dangerous thing to do, and Thread#kill can cause ensures and resource cleanup code to not run.

See http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html

@e2
Copy link
Author

e2 commented Apr 2, 2015

So you may have to accept that fiber threads are going to be present in Thread.list.

I thought it wouldn't be worth the effort, but I didn't know Thread.list was internally relied upon. Good to know it won't go away.

What is this code for?

Cross-platform attempt inside a test env to make sure all threads created during tests are killed before starting the next test.

All I really need is to distinguish "app" threads from "JRuby" threads. Custom fields in thread-local storage is the best solution I guess (to differentiate).

See http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html

Thanks! I wish I saw that years earlier. (HTML on the page is borked, but it's all very relevant).

I pretty much use Thread#kill and Thread#raise only when I can guarantee the thread will be joined (and only in extreme cases, e.g. for catching Ctrl-C and passing it to a background job). And only to make things single-threaded again (joined with the main thread). And killing/raising only when the thread is actually sleeping.

Other than that I rely on queues as much as possible.

Anyway, don't let this bother you - thread-local storage solves this for me.

@e2 e2 closed this as completed Apr 2, 2015
@enebo enebo added this to the Invalid or Duplicate milestone Apr 28, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants