[ruby-core:62591] [ruby-trunk - Bug #9835] IGNORE signal handler has possible race condition in Ruby 2.1.2

From: normalperson@...
Date: 2014-05-14 19:28:38 UTC
List: ruby-core #62591
Issue #9835 has been updated by Eric Wong.


 It looks like a race condition in your code.  You were lucky to not hit
 it in 1.8.7 or with a different use of trap (because execution speeds
 may be different different).
 
     parent execution timeline
     -----------------------------+
     trap(USR1, show_children)    |
                                  |
     fork ------------------------+-- child execution timeline -----
                                  |
     *** kill(USR1, -getpgid($$)) | trap(USR1, IGNORE)
                                  |
 
 Once you fork, parent and child run in parallel.  So the order of
 execution where '***' is highlighted is outside your control.
 
 So to ensure your child ignores properly, you must setup the ignore
 handler before forking.  There will always be a moment in time where
 the parent and child will have the same signal handler.
 
 You also do not want to a signal in the parent which arrive immediately
 before or after the fork, either.  So I suggest something like the
 following to defer signals in the parent:
 
     # note: this count nals in general) is racy
     usr1_queue = []
     show_children = trap("USR1") { usr1_queue << nil } # defer signals
     pid = fork
     if pid # parent
       trap("USR1", show_children) # restore immediate handling
 
       # process deferred signals
       usr1_queue.each { show_children.call }
       usr1_queue.clear
       ...
     else # child
       trap("USR1", "IGNORE")
       # do nothing with usr1_queue here, implicitly ignored
       ...
     end

----------------------------------------
Bug #9835: IGNORE signal handler has possible race condition in Ruby 2.1.2
https://bugs.ruby-lang.org/issues/9835#change-46734

* Author: Kyle Smith
* Status: Rejected
* Priority: Low
* Assignee: 
* Category: core
* Target version: 
* ruby -v: ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------
I'm migrating an application from 1.8.7 to 2.1.1/2.1.2, so I'm not sure when this was introduced.  Attached is a demo program with some notes about how the IGNORE option to Signal.trap seems to have a race condition whereby receiving that signal shortly after that call, it raises a SignalException with the message including only the name of the signal it received.  However, if you trap the signal with an empty block, that race does not occur.

I've tested the attached program on 1.8.7 (no issue), 2.1.1 (issue) and 2.1.2 (issue) on a Linux system (Ubuntu lucid).

---Files--------------------------------
test.rb (1.37 KB)


-- 
https://bugs.ruby-lang.org/

In This Thread

Prev Next