]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Reformat threads code
[stockfish] / src / search.cpp
index 3ec60e7cfd4f3d768631ab3a80d2e66f1adcff80..f0bbf0fdecd013362a81f5037cb8d539e8c0495e 100644 (file)
@@ -544,7 +544,7 @@ namespace {
     const bool RootNode = (NT == Root || NT == SplitPointRoot);
 
     assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
-    assert(PvNode == (alpha != beta - 1));
+    assert((alpha == beta - 1) || PvNode);
     assert(depth > DEPTH_ZERO);
     assert(pos.thread() >= 0 && pos.thread() < Threads.size());
 
@@ -573,22 +573,32 @@ namespace {
         thread.maxPly = ss->ply;
 
     // Step 1. Initialize node
-    if (!SpNode)
-    {
-        ss->currentMove = ss->bestMove = threatMove = (ss+1)->excludedMove = MOVE_NONE;
-        (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
-        (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
-    }
-    else
+    if (SpNode)
     {
-        sp = ss->sp;
         tte = NULL;
         ttMove = excludedMove = MOVE_NONE;
+        sp = ss->sp;
         threatMove = sp->threatMove;
+        bestValue = sp->bestValue;
+        moveCount = sp->moveCount; // Lock must be held here
+
+        assert(bestValue > -VALUE_INFINITE && moveCount > 0);
+
         goto split_point_start;
     }
+    else
+    {
+        ss->currentMove = ss->bestMove = threatMove = (ss+1)->excludedMove = MOVE_NONE;
+        (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
+        (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
+
+    }
 
     // Step 2. Check for aborted search and immediate draw
+    // Enforce node limit here. FIXME: This only works with 1 search thread.
+    if (Limits.maxNodes && pos.nodes_searched() >= Limits.maxNodes)
+        Signals.stop = true;
+
     if ((   Signals.stop
          || pos.is_draw<false>()
          || ss->ply > MAX_PLY) && !RootNode)
@@ -771,6 +781,7 @@ namespace {
         Depth rdepth = depth - ONE_PLY - 3 * ONE_PLY;
 
         assert(rdepth >= ONE_PLY);
+        assert((ss-1)->currentMove != MOVE_NONE);
 
         MovePicker mp(pos, ttMove, H, pos.captured_piece_type());
         CheckInfo ci(pos);
@@ -778,6 +789,7 @@ namespace {
         while ((move = mp.next_move()) != MOVE_NONE)
             if (pos.pl_move_is_legal(move, ci.pinned))
             {
+                ss->currentMove = move;
                 pos.do_move(move, st, ci, pos.move_gives_check(move, ci));
                 value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth);
                 pos.undo_move(move);
@@ -814,14 +826,6 @@ split_point_start: // At split points actual search starts from here
                            && !excludedMove // Recursive singular search is not allowed
                            && (tte->type() & VALUE_TYPE_LOWER)
                            && tte->depth() >= depth - 3 * ONE_PLY;
-    if (SpNode)
-    {
-        lock_grab(&(sp->lock));
-        bestValue = sp->bestValue;
-        moveCount = sp->moveCount;
-
-        assert(bestValue > -VALUE_INFINITE && moveCount > 0);
-    }
 
     // Step 11. Loop through moves
     // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
@@ -848,7 +852,7 @@ split_point_start: // At split points actual search starts from here
       if (SpNode)
       {
           moveCount = ++sp->moveCount;
-          lock_release(&(sp->lock));
+          lock_release(sp->lock);
       }
       else
           moveCount++;
@@ -919,7 +923,7 @@ split_point_start: // At split points actual search starts from here
               && (!threatMove || !connected_threat(pos, move, threatMove)))
           {
               if (SpNode)
-                  lock_grab(&(sp->lock));
+                  lock_grab(sp->lock);
 
               continue;
           }
@@ -934,7 +938,7 @@ split_point_start: // At split points actual search starts from here
           if (futilityValue < beta)
           {
               if (SpNode)
-                  lock_grab(&(sp->lock));
+                  lock_grab(sp->lock);
 
               continue;
           }
@@ -944,7 +948,7 @@ split_point_start: // At split points actual search starts from here
               && pos.see_sign(move) < 0)
           {
               if (SpNode)
-                  lock_grab(&(sp->lock));
+                  lock_grab(sp->lock);
 
               continue;
           }
@@ -1009,12 +1013,12 @@ split_point_start: // At split points actual search starts from here
       // Step 18. Check for new best move
       if (SpNode)
       {
-          lock_grab(&(sp->lock));
+          lock_grab(sp->lock);
           bestValue = sp->bestValue;
           alpha = sp->alpha;
       }
 
-      // Finished searching the move. If StopRequest is true, the search
+      // Finished searching the move. If Signals.stop is true, the search
       // was aborted because the user interrupted the search or because we
       // ran out of time. In this case, the return value of the search cannot
       // be trusted, and we don't update the best move and/or PV.
@@ -1075,7 +1079,7 @@ split_point_start: // At split points actual search starts from here
     // Step 20. Check for mate and stalemate
     // All legal moves have been searched and if there are no legal moves, it
     // must be mate or stalemate. Note that we can have a false positive in
-    // case of StopRequest or thread.cutoff_occurred() are set, but this is
+    // case of Signals.stop or thread.cutoff_occurred() are set, but this is
     // harmless because return value is discarded anyhow in the parent nodes.
     // If we are in a singular extension search then return a fail low score.
     if (!moveCount)
@@ -1123,14 +1127,6 @@ split_point_start: // At split points actual search starts from here
         }
     }
 
-    if (SpNode)
-    {
-        // Here we have the lock still grabbed
-        sp->is_slave[pos.thread()] = false;
-        sp->nodes += pos.nodes_searched();
-        lock_release(&(sp->lock));
-    }
-
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
     return bestValue;
@@ -1148,7 +1144,7 @@ split_point_start: // At split points actual search starts from here
 
     assert(NT == PV || NT == NonPV);
     assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
-    assert(PvNode == (alpha != beta - 1));
+    assert((alpha == beta - 1) || PvNode);
     assert(depth <= DEPTH_ZERO);
     assert(pos.thread() >= 0 && pos.thread() < Threads.size());
 
@@ -1830,34 +1826,34 @@ void RootMove::insert_pv_in_tt(Position& pos) {
 
 
 /// Thread::idle_loop() is where the thread is parked when it has no work to do.
-/// The parameter 'sp', if non-NULL, is a pointer to an active SplitPoint object
-/// for which the thread is the master.
+/// The parameter 'master_sp', if non-NULL, is a pointer to an active SplitPoint
+/// object for which the thread is the master.
 
-void Thread::idle_loop(SplitPoint* sp) {
+void Thread::idle_loop(SplitPoint* sp_master) {
 
-  while (true)
+  // If this thread is the master of a split point and all slaves have
+  // finished their work at this split point, return from the idle loop.
+  while (!sp_master || sp_master->slavesMask)
   {
       // If we are not searching, wait for a condition to be signaled
       // instead of wasting CPU time polling for work.
       while (   do_sleep
-             || do_terminate
-             || (Threads.use_sleeping_threads() && !is_searching))
+             || do_exit
+             || (!is_searching && Threads.use_sleeping_threads()))
       {
-          assert((!sp && threadID) || Threads.use_sleeping_threads());
-
-          if (do_terminate)
+          if (do_exit)
           {
-              assert(!sp);
+              assert(!sp_master);
               return;
           }
 
           // Grab the lock to avoid races with Thread::wake_up()
-          lock_grab(&sleepLock);
+          lock_grab(sleepLock);
 
           // If we are master and all slaves have finished don't go to sleep
-          if (sp && Threads.split_point_finished(sp))
+          if (sp_master && !sp_master->slavesMask)
           {
-              lock_release(&sleepLock);
+              lock_release(sleepLock);
               break;
           }
 
@@ -1866,54 +1862,50 @@ void Thread::idle_loop(SplitPoint* sp) {
           // in the meanwhile, allocated us and sent the wake_up() call before we
           // had the chance to grab the lock.
           if (do_sleep || !is_searching)
-              cond_wait(&sleepCond, &sleepLock);
+              cond_wait(sleepCond, sleepLock);
 
-          lock_release(&sleepLock);
+          lock_release(sleepLock);
       }
 
       // If this thread has been assigned work, launch a search
       if (is_searching)
       {
-          assert(!do_terminate);
+          assert(!do_sleep && !do_exit);
 
           // Copy split point position and search stack and call search()
           Stack ss[MAX_PLY_PLUS_2];
-          SplitPoint* tsp = splitPoint;
-          Position pos(*tsp->pos, threadID);
-
-          memcpy(ss, tsp->ss - 1, 4 * sizeof(Stack));
-          (ss+1)->sp = tsp;
-
-          if (tsp->nodeType == Root)
-              search<SplitPointRoot>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
-          else if (tsp->nodeType == PV)
-              search<SplitPointPV>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
-          else if (tsp->nodeType == NonPV)
-              search<SplitPointNonPV>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
+          SplitPoint* sp = splitPoint;
+          Position pos(*sp->pos, threadID);
+
+          memcpy(ss, sp->ss - 1, 4 * sizeof(Stack));
+          (ss+1)->sp = sp;
+
+          lock_grab(sp->lock);
+
+          if (sp->nodeType == Root)
+              search<SplitPointRoot>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
+          else if (sp->nodeType == PV)
+              search<SplitPointPV>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
+          else if (sp->nodeType == NonPV)
+              search<SplitPointNonPV>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
           else
               assert(false);
 
           assert(is_searching);
 
+          // We return from search with lock held
+          sp->slavesMask &= ~(1ULL << threadID);
+          sp->nodes += pos.nodes_searched();
+          lock_release(sp->lock);
+
           is_searching = false;
 
           // Wake up master thread so to allow it to return from the idle loop in
           // case we are the last slave of the split point.
           if (   Threads.use_sleeping_threads()
-              && threadID != tsp->master
-              && !Threads[tsp->master].is_searching)
-              Threads[tsp->master].wake_up();
-      }
-
-      // If this thread is the master of a split point and all slaves have
-      // finished their work at this split point, return from the idle loop.
-      if (sp && Threads.split_point_finished(sp))
-      {
-          // Because sp->is_slave[] is reset under lock protection,
-          // be sure sp->lock has been released before to return.
-          lock_grab(&(sp->lock));
-          lock_release(&(sp->lock));
-          return;
+              && threadID != sp->master
+              && !Threads[sp->master].is_searching)
+              Threads[sp->master].wake_up();
       }
   }
 }
@@ -1945,7 +1937,6 @@ void check_time() {
                    || stillAtFirstMove;
 
   if (   (Limits.use_time_management() && noMoreTime)
-      || (Limits.maxTime && e >= Limits.maxTime)
-         /* missing nodes limit */ ) // FIXME
+      || (Limits.maxTime && e >= Limits.maxTime))
       Signals.stop = true;
 }