[前][次][番号順一覧][スレッド一覧]

ruby-changes:24886

From: kosaki <ko1@a...>
Date: Sun, 9 Sep 2012 21:32:46 +0900 (JST)
Subject: [ruby-changes:24886] kosaki:r36938 (trunk): * lib/thread.rb (Queue#pop): Fixed double registration issue when

kosaki	2012-09-09 21:32:33 +0900 (Sun, 09 Sep 2012)

  New Revision: 36938

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=36938

  Log:
    * lib/thread.rb (Queue#pop): Fixed double registration issue when
      mutex.sleep is interrupted. [Bug #5258] [ruby-dev:44448]
    * lib/thread.rb (SizedQueue#push): ditto.
    
    * test/thread/test_queue.rb (test_sized_queue_and_wakeup,
    test_queue_pop_interrupt, test_sized_queue_pop_interrupt,
    test_sized_queue_push_interrupt): new tests.

  Modified files:
    trunk/ChangeLog
    trunk/lib/thread.rb
    trunk/test/thread/test_queue.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 36937)
+++ ChangeLog	(revision 36938)
@@ -1,3 +1,13 @@
+Sun Sep  9 21:21:15 2012  KOSAKI Motohiro  <kosaki.motohiro@g...>
+
+	* lib/thread.rb (Queue#pop): Fixed double registration issue when
+	  mutex.sleep is interrupted. [Bug #5258] [ruby-dev:44448]
+	* lib/thread.rb (SizedQueue#push): ditto.
+
+	* test/thread/test_queue.rb (test_sized_queue_and_wakeup,
+	test_queue_pop_interrupt, test_sized_queue_pop_interrupt,
+	test_sized_queue_push_interrupt): new tests.
+
 Sun Sep  9 20:20:31 2012  KOSAKI Motohiro  <kosaki.motohiro@g...>
 
 	* lib/sync.rb (Sync_m#sync_lock): Fixed wakeup/raise unsafe code.
Index: lib/thread.rb
===================================================================
--- lib/thread.rb	(revision 36937)
+++ lib/thread.rb	(revision 36938)
@@ -182,16 +182,20 @@
   #
   def pop(non_block=false)
     @mutex.synchronize{
-      while true
-        if @que.empty?
-          raise ThreadError, "queue empty" if non_block
-          # @waiting.include? check is necessary for avoiding a race against
-          # Thread.wakeup [Bug 5195]
-          @waiting.push Thread.current unless @waiting.include?(Thread.current)
-          @mutex.sleep
-        else
-          return @que.shift
+      begin
+        while true
+          if @que.empty?
+            raise ThreadError, "queue empty" if non_block
+            # @waiting.include? check is necessary for avoiding a race against
+            # Thread.wakeup [Bug 5195]
+            @waiting.push Thread.current unless @waiting.include?(Thread.current)
+            @mutex.sleep
+          else
+            return @que.shift
+          end
         end
+      ensure
+        @waiting.delete(Thread.current)
       end
     }
   end
@@ -298,10 +302,14 @@
   #
   def push(obj)
     @mutex.synchronize{
-      while true
-        break if @que.length < @max
-        @queue_wait.push Thread.current
-        @mutex.sleep
+      begin
+        while true
+          break if @que.length < @max
+          @queue_wait.push Thread.current unless @queue_wait.include?(Thread.current)
+          @mutex.sleep
+        end
+      ensure
+        @queue_wait.delete(Thread.current)
       end
 
       @que.push obj
Index: test/thread/test_queue.rb
===================================================================
--- test/thread/test_queue.rb	(revision 36937)
+++ test/thread/test_queue.rb	(revision 36938)
@@ -56,6 +56,48 @@
     assert_equal(1, q.max)
   end
 
+  def test_sized_queue_and_wakeup
+    sq = SizedQueue.new(1)
+    sq.push(0)
+
+    t1 = Thread.start { sq.push(1) ; sleep }
+
+    sleep 0.1 until t1.stop?
+    t1.wakeup
+    sleep 0.1 until t1.stop?
+
+    t2 = Thread.start { sq.push(2) }
+    sleep 0.1 until t1.stop? && t2.stop?
+
+    queue_wait = sq.instance_eval{ @queue_wait }
+    assert_equal(queue_wait.uniq, queue_wait)
+  end
+
+  def test_queue_pop_interrupt
+    q = Queue.new
+    t1 = Thread.new { q.pop }
+    sleep 0.01 until t1.stop?
+    t1.kill.join
+    assert_equal(0, q.num_waiting)
+  end
+
+  def test_sized_queue_pop_interrupt
+    q = SizedQueue.new(1)
+    t1 = Thread.new { q.pop }
+    sleep 0.01 until t1.stop?
+    t1.kill.join
+    assert_equal(0, q.num_waiting)
+  end
+
+  def test_sized_queue_push_interrupt
+    q = SizedQueue.new(1)
+    q.push(1)
+    t1 = Thread.new { q.push(2) }
+    sleep 0.01 until t1.stop?
+    t1.kill.join
+    assert_equal(0, q.num_waiting)
+  end
+
   def test_thr_kill
     bug5343 = '[ruby-core:39634]'
     Dir.mktmpdir {|d|

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]