Project

General

Profile

« Previous | Next » 

Revision b2e84819

Added by ko1 (Koichi Sasada) over 2 years ago

fix deadlock on Thread#join

because of 9720f5ac894566ade2aabcf9adea0a3235de1353

http://rubyci.s3.amazonaws.com/solaris11-sunc/ruby-master/log/20230403T130011Z.fail.html.gz

 1) Failure: TestThread#test_signal_at_join [/export/home/chkbuild/chkbuild-sunc/tmp/build/20230403T130011Z/ruby/test/ruby/test_thread.rb:1488]: Exception raised: <#<fatal:"No live threads left. Deadlock?\n1 threads, 1 sleeps current:0x00891288 main thread:0x00891288\n* #<Thread:0xfef89a18 sleep_forever>\n rb_thread_t:0x00891288 native:0x00000001 int:0\n \n">> Backtrace: -:30:in `join' -:30:in `block (3 levels) in <main>' -:21:in `times' -:21:in `block (2 levels) in <main>'. 

The mechanism:

  • Main thread (M) calls Thread#join
  • M: calls sleep_forever()
  • M: set th->status = THREAD_STOPPED_FOREVER
  • M: do checkints
  • M: handle a trap handler with th->status = THREAD_RUNNABLE
  • M: thread switch at the end of the trap handler
  • Another thread (T) will process Thread#kill by M.
  • T: rb_threadptr_join_list_wakeup() at the end of T tris to wakeup M,
    but M's state is runnable because M is handling trap handler and
    just ignore the waking up and terminate T$a
  • T: switch to M.
  • M: after the trap handler, reset th->status = THREAD_STOPPED_FOREVER
    and check deadlock -> Deadlock because only M is living.

To avoid such situation, add new sleep flags SLEEP_ALLOW_SPURIOUS
and SLEEP_NO_CHECKINTS to skip any check ints.

BTW this is instentional to leave second vm_check_ints_blocking()
without checking SLEEP_NO_CHECKINTS because SLEEP_ALLOW_SPURIOUS
should be specified with SLEEP_NO_CHECKINTS and skipping this
checkints can skip any interrupts.