]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Ensure function boundaries for threads state changes
[stockfish] / src / search.cpp
index c13431bc9721d418b1eabded12b677df2bb7ba23..54266914b25688f82a5bea57d898743291a7c2b5 100644 (file)
@@ -164,8 +164,8 @@ namespace {
   int32_t FutilityMarginsMatrix[14][64]; // [depth][moveNumber]
   int FutilityMoveCountArray[32]; // [depth]
 
-  inline Value futility_margin(Depth d, int mn) { return (Value) (d < 14? FutilityMarginsMatrix[Max(d, 0)][Min(mn, 63)] : 2*VALUE_INFINITE); }
-  inline int futility_move_count(Depth d) { return (d < 32? FutilityMoveCountArray[d] : 512); }
+  inline Value futility_margin(Depth d, int mn) { return Value(d < 7*OnePly ? FutilityMarginsMatrix[Max(d, 0)][Min(mn, 63)] : 2 * VALUE_INFINITE); }
+  inline int futility_move_count(Depth d) { return d < 16*OnePly ? FutilityMoveCountArray[d] : 512; }
 
   /// Variables initialized by UCI options
 
@@ -219,9 +219,8 @@ namespace {
   Thread Threads[THREAD_MAX];
   Lock MPLock;
   Lock IOLock;
-  bool AllThreadsShouldExit = false;
+  bool AllThreadsShouldExit, AllThreadsShouldSleep;
   SplitPoint SplitPointStack[THREAD_MAX][ACTIVE_SPLIT_POINTS_MAX];
-  bool Idle = true;
 
 #if !defined(_MSC_VER)
   pthread_cond_t WaitCond;
@@ -281,6 +280,7 @@ namespace {
              const Value futilityValue, Depth depth, int *moves,
              MovePicker *mp, int master, bool pvNode);
   void wake_sleeping_threads();
+  void put_threads_to_sleep();
 
 #if !defined(_MSC_VER)
   void *init_thread(void *threadID);
@@ -336,7 +336,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
            int maxNodes, int maxTime, Move searchMoves[]) {
 
   // Initialize global search variables
-  Idle = StopOnPonderhit = AbortSearch = Quit = false;
+  StopOnPonderhit = AbortSearch = Quit = false;
   AspirationFailLow = false;
   NodesSincePoll = 0;
   SearchStartTime = get_system_time();
@@ -522,13 +522,13 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
   if (UseLogFile)
       LogFile.close();
 
-  Idle = true;
+  put_threads_to_sleep();
+
   return !Quit;
 }
 
 
-/// init_search() is called during startup. It initializes various
-/// lookup tables.
+/// init_search() is called during startup. It initializes various lookup tables
 
 void init_search() {
 
@@ -568,9 +568,6 @@ void init_threads() {
   pthread_t pthread[1];
 #endif
 
-  for (i = 0; i < THREAD_MAX; i++)
-      Threads[i].activeSplitPoints = 0;
-
   // Initialize global locks
   lock_init(&MPLock, NULL);
   lock_init(&IOLock, NULL);
@@ -585,14 +582,15 @@ void init_threads() {
       SitIdleEvent[i] = CreateEvent(0, FALSE, FALSE, 0);
 #endif
 
+  // Will be set just before program exits to properly end the threads
+  AllThreadsShouldExit = false;
+
+  // Threads will be put to sleep as soon as created
+  AllThreadsShouldSleep = true;
+
   // All threads except the main thread should be initialized to idle state
   for (i = 1; i < THREAD_MAX; i++)
-  {
-      Threads[i].stop = false;
-      Threads[i].workIsWaiting = false;
       Threads[i].idle = true;
-      Threads[i].running = false;
-  }
 
   // Launch the helper threads
   for (i = 1; i < THREAD_MAX; i++)
@@ -610,19 +608,19 @@ void init_threads() {
           Application::exit_with_failure();
       }
 
-      // Wait until the thread has finished launching
-      while (!Threads[i].running);
+      // Wait until the thread has finished launching and is gone to sleep
+      while (!Threads[i].running || !Threads[i].sleeping);
   }
 }
 
 
-/// stop_threads() is called when the program exits. It makes all the
+/// exit_threads() is called when the program exits. It makes all the
 /// helper threads exit cleanly.
 
-void stop_threads() {
+void exit_threads() {
 
   ActiveThreads = THREAD_MAX;  // HACK
-  Idle = false;  // HACK
+  AllThreadsShouldSleep = true;  // HACK
   wake_sleeping_threads();
   AllThreadsShouldExit = true;
   for (int i = 1; i < THREAD_MAX; i++)
@@ -654,7 +652,6 @@ void SearchStack::init(int ply) {
   currentMove = threatMove = MOVE_NONE;
   reduction = Depth(0);
   eval = VALUE_NONE;
-  evalInfo = NULL;
 }
 
 void SearchStack::initKillers() {
@@ -1387,10 +1384,7 @@ namespace {
         if (tte && (tte->type() & VALUE_TYPE_EVAL))
             staticValue = value_from_tt(tte->value(), ply);
         else
-        {
             staticValue = evaluate(pos, ei, threadID);
-            ss[ply].evalInfo = &ei;
-        }
 
         ss[ply].eval = staticValue;
         futilityValue = staticValue + futility_margin(depth, 0); //FIXME: Remove me, only for split
@@ -1544,7 +1538,8 @@ namespace {
 
           // Value based pruning
           Depth predictedDepth = newDepth - nonpv_reduction(depth, moveCount); //FIXME: We are ignoring condition: depth >= 3*OnePly, BUG??
-          futilityValueScaled = ss[ply].eval + futility_margin(predictedDepth, moveCount) + H.gain(pos.piece_on(move_from(move)), move_to(move)) + 45;
+          futilityValueScaled =  ss[ply].eval + futility_margin(predictedDepth, moveCount)
+                               + H.gain(pos.piece_on(move_from(move)), move_to(move)) + 45;
 
           if (futilityValueScaled < beta)
           {
@@ -2780,16 +2775,17 @@ namespace {
 
     Threads[threadID].running = true;
 
-    while (true)
+    while (!AllThreadsShouldExit || threadID == 0)
     {
-        if (AllThreadsShouldExit && threadID != 0)
-            break;
-
         // If we are not thinking, wait for a condition to be signaled
         // instead of wasting CPU time polling for work.
-        while (threadID != 0 && (Idle || threadID >= ActiveThreads))
+        while (    threadID != 0
+               && !AllThreadsShouldExit
+               && (AllThreadsShouldSleep || threadID >= ActiveThreads))
         {
 
+            Threads[threadID].sleeping = true;
+
 #if !defined(_MSC_VER)
             pthread_mutex_lock(&WaitLock);
             if (Idle || threadID >= ActiveThreads)
@@ -2801,6 +2797,10 @@ namespace {
 #endif
         }
 
+        // Out of the while loop to avoid races in case thread is woken up but
+        // while condition still holds true so that is put to sleep again.
+        Threads[threadID].sleeping = false;
+
       // If this thread has been assigned work, launch a search
       if (Threads[threadID].workIsWaiting)
       {
@@ -3052,10 +3052,16 @@ namespace {
 
   void wake_sleeping_threads() {
 
+    assert(AllThreadsShouldSleep);
+
+    AllThreadsShouldSleep = false;
+
     if (ActiveThreads > 1)
     {
         for (int i = 1; i < ActiveThreads; i++)
         {
+            assert(Threads[i].sleeping == true);
+
             Threads[i].idle = true;
             Threads[i].workIsWaiting = false;
         }
@@ -3068,10 +3074,30 @@ namespace {
       for (int i = 1; i < THREAD_MAX; i++)
           SetEvent(SitIdleEvent[i]);
 #endif
+
+      // Wait for the threads to be all woken up
+      for (int i = 1; i < ActiveThreads; i++)
+           while (Threads[i].sleeping);
     }
   }
 
 
+  // put_threads_to_sleep() makes all the threads go to sleep just before
+  // to leave think(), at the end of the search. Threads should have already
+  // finished the job and should be idle.
+
+  void put_threads_to_sleep() {
+
+    assert(!AllThreadsShouldSleep);
+
+    AllThreadsShouldSleep = true;
+
+    // Wait for the threads to be all sleeping
+    for (int i = 1; i < ActiveThreads; i++)
+        while (!Threads[i].sleeping);
+  }
+
+
   // init_thread() is the function which is called when a new thread is
   // launched. It simply calls the idle_loop() function with the supplied
   // threadID. There are two versions of this function; one for POSIX