Bladeren bron

Automated testing: graceful shutdown for when game is ended

Before when CloseServer / LeaveGame applied there was no thread sync on server.
Now server use std::atomic bool for synchronization and graceful shutdown.
Arseniy Shestakov 8 jaren geleden
bovenliggende
commit
a2284c3209
6 gewijzigde bestanden met toevoegingen van 39 en 30 verwijderingen
  1. 1 0
      Global.h
  2. 5 4
      client/CMT.cpp
  3. 14 11
      client/Client.cpp
  4. 4 0
      client/NetPacksClient.cpp
  5. 10 10
      server/CGameHandler.cpp
  6. 5 5
      server/CVCMIServer.cpp

+ 1 - 0
Global.h

@@ -143,6 +143,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #include <unordered_map>
 #include <utility>
 #include <vector>
+#include <atomic>
 
 //The only available version is 3, as of Boost 1.50
 #include <boost/version.hpp>

+ 5 - 4
client/CMT.cpp

@@ -517,9 +517,10 @@ int main(int argc, char** argv)
 		bfs::path fileToStartFrom; //none by default
 		if(vm.count("start"))
 			fileToStartFrom = vm["start"].as<bfs::path>();
-		std::string testmap;
 		if(vm.count("testmap"))
-			testmap = vm["testmap"].as<std::string>();
+		{
+			session["testmap"].String() = vm["testmap"].as<std::string>();
+		}
 
 		session["spectate"].Bool() = vm.count("spectate");
 		if(session["spectate"].Bool())
@@ -532,9 +533,9 @@ int main(int argc, char** argv)
 			if(vm.count("spectate-battle-speed"))
 				session["spectate-battle-speed"].Float() = vm["spectate-battle-speed"].as<int>();
 		}
-		if(!testmap.empty())
+		if(!session["testmap"].isNull())
 		{
-			startTestMap(testmap);
+			startTestMap(session["testmap"].String());
 		}
 		else
 		{

+ 14 - 11
client/Client.cpp

@@ -714,19 +714,22 @@ void CClient::stopConnection()
 {
 	terminate = true;
 
-	if (serv && serv->isHost()) //request closing connection
+	if(serv)
 	{
-		logNetwork->infoStream() << "Connection has been requested to be closed.";
 		boost::unique_lock<boost::mutex>(*serv->wmx);
-		CloseServer close_server;
-		sendRequest(&close_server, PlayerColor::NEUTRAL);
-		logNetwork->infoStream() << "Sent closing signal to the server";
-	}
-	else
-	{
-		LeaveGame leave_Game;
-		sendRequest(&leave_Game, PlayerColor::NEUTRAL);
-		logNetwork->infoStream() << "Sent leaving signal to the server";
+		if(serv->isHost()) //request closing connection
+		{
+			logNetwork->infoStream() << "Connection has been requested to be closed.";
+			CloseServer close_server;
+			sendRequest(&close_server, PlayerColor::NEUTRAL);
+			logNetwork->infoStream() << "Sent closing signal to the server";
+		}
+		else
+		{
+			LeaveGame leave_Game;
+			sendRequest(&leave_Game, PlayerColor::NEUTRAL);
+			logNetwork->infoStream() << "Sent leaving signal to the server";
+		}
 	}
 
 	if(connectionHandler)//end connection handler

+ 4 - 0
client/NetPacksClient.cpp

@@ -302,6 +302,10 @@ void ChangeObjPos::applyCl(CClient *cl)
 void PlayerEndsGame::applyCl(CClient *cl)
 {
 	CALL_IN_ALL_INTERFACES(gameOver, player, victoryLossCheckResult);
+
+	// In auto testing mode we always close client if red player won or lose
+	if(!settings["session"]["testmap"].isNull() && player == PlayerColor(0))
+		handleQuit(settings["session"]["spectate"].Bool()); // if spectator is active ask to close client or not
 }
 
 void RemoveBonus::applyCl(CClient *cl)

+ 10 - 10
server/CGameHandler.cpp

@@ -48,7 +48,7 @@
 #ifndef _MSC_VER
 #include <boost/thread/xtime.hpp>
 #endif
-extern bool end2;
+extern std::atomic<bool> serverShuttingDown;
 #ifdef min
 #undef min
 #endif
@@ -1033,12 +1033,13 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
 
 	auto handleDisconnection = [&](const std::exception & e)
 	{
+		boost::unique_lock<boost::mutex> lock(*c.wmx);
 		assert(!c.connected); //make sure that connection has been marked as broken
 		logGlobal->error(e.what());
 		conns -= &c;
 		for(auto playerConn : connections)
 		{
-			if(playerConn.second == &c)
+			if(!serverShuttingDown && playerConn.second == &c)
 			{
 				PlayerCheated pc;
 				pc.player = playerConn.first;
@@ -1128,7 +1129,7 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
 	}
 	catch(...)
 	{
-		end2 = true;
+		serverShuttingDown = true;
 		handleException();
 		throw;
 	}
@@ -1902,7 +1903,7 @@ void CGameHandler::run(bool resume)
 	if (gs->scenarioOps->mode == StartInfo::DUEL)
 	{
 		runBattle();
-		end2 = true;
+		serverShuttingDown = true;
 
 
 		while(conns.size() && (*conns.begin())->isOpen())
@@ -1913,7 +1914,7 @@ void CGameHandler::run(bool resume)
 
 	auto playerTurnOrder = generatePlayerTurnOrder();
 
-	while(!end2)
+	while(!serverShuttingDown)
 	{
 		if (!resume) newTurn();
 
@@ -1954,7 +1955,7 @@ void CGameHandler::run(bool resume)
 
 					//wait till turn is done
 					boost::unique_lock<boost::mutex> lock(states.mx);
-					while (states.players.at(playerColor).makingTurn && !end2)
+					while(states.players.at(playerColor).makingTurn && !serverShuttingDown)
 					{
 						static time_duration p = milliseconds(100);
 						states.cv.timed_wait(lock, p);
@@ -1970,7 +1971,7 @@ void CGameHandler::run(bool resume)
 					activePlayer = true;
 		}
 		if (!activePlayer)
-			end2 = true;
+			serverShuttingDown = true;
 	}
 	while(conns.size() && (*conns.begin())->isOpen())
 		boost::this_thread::sleep(boost::posix_time::milliseconds(5)); //give time client to close socket
@@ -2734,7 +2735,7 @@ void CGameHandler::close()
 	{
 		exit(0);
 	}
-	end2 = true;
+	serverShuttingDown = true;
 
 	for (auto & elem : conns)
 	{
@@ -2745,7 +2746,6 @@ void CGameHandler::close()
 		elem->close();
 		elem->connected = false;
 	}
-	exit(0);
 }
 
 void CGameHandler::playerLeftGame(int cid)
@@ -5103,7 +5103,7 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
 
 			if (p->human)
 			{
-				end2 = true;
+				serverShuttingDown = true;
 
 				if (gs->scenarioOps->campState)
 				{

+ 5 - 5
server/CVCMIServer.cpp

@@ -44,7 +44,7 @@ std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX
 #ifndef VCMI_ANDROID
 namespace intpr = boost::interprocess;
 #endif
-bool end2 = false;
+std::atomic<bool> serverShuttingDown(false);
 
 boost::program_options::variables_map cmdLineOptions;
 
@@ -107,7 +107,7 @@ void CPregameServer::handleConnection(CConnection *cpc)
 			}
 			else if(quitting) // Server must be stopped if host is leaving from lobby to avoid crash
 			{
-				end2 = true;
+				serverShuttingDown = true;
 			}
 		}
 	}
@@ -477,7 +477,7 @@ void CVCMIServer::start()
 			std::string name = NAME;
 			firstConnection = new CConnection(s, name.append(" STATE_WAITING"));
 			logNetwork->info("Got connection!");
-			while(!end2)
+			while(!serverShuttingDown)
 			{
 				ui8 mode;
 				*firstConnection >> mode;
@@ -649,7 +649,7 @@ int main(int argc, char** argv)
 
 		try
 		{
-			while (!end2)
+			while(!serverShuttingDown)
 			{
 				server.start();
 			}
@@ -658,7 +658,7 @@ int main(int argc, char** argv)
 		catch (boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
 		{
 			logNetwork->error(e.what());
-			end2 = true;
+			serverShuttingDown = true;
 		}
 		catch (...)
 		{