From 946c098df3d8882df529c56368bf42b956fe7246 Mon Sep 17 00:00:00 2001
From: Eric Wong <normalperson@yhbt.net>
Date: Thu, 26 Dec 2013 09:58:35 +0000
Subject: [PATCH] thread: fix deadlock/freeze on SizedQueue#push

SizedQueue#push needs to check the thread list for threads
waiting on enqueue.  Checking the wrong thread list leads
strange/surprising behavior when the the queue is full.
---
 ext/thread/thread.c       |  2 +-
 test/thread/test_queue.rb | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/ext/thread/thread.c b/ext/thread/thread.c
index b8be5d8..208d117 100644
--- a/ext/thread/thread.c
+++ b/ext/thread/thread.c
@@ -459,7 +459,7 @@ static VALUE
 rb_szqueue_push(VALUE self, VALUE obj)
 {
     struct waiting_delete args;
-    args.waiting = GET_QUEUE_WAITERS(self);
+    args.waiting = GET_SZQUEUE_WAITERS(self);
     args.th      = rb_thread_current();
 
     while (queue_length(self) >= GET_SZQUEUE_ULONGMAX(self)) {
diff --git a/test/thread/test_queue.rb b/test/thread/test_queue.rb
index 563b91e..438e1e7 100644
--- a/test/thread/test_queue.rb
+++ b/test/thread/test_queue.rb
@@ -134,6 +134,29 @@ class TestQueue < Test::Unit::TestCase
     assert_same q, retval
   end
 
+  def test_sized_queue_throttle
+    q = SizedQueue.new(1)
+    i = 0
+    consumer = Thread.new do
+      while q.pop
+        i += 1
+        Thread.pass
+      end
+    end
+    nprod = 4
+    npush = 100
+
+    producer = nprod.times.map do
+      Thread.new do
+        npush.times { q.push(true) }
+      end
+    end
+    producer.each(&:join)
+    q.push(nil)
+    consumer.join
+    assert_equal(nprod * npush, i)
+  end
+
   def test_queue_thread_raise
     q = Queue.new
     th1 = Thread.new do
-- 
1.8.5.rc2.1.g2f4e96a

