diff --git a/src/application.cpp b/src/application.cpp
new file mode 100644
index 00000000..b7ebbbb9
--- /dev/null
+++ b/src/application.cpp
@@ -0,0 +1,80 @@
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+ Copyright (C) 2008 Marco Costalba
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+
+////
+//// Includes
+////
+
+#include "bitboard.h"
+#include "direction.h"
+#include "endgame.h"
+#include "evaluate.h"
+#include "material.h"
+#include "mersenne.h"
+#include "misc.h"
+#include "movepick.h"
+#include "position.h"
+#include "search.h"
+#include "thread.h"
+#include "ucioption.h"
+
+
+/// Application class is in charge of initializing global resources
+/// at startup and cleanly releases them when program terminates.
+
+Application::Application() {
+
+ init_mersenne();
+ init_direction_table();
+ init_bitboards();
+ init_uci_options();
+ Position::init_zobrist();
+ Position::init_piece_square_tables();
+ MovePicker::init_phase_table();
+ init_eval(1);
+ init_bitbases();
+ init_threads();
+
+ // Make random number generation less deterministic, for book moves
+ for (int i = abs(get_system_time() % 10000); i > 0; i--)
+ genrand_int32();
+}
+
+Application::~Application() {
+
+ stop_threads();
+ quit_eval();
+}
+
+void Application::initialize() {
+
+ instance();
+}
+
+Application& Application::instance() {
+
+ static Application singleton;
+ return singleton;
+}
+
+void Application::exit_with_failure() {
+
+ exit(EXIT_FAILURE); // d'tor will be called automatically
+}
diff --git a/src/application.h b/src/application.h
new file mode 100644
index 00000000..f7149384
--- /dev/null
+++ b/src/application.h
@@ -0,0 +1,46 @@
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+ Copyright (C) 2008 Marco Costalba
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+
+#if !defined(APPLICATION_H_INCLUDED)
+#define APPLICATION_H_INCLUDED
+
+
+/// Singleton class used to housekeep memory and global resources
+/// so to be sure we always leave in a clean state.
+
+class Application {
+
+ Application();
+ Application(const Application&);
+
+public:
+ static void initialize();
+ static void exit_with_failure();
+
+ ~Application();
+
+private:
+ static Application& instance();
+
+ void init();
+ void deallocateAll();
+};
+
+#endif // !defined(APPLICATION_H_INCLUDED)
diff --git a/src/benchmark.cpp b/src/benchmark.cpp
index 9b1b4009..6e8357f2 100644
--- a/src/benchmark.cpp
+++ b/src/benchmark.cpp
@@ -79,15 +79,14 @@ void benchmark(const std::string& commandLine) {
if (val < 4 || val > 1024)
{
std::cerr << "The hash table size must be between 4 and 1024" << std::endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
csStr >> threads;
csVal >> val;
if (val < 1 || val > THREAD_MAX)
{
- std::cerr << "The number of threads must be between 1 and " << THREAD_MAX
- << std::endl;
- exit(EXIT_FAILURE);
+ std::cerr << "The number of threads must be between 1 and " << THREAD_MAX << std::endl;
+ Application::exit_with_failure();
}
set_option_value("Hash", ttSize);
set_option_value("Threads", threads);
@@ -115,9 +114,8 @@ void benchmark(const std::string& commandLine) {
std::ifstream fenFile(fileName.c_str());
if (!fenFile.is_open())
{
- std::cerr << "Unable to open positions file " << fileName
- << std::endl;
- exit(EXIT_FAILURE);
+ std::cerr << "Unable to open positions file " << fileName << std::endl;
+ Application::exit_with_failure();
}
std::string pos;
while (fenFile.good())
@@ -141,7 +139,8 @@ void benchmark(const std::string& commandLine) {
int dummy[2] = {0, 0};
Position pos(*it);
std::cout << "\nProcessing position " << cnt << '/' << positions.size() << std::endl << std::endl;
- think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves);
+ if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
+ break;
totalNodes += nodes_searched();
}
std::cout << "\nProcessing time (ms) " << get_system_time() - startTime << std::endl
diff --git a/src/book.cpp b/src/book.cpp
index c69eab73..c6e1e436 100644
--- a/src/book.cpp
+++ b/src/book.cpp
@@ -372,7 +372,7 @@ void Book::open(const string& fName) {
if (!good())
{
cerr << "Failed to open book file " << fileName << endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
}
@@ -489,7 +489,7 @@ void Book::read_entry(BookEntry& entry, int idx) {
if (!good())
{
cerr << "Failed to read book entry at index " << idx << endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
}
diff --git a/src/evaluate.cpp b/src/evaluate.cpp
index c29fd5e6..d4fdac21 100644
--- a/src/evaluate.cpp
+++ b/src/evaluate.cpp
@@ -505,6 +505,8 @@ void quit_eval() {
{
delete PawnTable[i];
delete MaterialTable[i];
+ PawnTable[i] = NULL;
+ MaterialTable[i] = NULL;
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 01fb4786..36534ae3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -20,32 +20,24 @@
// To profile with callgrind uncomment following line
//#define USE_CALLGRIND
+
////
//// Includes
////
#include
+#include
#include "benchmark.h"
-#include "bitboard.h"
-#include "direction.h"
-#include "endgame.h"
-#include "evaluate.h"
-#include "material.h"
-#include "mersenne.h"
#include "misc.h"
-#include "movepick.h"
-#include "position.h"
-#include "search.h"
-#include "thread.h"
#include "uci.h"
-#include "ucioption.h"
#ifdef USE_CALLGRIND
#include
#endif
-using std::string;
+using namespace std;
+
////
//// Functions
@@ -54,54 +46,38 @@ using std::string;
int main(int argc, char *argv[]) {
// Disable IO buffering
- std::cout.rdbuf()->pubsetbuf(NULL, 0);
- std::cin.rdbuf()->pubsetbuf(NULL, 0);
+ cout.rdbuf()->pubsetbuf(NULL, 0);
+ cin.rdbuf()->pubsetbuf(NULL, 0);
- // Initialization
- init_mersenne();
- init_direction_table();
- init_bitboards();
- init_uci_options();
- Position::init_zobrist();
- Position::init_piece_square_tables();
- MovePicker::init_phase_table();
- init_eval(1);
- init_bitbases();
- init_threads();
+ // Initialization through global resources manager
+ Application::initialize();
#ifdef USE_CALLGRIND
CALLGRIND_START_INSTRUMENTATION;
#endif
- // Make random number generation less deterministic, for book moves
- for (int i = abs(get_system_time() % 10000); i > 0; i--)
- genrand_int32();
-
- // Process command line arguments
- if (argc >= 2 && string(argv[1]) == "bench")
+ // Process command line arguments if any
+ if (argc > 1)
{
- if (argc < 4 || argc > 7)
+ if (string(argv[1]) != "bench" || argc < 4 || argc > 7)
+ cout << "Usage: stockfish bench "
+ << "[time = 60s] [fen positions file = default] "
+ << "[time, depth or node limited = time]" << endl;
+ else
{
- std::cout << "Usage: stockfish bench "
- << "[time = 60s] [fen positions file = default] "
- << "[time, depth or node limited = time]"
- << std::endl;
- exit(0);
+ string time = argc > 4 ? argv[4] : "60";
+ string fen = argc > 5 ? argv[5] : "default";
+ string lim = argc > 6 ? argv[6] : "time";
+ benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim);
}
- string time = argc > 4 ? argv[4] : "60";
- string fen = argc > 5 ? argv[5] : "default";
- string lim = argc > 6 ? argv[6] : "time";
- benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim);
return 0;
}
// Print copyright notice
- std::cout << engine_name() << ". Copyright (C) "
- << "2004-2008 Tord Romstad, Marco Costalba. "
- << std::endl;
+ cout << engine_name() << ". Copyright (C) "
+ << "2004-2008 Tord Romstad, Marco Costalba. " << endl;
// Enter UCI mode
uci_main_loop();
-
return 0;
}
diff --git a/src/material.cpp b/src/material.cpp
index 442dab56..b5f85de1 100644
--- a/src/material.cpp
+++ b/src/material.cpp
@@ -90,7 +90,7 @@ MaterialInfoTable::MaterialInfoTable(unsigned int numOfEntries) {
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo))
<< " bytes for material hash table." << std::endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
clear();
}
diff --git a/src/misc.h b/src/misc.h
index aff7cf3e..8c0a1f05 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -29,6 +29,7 @@
#include
#include
+#include "application.h"
////
//// Macros
@@ -47,6 +48,7 @@ extern int get_system_time();
extern int cpu_count();
extern int Bioskey();
+
////
//// Debug
////
diff --git a/src/pawns.cpp b/src/pawns.cpp
index f06d9f12..f34095b9 100644
--- a/src/pawns.cpp
+++ b/src/pawns.cpp
@@ -144,7 +144,7 @@ PawnInfoTable::PawnInfoTable(unsigned numOfEntries) {
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
<< " bytes for pawn hash table." << std::endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
clear();
}
diff --git a/src/search.cpp b/src/search.cpp
index 64863be1..6250f02f 100644
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -359,10 +359,11 @@ void SearchStack::initKillers() {
////
/// think() is the external interface to Stockfish's search, and is called when
-/// the program receives the UCI 'go' command. It initializes various
-/// search-related global variables, and calls root_search()
+/// the program receives the UCI 'go' command. It initializes various
+/// search-related global variables, and calls root_search(). It returns false
+/// when a quit command is received during the search.
-void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
+bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]) {
@@ -377,7 +378,7 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
if (bookMove != MOVE_NONE)
{
std::cout << "bestmove " << bookMove << std::endl;
- return;
+ return true;
}
}
@@ -541,13 +542,8 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
if (UseLogFile)
LogFile.close();
- if (Quit)
- {
- stop_threads();
- quit_eval();
- exit(0);
- }
Idle = true;
+ return !Quit;
}
@@ -2454,6 +2450,7 @@ namespace {
AbortSearch = true;
PonderSearch = false;
Quit = true;
+ return;
}
else if(command == "stop")
{
@@ -2551,19 +2548,21 @@ namespace {
// after which the bestmove and pondermove will be printed (in id_loop()).
void wait_for_stop_or_ponderhit() {
+
std::string command;
- while(true) {
- if(!std::getline(std::cin, command))
- command = "quit";
+ while (true)
+ {
+ if (!std::getline(std::cin, command))
+ command = "quit";
- if(command == "quit") {
- stop_threads();
- quit_eval();
- exit(0);
- }
- else if(command == "ponderhit" || command == "stop")
- break;
+ if (command == "quit")
+ {
+ Quit = true;
+ break;
+ }
+ else if(command == "ponderhit" || command == "stop")
+ break;
}
}
diff --git a/src/search.h b/src/search.h
index 0323d47e..bef8bf2e 100644
--- a/src/search.h
+++ b/src/search.h
@@ -84,7 +84,7 @@ extern History H;
extern void init_threads();
extern void stop_threads();
-extern void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
+extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]);
extern int64_t nodes_searched();
diff --git a/src/tt.cpp b/src/tt.cpp
index 83eaf800..a0cc7922 100644
--- a/src/tt.cpp
+++ b/src/tt.cpp
@@ -69,7 +69,7 @@ void TranspositionTable::set_size(unsigned mbSize) {
{
std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << std::endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
clear();
}
diff --git a/src/uci.cpp b/src/uci.cpp
index 9c13eff7..4c9d90e5 100644
--- a/src/uci.cpp
+++ b/src/uci.cpp
@@ -56,11 +56,10 @@ namespace {
Position RootPosition;
// Local functions
- void get_command();
- void handle_command(const std::string &command);
- void set_option(UCIInputParser &uip);
- void set_position(UCIInputParser &uip);
- void go(UCIInputParser &uip);
+ bool handle_command(const std::string& command);
+ void set_option(UCIInputParser& uip);
+ void set_position(UCIInputParser& uip);
+ bool go(UCIInputParser& uip);
}
@@ -68,17 +67,25 @@ namespace {
//// Functions
////
-/// uci_main_loop() is the only global function in this file. It is
+/// uci_main_loop() is the only global function in this file. It is
/// called immediately after the program has finished initializing.
/// The program remains in this loop until it receives the "quit" UCI
-/// command.
+/// command. It waits for a command from the user, and passes this
+/// command to handle_command and also intercepts EOF from stdin,
+/// by translating EOF to the "quit" command. This ensures that Stockfish
+/// exits gracefully if the GUI dies unexpectedly.
void uci_main_loop() {
RootPosition.from_fen(StartPosition);
+ std::string command;
- while (1)
- get_command();
+ do {
+ // Wait for a command from stdin
+ if (!std::getline(std::cin, command))
+ command = "quit";
+
+ } while (handle_command(command));
}
@@ -88,29 +95,12 @@ void uci_main_loop() {
namespace {
- // get_command() waits for a command from the user, and passes
- // this command to handle_command. get_command also intercepts
- // EOF from stdin, by translating EOF to the "quit" command. This
- // ensures that Stockfish exits gracefully if the GUI dies
- // unexpectedly.
-
- void get_command() {
-
- std::string command;
-
- if (!std::getline(std::cin, command))
- command = "quit";
-
- handle_command(command);
- }
-
-
// handle_command() takes a text string as input, uses a
// UCIInputParser object to parse this text string as a UCI command,
- // and calls the appropriate functions. In addition to the UCI
+ // and calls the appropriate functions. In addition to the UCI
// commands, the function also supports a few debug commands.
- void handle_command(const std::string &command) {
+ bool handle_command(const std::string& command) {
UCIInputParser uip(command);
std::string token;
@@ -118,12 +108,12 @@ namespace {
uip >> token; // operator >> skips any whitespace
if (token == "quit")
- {
- stop_threads();
- quit_eval();
- exit(0);
- }
- else if (token == "uci")
+ return false;
+
+ if (token == "go")
+ return go(uip);
+
+ if (token == "uci")
{
std::cout << "id name " << engine_name() << std::endl
<< "id author Tord Romstad, Marco Costalba"
@@ -143,8 +133,6 @@ namespace {
set_position(uip);
else if (token == "setoption")
set_option(uip);
- else if (token == "go")
- go(uip);
// The remaining commands are for debugging purposes only.
// Perhaps they should be removed later in order to reduce the
@@ -183,6 +171,7 @@ namespace {
std::cout << token << std::endl;
}
}
+ return true;
}
@@ -192,7 +181,7 @@ namespace {
// ("position"), and is ready to read the second token ("startpos"
// or "fen", if the input is well-formed).
- void set_position(UCIInputParser &uip) {
+ void set_position(UCIInputParser& uip) {
std::string token;
@@ -242,7 +231,7 @@ namespace {
// ("setoption"), and is ready to read the second token ("name", if
// the input is well-formed).
- void set_option(UCIInputParser &uip) {
+ void set_option(UCIInputParser& uip) {
std::string token, name;
@@ -269,14 +258,15 @@ namespace {
// go() is called when Stockfish receives the "go" UCI command. The
- // input parameter is a UCIInputParser. It is assumed that this
+ // input parameter is a UCIInputParser. It is assumed that this
// parser has consumed the first token of the UCI command ("go"),
- // and is ready to read the second token. The function sets the
+ // and is ready to read the second token. The function sets the
// thinking time and other parameters from the input string, and
// calls think() (defined in search.cpp) with the appropriate
- // parameters.
+ // parameters. Returns false if a quit command is received while
+ // thinking, returns true otherwise.
- void go(UCIInputParser &uip) {
+ bool go(UCIInputParser& uip) {
std::string token;
@@ -328,7 +318,7 @@ namespace {
assert(RootPosition.is_ok());
- think(RootPosition, infinite, ponder, RootPosition.side_to_move(), time,
- inc, movesToGo, depth, nodes, moveTime, searchMoves);
+ return think(RootPosition, infinite, ponder, RootPosition.side_to_move(), time,
+ inc, movesToGo, depth, nodes, moveTime, searchMoves);
}
}