ruby-changes:53250
From: normal <ko1@a...>
Date: Wed, 31 Oct 2018 11:31:20 +0900 (JST)
Subject: [ruby-changes:53250] normal:r65465 (trunk): thread_pthread.c (ubf_select): avoid deadlock on contention
normal 2018-10-31 11:31:15 +0900 (Wed, 31 Oct 2018) New Revision: 65465 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=65465 Log: thread_pthread.c (ubf_select): avoid deadlock on contention vm->gvl.lock can be held by another thread, we must not wait on it when called by the MJIT worker thread when it migrates work to another thread. ubf_select is designed to do retrying anyways, so it has no obligation to wake up a timer thread. cf. http://ci.rvm.jp/results/trunk-mjit-wait@silicon-docker/1437880 Modified files: trunk/thread_pthread.c Index: thread_pthread.c =================================================================== --- thread_pthread.c (revision 65464) +++ thread_pthread.c (revision 65465) @@ -1342,11 +1342,17 @@ ubf_select(void *ptr) https://github.com/ruby/ruby/blob/trunk/thread_pthread.c#L1342 * in unblock_function_clear. */ if (cur != vm->gvl.timer && cur != sigwait_th) { - rb_native_mutex_lock(&vm->gvl.lock); - if (!vm->gvl.timer) { - rb_thread_wakeup_timer_thread(-1); + /* + * Double-checked locking above was to prevent nested locking + * by the SAME thread. We use trylock here to prevent deadlocks + * between DIFFERENT threads + */ + if (native_mutex_trylock(&vm->gvl.lock) == 0) { + if (!vm->gvl.timer) { + rb_thread_wakeup_timer_thread(-1); + } + rb_native_mutex_unlock(&vm->gvl.lock); } - rb_native_mutex_unlock(&vm->gvl.lock); } ubf_wakeup_thread(th); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/