diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 6ac64d43..f42c0e6c 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -107,7 +107,7 @@ void benchmark(istringstream& is) { for (size_t i = 0; i < fens.size(); i++) { - Position pos(fens[i], false); + Position pos(fens[i], false, NULL); cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl; diff --git a/src/endgame.cpp b/src/endgame.cpp index 65f0f409..5e021f11 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -77,7 +77,7 @@ namespace { string fen = sides[0] + char('0' + int(8 - code.length())) + sides[1] + "/8/8/8/8/8/8/8 w - - 0 10"; - return Position(fen, false).material_key(); + return Position(fen, false, NULL).material_key(); } template diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 515405ca..9806b34b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -371,7 +371,7 @@ Value do_evaluate(const Position& pos, Value& margin) { margins[WHITE] = margins[BLACK] = VALUE_ZERO; // Probe the material hash table - ei.mi = this_thread->materialTable.probe(pos); + ei.mi = pos.this_thread()->materialTable.probe(pos); score += ei.mi->material_value(); // If we have a specialized evaluation function for the current material @@ -383,7 +383,7 @@ Value do_evaluate(const Position& pos, Value& margin) { } // Probe the pawn hash table - ei.pi = this_thread->pawnTable.probe(pos); + ei.pi = pos.this_thread()->pawnTable.probe(pos); score += ei.pi->pawns_value(); // Initialize attack and king safety bitboards diff --git a/src/position.cpp b/src/position.cpp index 47b08ec0..3a0f8b1c 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -92,17 +92,19 @@ CheckInfo::CheckInfo(const Position& pos) { } -/// Position::operator=() creates a copy of 'pos'. We want the new born Position +/// Position::copy() creates a copy of 'pos'. We want the new born Position /// object do not depend on any external data so we detach state pointer from /// the source one. -Position& Position::operator=(const Position& pos) { +void Position::copy(const Position& pos, Thread* th) { memcpy(this, &pos, sizeof(Position)); startState = *st; st = &startState; + thisThread = th; nodes = 0; - return *this; + + assert(pos_is_ok()); } @@ -110,7 +112,7 @@ Position& Position::operator=(const Position& pos) { /// string. This function is not very robust - make sure that input FENs are /// correct (this is assumed to be the responsibility of the GUI). -void Position::from_fen(const string& fenStr, bool isChess960) { +void Position::from_fen(const string& fenStr, bool isChess960, Thread* th) { /* A FEN string defines a particular position using only the ASCII character set. @@ -226,6 +228,7 @@ void Position::from_fen(const string& fenStr, bool isChess960) { st->npMaterial[BLACK] = compute_non_pawn_material(BLACK); st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove); chess960 = isChess960; + thisThread = th; assert(pos_is_ok()); } @@ -328,7 +331,7 @@ void Position::print(Move move) const { if (move) { - Position p(*this); + Position p(*this, thisThread); cout << "\nMove is: " << (sideToMove == BLACK ? ".." : "") << move_to_san(p, move); } @@ -895,8 +898,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI } // Prefetch pawn and material hash tables - prefetch((char*)this_thread->pawnTable.entries[st->pawnKey]); - prefetch((char*)this_thread->materialTable.entries[st->materialKey]); + prefetch((char*)thisThread->pawnTable.entries[st->pawnKey]); + prefetch((char*)thisThread->materialTable.entries[st->materialKey]); // Update incremental scores st->psqScore += psq_delta(piece, from, to); @@ -1538,9 +1541,10 @@ void Position::init() { void Position::flip() { // Make a copy of current position before to start changing - const Position pos(*this); + const Position pos(*this, thisThread); clear(); + thisThread = pos.this_thread(); // Board for (Square s = SQ_A1; s <= SQ_H8; s++) diff --git a/src/position.h b/src/position.h index 2db3d965..b59e5923 100644 --- a/src/position.h +++ b/src/position.h @@ -84,14 +84,19 @@ struct StateInfo { /// * A counter for detecting 50 move rule draws. class Position { -public: - Position() {} - Position(const Position& p) { *this = p; } - Position(const std::string& f, bool c960) { from_fen(f, c960); } + + // No copy c'tor or assignment operator allowed + Position(const Position&); Position& operator=(const Position&); +public: + Position() {} + Position(const Position& p, Thread* t) { copy(p, t); } + Position(const std::string& f, bool c960, Thread* t) { from_fen(f, c960, t); } + // Text input/output - void from_fen(const std::string& fen, bool isChess960); + void copy(const Position& pos, Thread* th); + void from_fen(const std::string& fen, bool isChess960, Thread* th); const std::string to_fen() const; void print(Move m = MOVE_NONE) const; @@ -171,6 +176,7 @@ public: Color side_to_move() const; int startpos_ply_counter() const; bool is_chess960() const; + Thread* this_thread() const; int64_t nodes_searched() const; void set_nodes_searched(int64_t n); template bool is_draw() const; @@ -218,6 +224,7 @@ private: int64_t nodes; int startPosPly; Color sideToMove; + Thread* thisThread; StateInfo* st; int chess960; @@ -427,4 +434,8 @@ inline PieceType Position::captured_piece_type() const { return st->capturedType; } +inline Thread* Position::this_thread() const { + return thisThread; +} + #endif // !defined(POSITION_H_INCLUDED) diff --git a/src/search.cpp b/src/search.cpp index ebbff3a4..920310da 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -332,7 +332,7 @@ finalize: // but if we are pondering or in infinite search, we shouldn't print the best // move before we are told to do so. if (!Signals.stop && (Limits.ponder || Limits.infinite)) - this_thread->wait_for_stop_or_ponderhit(); + pos.this_thread()->wait_for_stop_or_ponderhit(); // Best move could be MOVE_NONE when searching on a stalemate position cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], Chess960) @@ -543,7 +543,7 @@ namespace { bool isPvMove, inCheck, singularExtensionNode, givesCheck; bool captureOrPromotion, dangerous, doFullDepthSearch; int moveCount = 0, playedMoveCount = 0; - Thread* thisThread = this_thread; + Thread* thisThread = pos.this_thread(); SplitPoint* sp = NULL; refinedValue = bestValue = value = -VALUE_INFINITE; @@ -1825,7 +1825,7 @@ void Thread::idle_loop(SplitPoint* sp_master) { lock_release(Threads.splitLock); Stack ss[MAX_PLY_PLUS_2]; - Position pos(*sp->pos); + Position pos(*sp->pos, this); memcpy(ss, sp->ss - 1, 4 * sizeof(Stack)); (ss+1)->sp = sp; diff --git a/src/thread.cpp b/src/thread.cpp index 7b9a4f32..fe7a669b 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -28,22 +28,17 @@ using namespace Search; ThreadsManager Threads; // Global object -THREAD_LOCAL Thread* this_thread; // Thread local variable namespace { extern "C" { // start_routine() is the C function which is called when a new thread // is launched. It is a wrapper to member function pointed by start_fn. - long start_routine(Thread* th) { - - this_thread = th; // Save pointer into thread local storage - (th->*(th->start_fn))(); - return 0; - } + long start_routine(Thread* th) { (th->*(th->start_fn))(); return 0; } } } + // Thread c'tor starts a newly-created thread of execution that will call // the idle loop function pointed by start_fn going immediately to sleep. @@ -210,7 +205,6 @@ void ThreadsManager::init() { lock_init(splitLock); timer = new Thread(&Thread::timer_loop); threads.push_back(new Thread(&Thread::main_loop)); - this_thread = main_thread(); // Use main thread's resources read_uci_options(); } @@ -313,7 +307,7 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, assert(beta <= VALUE_INFINITE); assert(depth > DEPTH_ZERO); - Thread* master = this_thread; + Thread* master = pos.this_thread(); if (master->splitPointsCnt >= MAX_SPLITPOINTS_PER_THREAD) return bestValue; @@ -440,7 +434,7 @@ void ThreadsManager::start_searching(const Position& pos, const LimitsType& limi Signals.stopOnPonderhit = Signals.firstRootMove = false; Signals.stop = Signals.failedLowAtRoot = false; - RootPosition = pos; + RootPosition.copy(pos, main_thread()); Limits = limits; RootMoves.clear(); diff --git a/src/thread.h b/src/thread.h index e03578ee..3eb8fc9c 100644 --- a/src/thread.h +++ b/src/thread.h @@ -119,7 +119,7 @@ public: bool use_sleeping_threads() const { return useSleepingThreads; } int min_split_depth() const { return minimumSplitDepth; } int size() const { return (int)threads.size(); } - Thread* main_thread() const { return threads[0]; } + Thread* main_thread() { return threads[0]; } void wake_up() const; void sleep() const; @@ -146,6 +146,5 @@ private: }; extern ThreadsManager Threads; -extern THREAD_LOCAL Thread* this_thread; #endif // !defined(THREAD_H_INCLUDED) diff --git a/src/types.h b/src/types.h index 2a3b41fa..031cb0ba 100644 --- a/src/types.h +++ b/src/types.h @@ -64,12 +64,6 @@ # define FORCE_INLINE inline #endif -#if defined(__GNUC__) -# define THREAD_LOCAL __thread -#else -# define THREAD_LOCAL __declspec(thread) -#endif - #if defined(USE_POPCNT) const bool HasPopCnt = true; #else diff --git a/src/uci.cpp b/src/uci.cpp index dd4040d7..c6da2fc4 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -56,7 +56,7 @@ namespace { void uci_loop(const string& args) { - Position pos(StartFEN, false); // The root position + Position pos(StartFEN, false, Threads.main_thread()); // The root position string cmd, token; while (token != "quit") @@ -167,7 +167,7 @@ namespace { else return; - pos.from_fen(fen, Options["UCI_Chess960"]); + pos.from_fen(fen, Options["UCI_Chess960"], Threads.main_thread()); // Parse move list (if any) while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE)