From 10c14095de5dd4114d8cf536c5bd4cea63370a97 Mon Sep 17 00:00:00 2001 From: kosaki Date: Sun, 9 Sep 2012 06:27:02 +0000 Subject: * thread.c (rb_mutex_lock): stop multiple threads use pthread_cond_timedwait() concurrently. [Bug #6278] [ruby-core:44275] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36926 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- thread.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'thread.c') diff --git a/thread.c b/thread.c index 831eb2a69e..4c0bd7a3d4 100644 --- a/thread.c +++ b/thread.c @@ -3910,6 +3910,13 @@ lock_interrupt(void *ptr) native_mutex_unlock(&mutex->lock); } +/* + * At maximum, only one thread can use cond_timedwait and watch deadlock + * periodically. Multiple polling thread (i.e. concurrent deadlock check) + * introduces new race conditions. [Bug #6278] [ruby-core:44275] + */ +rb_thread_t *patrol_thread = NULL; + /* * call-seq: * mutex.lock -> self @@ -3947,14 +3954,20 @@ rb_mutex_lock(VALUE self) * vm->sleepr is unstable value. we have to avoid both deadlock * and busy loop. */ - if (vm_living_thread_num(th->vm) == th->vm->sleeper) { + if ((vm_living_thread_num(th->vm) == th->vm->sleeper) && + !patrol_thread) { timeout_ms = 100; + patrol_thread = th; } + GVL_UNLOCK_BEGIN(); interrupted = lock_func(th, mutex, timeout_ms); native_mutex_unlock(&mutex->lock); GVL_UNLOCK_END(); + if (patrol_thread == th) + patrol_thread = NULL; + reset_unblock_function(th, &oldubf); th->locking_mutex = Qfalse; @@ -4642,6 +4655,7 @@ rb_check_deadlock(rb_vm_t *vm) if (vm_living_thread_num(vm) > vm->sleeper) return; if (vm_living_thread_num(vm) < vm->sleeper) rb_bug("sleeper must not be more than vm_living_thread_num(vm)"); + if (patrol_thread && patrol_thread != GET_THREAD()) return; st_foreach(vm->living_threads, check_deadlock_i, (st_data_t)&found); -- cgit v1.2.3