From d165d5af914c3c925fb7ba53fbd63dfb2de92f5d Mon Sep 17 00:00:00 2001 From: jundery Date: Sun, 3 Mar 2013 23:44:46 -0700 Subject: [PATCH] Fix race condition where idle_loop() gets called from Split() SplitPoint member slavesMask wasn't read under lock No functional change. --- src/search.cpp | 8 +++++++- src/thread.cpp | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 19ebc5e6..c5c5b944 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1622,7 +1622,7 @@ void Thread::idle_loop() { // Pointer 'this_sp' is not null only if we are called from split(), and not // at the thread creation. So it means we are the split point's master. - const SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : NULL; + SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : NULL; assert(!this_sp || (this_sp->masterThread == this && searching)); @@ -1630,6 +1630,9 @@ void Thread::idle_loop() { // their work at this split point, return from the idle loop. while (!this_sp || this_sp->slavesMask) { + if (this_sp) + this_sp->mutex.unlock(); + // If we are not searching, wait for a condition to be signaled instead of // wasting CPU time polling for work. while ((!searching && Threads.sleepWhileIdle) || exit) @@ -1721,6 +1724,9 @@ void Thread::idle_loop() { // unsafe because if we are exiting there is a chance are already freed. sp->mutex.unlock(); } + + if(this_sp) + this_sp->mutex.lock(); } } diff --git a/src/thread.cpp b/src/thread.cpp index 0d8070f2..df746a4a 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -312,6 +312,7 @@ void Thread::split(Position& pos, Stack* ss, Value alpha, Value beta, Value* bes sp.mutex.unlock(); Threads.mutex.unlock(); + // Calling idle_loop with sp.mutex locked Thread::idle_loop(); // Force a call to base class idle_loop() // In helpful master concept a master can help only a sub-tree of its split @@ -322,6 +323,10 @@ void Thread::split(Position& pos, Stack* ss, Value alpha, Value beta, Value* bes // We have returned from the idle loop, which means that all threads are // finished. Note that setting 'searching' and decreasing splitPointsSize is // done under lock protection to avoid a race with Thread::is_available_to(). + // idle_loop returns with sp.mutex locked but we must unlock it inorder to + // lock Threads.mutex without conflicting with check_time() (threads holding + // multiple locks must always acquired them in the same order to avoid deadlocks) + sp.mutex.unlock(); Threads.mutex.lock(); sp.mutex.lock(); } -- 2.39.2