summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-03-23 10:17:50 +0000
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-03-23 10:17:50 +0000
commit78630e3a82afdea79220364d78aa4aea52ca100d (patch)
tree0110713f71edc4b80a7b0fd5c9425a675badf368
parente8122fadd454723c4b557f30f53dbd3b88c1606d (diff)
merge revision(s) 22011:
* 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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@23049 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog6
-rw-r--r--ext/thread/thread.c60
-rw-r--r--test/thread/test_thread.rb9
-rw-r--r--version.h2
4 files changed, 67 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index acebc42a5a..1b6a2f2a7f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Mon Mar 23 19:17:06 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * 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]
+
Mon Mar 23 18:26:57 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
* eval.c (rb_thread_value): missed to change at r17874. [ruby-core:17595]
diff --git a/ext/thread/thread.c b/ext/thread/thread.c
index ac81b2e3ba..298d7d08ca 100644
--- a/ext/thread/thread.c
+++ b/ext/thread/thread.c
@@ -440,6 +440,12 @@ lock_mutex(Mutex *mutex)
}
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 @@ unlock_mutex(Mutex *mutex)
}
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 @@ rb_condvar_alloc(VALUE klass)
*
*/
+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 @@ wait_condvar(ConditionVariable *condvar, Mutex *mutex)
if (RTEST(waking)) {
wake_thread(waking);
}
- rb_ensure(wait_list, (VALUE)&condvar->waiting, lock_mutex, (VALUE)mutex);
}
static VALUE
@@ -741,6 +761,13 @@ signal_condvar(ConditionVariable *condvar)
}
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 @@ rb_queue_num_waiting(VALUE self)
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 @@ rb_queue_pop(int argc, VALUE *argv, VALUE self)
{
Queue *queue;
int should_block;
- VALUE result;
Data_Get_Struct(self, Queue, queue);
if (argc == 0) {
@@ -997,15 +1033,21 @@ rb_queue_pop(int argc, VALUE *argv, VALUE self)
}
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 @@ rb_queue_push(VALUE self, VALUE value)
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;
}
diff --git a/test/thread/test_thread.rb b/test/thread/test_thread.rb
index 44ae3b338d..699f4fe406 100644
--- a/test/thread/test_thread.rb
+++ b/test/thread/test_thread.rb
@@ -77,5 +77,14 @@ class TC_Thread < Test::Unit::TestCase
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
diff --git a/version.h b/version.h
index 36b84f3209..5396b5f543 100644
--- a/version.h
+++ b/version.h
@@ -2,7 +2,7 @@
#define RUBY_RELEASE_DATE "2009-03-23"
#define RUBY_VERSION_CODE 187
#define RUBY_RELEASE_CODE 20090323
-#define RUBY_PATCHLEVEL 152
+#define RUBY_PATCHLEVEL 153
#define RUBY_VERSION_MAJOR 1
#define RUBY_VERSION_MINOR 8