Bug #8433

Mutexes held by background threads at fork not always released

Added by Ben Weintraub 11 months ago. Updated about 1 month ago.

[ruby-core:55102]
Status:Closed
Priority:Normal
Assignee:-
Category:-
Target version:-
ruby -v:ruby 2.0.0p195 (2013-05-14 revision 40734) [x86_64-darwin12.3.0] Backport:1.9.3: DONE, 2.0.0: DONE

Description

It appears that the Ruby interpreter attempts to automatically unlock Mutexes held by background threads at the time Process.fork is called in order to avoid deadlocks in the child process. Unfortunately, the logic for doing so appears unreliable.

Reproduction steps:
1. Download the attached mutex_fork.rb
2. Run it

Expected results:
The program should just spin indefinitely, producing no output.

Actual results:
A deadlock is produced, and the following output is seen:

$ ./mutexfork.rb
./mutex
fork.rb:14:in synchronize': No live threads left. Deadlock? from ./mutex_fork.rb:14:inblock (2 levels) in '
from ./mutexfork.rb:13:in fork'
from ./mutex_fork.rb:13:in
block in '
from ./mutex
fork.rb:11:in loop'
from ./mutex_fork.rb:11:in
'

Notes:
The child process is deadlocking when attempting to acquire the mutex that was held by a background thread in the parent at the time Process.fork was called. rbmutexabandonall appears to be intended to prevent this problem, but is not reliable as demonstrated by this test case. I suspect that the fork happens after the background thread has acquired the mutex, but before it has updated its keepingmutexes list, so upon fork, the forking thread does not realize that it should abandon this mutex.

Note that the Mutex#synchronize call on line 12 (just prior to the Process.fork call) is critical to reproduction here. Removing it causes the program to behave correctly.

mutex_fork.rb Magnifier (235 Bytes) Ben Weintraub, 05/22/2013 02:52 AM

Associated revisions

Revision 43148
Added by Nobuyoshi Nakada 7 months ago

thread.c: fix some mutexes remaining locked after forking

  • thread.c (terminateatforki): fix locking mutexes not unlocked in forks when not tracked in thread. [Bug #8433]

Revision 43149
Added by Nobuyoshi Nakada 7 months ago

thread.c: fix some mutexes remaining locked after forking

  • thread.c (terminateatforki): fix locking mutexes not unlocked in forks when not tracked in thread. [Bug #8433]

History

#1 Updated by Aaron Pfeifer 7 months ago

I've submitted a proposed patch for this issue at https://github.com/ruby/ruby/pull/415 . This seems to have done the trick for me running it through some basic tests, including the one you posted.

#2 Updated by Nobuyoshi Nakada 6 months ago

  • % Done changed from 0 to 100
  • Status changed from Open to Closed

This issue was solved with changeset r43148.
Ben, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


thread.c: fix some mutexes remaining locked after forking

  • thread.c (terminateatforki): fix locking mutexes not unlocked in forks when not tracked in thread. [Bug #8433]

#3 Updated by Aaron Pfeifer 6 months ago

Thank you for the quick response! Any chance this will be backported to 1.9.3?

#4 Updated by Nobuyoshi Nakada 6 months ago

  • Backport changed from 1.9.3: UNKNOWN, 2.0.0: UNKNOWN to 1.9.3: REQUIRED, 2.0.0: REQUIRED

#5 Updated by Usaku NAKAMURA 2 months ago

  • Backport changed from 1.9.3: REQUIRED, 2.0.0: REQUIRED to 1.9.3: DONE, 2.0.0: REQUIRED

r43148, r43149, and r43152 are backported into ruby19_3 at r45026.

#6 Updated by Tomoyuki Chikanaga about 1 month ago

  • Backport changed from 1.9.3: DONE, 2.0.0: REQUIRED to 1.9.3: DONE, 2.0.0: DONE

r43148, r43149, and r43152 were backported to ruby20_0 at r45049.

Also available in: Atom PDF