Fix race condition where idle_loop() gets called from Split()
authorjundery <jundery@gmail.com>
Mon, 4 Mar 2013 06:44:46 +0000 (23:44 -0700)
committerMarco Costalba <mcostalba@gmail.com>
Mon, 4 Mar 2013 07:52:24 +0000 (08:52 +0100)
SplitPoint member slavesMask wasn't read under lock

No functional change.

src/search.cpp
src/thread.cpp

index 19ebc5e6eeeb79ef8ce12a3835372b1581edae95..c5c5b94470fed9365831fea28427db4d4070d0e5 100644 (file)
@@ -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();
   }
 }
 
index 0d8070f202b0774d5077b4ec26962d54f438f7c4..df746a4a825d2befdc77fa5397e0b5be952b3a65 100644 (file)
@@ -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();
   }