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

ruby-changes:10461

From: nobu <ko1@a...>
Date: Tue, 3 Feb 2009 18:40:38 +0900 (JST)
Subject: [ruby-changes:10461] Ruby:r22011 (ruby_1_8): * ext/thread/thread.c (rb_queue_pop, rb_queue_push): should not lock

nobu	2009-02-03 18:35:50 +0900 (Tue, 03 Feb 2009)

  New Revision: 22011

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

  Log:
    * ext/thread/thread.c (rb_queue_pop, rb_queue_push): should not lock
      mutex if got an exception while waiting, and should ensure unlocked
      after signaled.  [ruby-dev:37545]

  Modified files:
    branches/ruby_1_8/ChangeLog
    branches/ruby_1_8/ext/thread/thread.c
    branches/ruby_1_8/test/thread/test_thread.rb

Index: ruby_1_8/ext/thread/thread.c
===================================================================
--- ruby_1_8/ext/thread/thread.c	(revision 22010)
+++ ruby_1_8/ext/thread/thread.c	(revision 22011)
@@ -440,6 +440,12 @@
 }
 
 static VALUE
+lock_mutex_call(VALUE mutex)
+{
+    return lock_mutex((Mutex *)mutex);
+}
+
+static VALUE
 rb_mutex_lock(VALUE self)
 {
     Mutex *mutex;
@@ -492,6 +498,12 @@
 }
 
 static VALUE
+unlock_mutex_call(VALUE mutex)
+{
+    return unlock_mutex((Mutex *)mutex);
+}
+
+static VALUE
 rb_mutex_unlock(VALUE self)
 {
     Mutex *mutex;
@@ -644,9 +656,18 @@
  *
  */
 
+static void condvar_wakeup(Mutex *mutex);
+
 static void
 wait_condvar(ConditionVariable *condvar, Mutex *mutex)
 {
+    condvar_wakeup(mutex);
+    rb_ensure(wait_list, (VALUE)&condvar->waiting, lock_mutex_call, (VALUE)mutex);
+}
+
+static void
+condvar_wakeup(Mutex *mutex)
+{
     VALUE waking;
 
     rb_thread_critical = 1;
@@ -658,7 +679,6 @@
     if (RTEST(waking)) {
 	wake_thread(waking);
     }
-    rb_ensure(wait_list, (VALUE)&condvar->waiting, lock_mutex, (VALUE)mutex);
 }
 
 static VALUE
@@ -741,6 +761,13 @@
 }
 
 static VALUE
+signal_condvar_call(VALUE condvar)
+{
+    signal_condvar((ConditionVariable *)condvar);
+    return Qundef;
+}
+
+static VALUE
 rb_condvar_signal(VALUE self)
 {
     ConditionVariable *condvar;
@@ -964,6 +991,16 @@
     return result;
 }
 
+static void
+wait_queue(ConditionVariable *condvar, Mutex *mutex)
+{
+    condvar_wakeup(mutex);
+    wait_list(&condvar->waiting);
+    lock_mutex(mutex);
+}
+
+static VALUE queue_pop_inner(VALUE arg);
+
 /*
  * Document-method: pop
  * call_seq: pop(non_block=false)
@@ -979,7 +1016,6 @@
 {
     Queue *queue;
     int should_block;
-    VALUE result;
     Data_Get_Struct(self, Queue, queue);
 
     if (argc == 0) {
@@ -997,15 +1033,21 @@
     }
 
     while (!queue->values.entries) {
-        wait_condvar(&queue->value_available, &queue->mutex);
+        wait_queue(&queue->value_available, &queue->mutex);
     }
 
-    result = shift_list(&queue->values);
+    return rb_ensure(queue_pop_inner, (VALUE)queue,
+		     unlock_mutex_call, (VALUE)&queue->mutex);
+}
+
+static VALUE
+queue_pop_inner(VALUE arg)
+{
+    Queue *queue = (Queue *)arg;
+    VALUE result = shift_list(&queue->values);
     if (queue->capacity && queue->values.size < queue->capacity) {
         signal_condvar(&queue->space_available);
     }
-    unlock_mutex(&queue->mutex);
-
     return result;
 }
 
@@ -1025,11 +1067,11 @@
 
     lock_mutex(&queue->mutex);
     while (queue->capacity && queue->values.size >= queue->capacity) {
-        wait_condvar(&queue->space_available, &queue->mutex);
+        wait_queue(&queue->space_available, &queue->mutex);
     }
     push_list(&queue->values, value);
-    signal_condvar(&queue->value_available);
-    unlock_mutex(&queue->mutex);
+    rb_ensure(signal_condvar_call, (VALUE)&queue->value_available,
+	      unlock_mutex_call, (VALUE)&queue->mutex);
 
     return self;
 }
Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog	(revision 22010)
+++ ruby_1_8/ChangeLog	(revision 22011)
@@ -1,3 +1,9 @@
+Tue Feb  3 18:35:48 2009  Nobuyoshi Nakada  <nobu@r...>
+
+	* ext/thread/thread.c (rb_queue_pop, rb_queue_push): should not lock
+	  mutex if got an exception while waiting, and should ensure unlocked
+	  after signaled.  [ruby-dev:37545]
+
 Tue Feb  3 12:27:19 2009  Yukihiro Matsumoto  <matz@r...>
 
 	* re.c (match_check): check if MatchData is initialized.
Index: ruby_1_8/test/thread/test_thread.rb
===================================================================
--- ruby_1_8/test/thread/test_thread.rb	(revision 22010)
+++ ruby_1_8/test/thread/test_thread.rb	(revision 22011)
@@ -77,5 +77,14 @@
             assert_equal("exit.", result[/.*\Z/], '[ruby-dev:30653]')
         }
     end
+
+    def test_queue_rescue
+        require "timeout"
+        queue = Queue.new
+        assert_raises(Timeout::Error) {Timeout.timeout(0.001) {queue.pop}}
+        queue.push(1)
+        assert_nothing_raised("[ruby-dev:37545]") {assert_equal(1, queue.pop)}
+        assert(queue.empty?)
+    end
 end
 

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

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