Bug #6416

Deadlock when calling Thread#join from signal interrupt context

Added by Timothy Elliott about 3 years ago. Updated over 2 years ago.

[ruby-core:44956]
Status:Closed
Priority:Normal
Assignee:Motohiro KOSAKI
ruby -v:ruby 2.0.0dev (2012-05-09 trunk 35598) [x86_64-linux] Backport:

Description

=begin
The interpreter can deadlock when calling Thread#join both from the main context and from the signal handler context.

t = Thread.new{ sleep 3 }

Signal.trap "SIGINT" do
t.join
end

puts 'Press ctrl + c now'
t.join

The above will deadlock on linux x86_64 with ruby 1.9.x and ruby trunk. It works fine with ruby 1.8.7-p352 and JRuby.

=end

Associated revisions

Revision 37852
Added by Motohiro KOSAKI over 2 years ago

  • vm_core.h (rb_thread_struct): added 'in_trap' member for marking running trap handler.
  • signal.c (signal_exec): turn on in_trap when running trap.
  • thread.c (Init_Thread, thread_create_core): initialize in_trap when creating new threads.
  • thread.c (thread_join_m): raise ThreadError when running trap handler.Bug [#6416]
  • test/ruby/test_thread.rb (test_thread_join_in_trap): new test for the above.

Revision 37852
Added by Motohiro KOSAKI over 2 years ago

  • vm_core.h (rb_thread_struct): added 'in_trap' member for marking running trap handler.
  • signal.c (signal_exec): turn on in_trap when running trap.
  • thread.c (Init_Thread, thread_create_core): initialize in_trap when creating new threads.
  • thread.c (thread_join_m): raise ThreadError when running trap handler.Bug [#6416]
  • test/ruby/test_thread.rb (test_thread_join_in_trap): new test for the above.

History

#1 Updated by Yusuke Endoh about 3 years ago

  • Status changed from Open to Assigned
  • Assignee set to Motohiro KOSAKI

Kosaki-san, could you take a look?

Yusuke Endoh mame@tsg.ne.jp

#2 Updated by Motohiro KOSAKI about 3 years ago

  • Assignee changed from Motohiro KOSAKI to Koichi Sasada

Hi ko1,

This is because thread_join() is not designed reentrant. It can insert a thread twice join_list. And then, join_list
is going to become circular ring and it lead to deadlock.

So, I think th.join in trap context should raise ThreadError. What do you think?

#3 Updated by Koichi Sasada over 2 years ago

  • Target version set to 2.0.0

Please give me a time.

#4 Updated by Koichi Sasada over 2 years ago

  • Assignee changed from Koichi Sasada to Motohiro KOSAKI

I agree with kosaki-san's comment.

#5 Updated by Motohiro KOSAKI over 2 years ago

  • Status changed from Assigned to Closed

Fixed at r37852.
Thanks, Timothy!

#6 Updated by Narihiro Nakamura over 2 years ago

Hello

I need sometimes to call Thread#join in Signal.trap when I want to implement safe termination in a server.
For instance: https://gist.github.com/4158509

Is it a wrong use case in the first place?

Thanks.

#7 Updated by Motohiro KOSAKI over 2 years ago

Nari,

In your case, main thread and trap handler uses the same mutex and it is racy and deadlockable. Even if I revert my change, it wouldn't work.

#8 Updated by Narihiro Nakamura over 2 years ago

kosaki (Motohiro KOSAKI) wrote:

Nari,

In your case, main thread and trap handler uses the same mutex and it is racy and deadlockable. Even if I revert my change, it wouldn't work.

I see, Thanks!

Also available in: Atom PDF