Browse Source

Fix pthread_mutex_lock abort() in requestActionASAP impl

Vadim Markovtsev 10 years ago
parent
commit
fa8a282696
5 changed files with 54 additions and 47 deletions
  1. 14 21
      AI/VCAI/VCAI.cpp
  2. 2 2
      server/CGameHandler.cpp
  3. 16 16
      server/CVCMIServer.cpp
  4. 8 8
      server/NetPacksServer.cpp
  5. 14 0
      server/StdInc.h

+ 14 - 21
AI/VCAI/VCAI.cpp

@@ -822,7 +822,7 @@ void VCAI::makeTurnInternal()
 		{
 			if (h->movement)
 				logAi->warnStream() << boost::format("hero %s has %d MP left") % h->name % h->movement;
-		}	
+		}
 	}
 	catch(boost::thread_interrupted &e)
 	{
@@ -891,7 +891,7 @@ bool VCAI::canGetArmy (const CGHeroInstance * army, const CGHeroInstance * sourc
 
 
 	const CArmedInstance *armies[] = {army, source};
- 
+
 	//we calculate total strength for each creature type available in armies
 	std::map<const CCreature*, int> creToPower;
 	for(auto armyPtr : armies)
@@ -988,7 +988,7 @@ void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance *
 }
 
 void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * other)
-{	
+{
 	auto equipBest = [](const CGHeroInstance * h, const CGHeroInstance * otherh, bool giveStuffToFirstHero) -> void
 	{
 		bool changeMade = false;
@@ -2059,7 +2059,7 @@ void VCAI::tryRealize(Goals::CollectRes & g)
 				cb->trade(obj, EMarketMode::RESOURCE_RESOURCE, i, g.resID, toGive);
 				if(cb->getResourceAmount(static_cast<Res::ERes>(g.resID)) >= g.value)
 					return;
-			} 
+			}
 
 			throw cannotFulfillGoalException("I cannot get needed resources by trade!");
 		}
@@ -2277,7 +2277,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on
 			completeGoal (goal);
 			//completed goal was main goal //TODO: find better condition
 			if (ultimateGoal->fulfillsMe(goal) || maxGoals > searchDepth2)
-				return sptr(Goals::Invalid()); 
+				return sptr(Goals::Invalid());
 		}
 		catch(std::exception &e)
 		{
@@ -2530,7 +2530,7 @@ int3 VCAI::explorationDesperate(HeroPtr h)
     //logAi->debugStream() << "Looking for an another place for exploration...";
 	SectorMap sm(h);
 	int radius = h->getSightRadious();
-	
+
 	std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
 	tiles.resize(radius);
 
@@ -2660,19 +2660,13 @@ void VCAI::finish()
 
 void VCAI::requestActionASAP(std::function<void()> whatToDo)
 {
-// 	static boost::mutex m;
-// 	boost::unique_lock<boost::mutex> mylock(m);
-
-	boost::barrier b(2);
-	boost::thread newThread([&b,this,whatToDo]()
+	boost::thread newThread([this, whatToDo]()
 	{
-		setThreadName("VCAI::requestActionASAP::helper");
+		setThreadName("VCAI::requestActionASAP::whatToDo");
 		SET_GLOBAL_STATE(this);
 		boost::shared_lock<boost::shared_mutex> gsLock(cb->getGsMutex());
-		b.wait();
 		whatToDo();
 	});
-	b.wait();
 }
 
 void VCAI::lostHero(HeroPtr h)
@@ -2867,8 +2861,8 @@ void AIStatus::heroVisit(const CGObjectInstance *obj, bool started)
 		objectsBeingVisited.push_back(obj);
 	else
 	{
-		// There can be more than one object visited at the time (eg. hero visits Subterranean Gate 
-		// causing visit to hero on the other side. 
+		// There can be more than one object visited at the time (eg. hero visits Subterranean Gate
+		// causing visit to hero on the other side.
 		// However, we are guaranteed that start/end visit notification maintain stack order.
 		assert(!objectsBeingVisited.empty());
 		objectsBeingVisited.pop_back();
@@ -2980,7 +2974,7 @@ void SectorMap::exploreNewSector(crint3 pos, int num, CCallback * cbp)
 							s.embarkmentPoints.push_back(neighPos);
 						}
 					});
-					
+
 					if(t->visitable)
 					{
 						auto obj = t->visitableObjects.front();
@@ -3036,7 +3030,7 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj)
 bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 {
 	switch (obj->ID)
-	{	
+	{
 		case Obj::TOWN:
 		case Obj::HERO: //never visit our heroes at random
 			return obj->tempOwner != h->tempOwner; //do not visit our towns at random
@@ -3087,7 +3081,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 			return canRecruitCreatures;
 		}
 		case Obj::HILL_FORT:
-		{	
+		{
 			for (auto slot : h->Slots())
 			{
 				if (slot.second->type->upgrades.size())
@@ -3386,7 +3380,7 @@ void SectorMap::makeParentBFS(crint3 source)
 		ui8 &sec = retreiveTile(curPos);
 		assert(sec == mySector); //consider only tiles from the same sector
 		UNUSED(sec);
-	
+
 		foreach_neighbour(curPos, [&](crint3 neighPos)
 		{
 			if(retreiveTile(neighPos) == mySector && !vstd::contains(parent, neighPos))
@@ -3405,4 +3399,3 @@ unsigned char & SectorMap::retreiveTile(crint3 pos)
 {
 	return retreiveTileN(sector, pos);
 }
-

+ 2 - 2
server/CGameHandler.cpp

@@ -5688,7 +5688,7 @@ bool CGameHandler::isValidObject(const CGObjectInstance *obj) const
 
 bool CGameHandler::isBlockedByQueries(const CPack *pack, PlayerColor player)
 {
-	if(dynamic_cast<const PlayerMessage*>(pack))
+	if(!strcmp(typeid(*pack).name(), typeid(PlayerMessage).name()))
 		return false;
 
 	auto query = queries.topQuery(player);
@@ -5826,7 +5826,7 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleI
 			auto warMachine = VLC->arth->creatureToMachineID(st->type->idNumber);
 			if (warMachine != ArtifactID::NONE)
 			{
-				auto hero = dynamic_cast<const CGHeroInstance*> (army);
+				auto hero = dynamic_ptr_cast<CGHeroInstance> (army);
 				if (hero)
 					removedWarMachines.push_back (ArtifactLocation(hero, hero->getArtPos(warMachine, true)));
 			}

+ 16 - 16
server/CVCMIServer.cpp

@@ -86,8 +86,8 @@ void CPregameServer::handleConnection(CConnection *cpc)
             logNetwork->infoStream() << "Got package to announce " << typeid(*cpfs).name() << " from " << *cpc;
 
 			boost::unique_lock<boost::recursive_mutex> queueLock(mx);
-			bool quitting = dynamic_cast<QuitMenuWithoutStarting*>(cpfs), 
-				startingGame = dynamic_cast<StartWithCurrentSettings*>(cpfs);
+			bool quitting = dynamic_ptr_cast<QuitMenuWithoutStarting>(cpfs),
+				startingGame = dynamic_ptr_cast<StartWithCurrentSettings>(cpfs);
 			if(quitting || startingGame) //host leaves main menu or wants to start game -> we end
 			{
 				cpc->receivedStop = true;
@@ -258,11 +258,11 @@ void CPregameServer::sendPack(CConnection * pc, const CPackForSelectionScreen &
 		*pc << &pack;
 	}
 
-	if(dynamic_cast<const QuitMenuWithoutStarting*>(&pack))
+	if(dynamic_ptr_cast<QuitMenuWithoutStarting>(&pack))
 	{
 		pc->sendStop = true;
 	}
-	else if(dynamic_cast<const StartWithCurrentSettings*>(&pack))
+	else if(dynamic_ptr_cast<StartWithCurrentSettings>(&pack))
 	{
 		pc->sendStop = true;
 	}
@@ -270,25 +270,25 @@ void CPregameServer::sendPack(CConnection * pc, const CPackForSelectionScreen &
 
 void CPregameServer::processPack(CPackForSelectionScreen * pack)
 {
-	if(dynamic_cast<CPregamePackToHost*>(pack))
+	if(dynamic_ptr_cast<CPregamePackToHost>(pack))
 	{
 		sendPack(host, *pack);
 	}
-	else if(SelectMap *sm = dynamic_cast<SelectMap*>(pack))
+	else if(SelectMap *sm = dynamic_ptr_cast<SelectMap>(pack))
 	{
 		vstd::clear_pointer(curmap);
 		curmap = sm->mapInfo;
 		sm->free = false;
 		announcePack(*pack);
 	}
-	else if(UpdateStartOptions *uso = dynamic_cast<UpdateStartOptions*>(pack))
+	else if(UpdateStartOptions *uso = dynamic_ptr_cast<UpdateStartOptions>(pack))
 	{
 		vstd::clear_pointer(curStartInfo);
 		curStartInfo = uso->options;
 		uso->free = false;
 		announcePack(*pack);
 	}
-	else if(dynamic_cast<const StartWithCurrentSettings*>(pack))
+	else if(dynamic_ptr_cast<StartWithCurrentSettings>(pack))
 	{
 		state = ENDING_AND_STARTING_GAME;
 		announcePack(*pack);
@@ -307,7 +307,7 @@ void CPregameServer::initConnection(CConnection *c)
 }
 
 void CPregameServer::startListeningThread(CConnection * pc)
-{	
+{
 	listeningThreads++;
 	pc->enterPregameConnectionMode();
 	pc->handler = new boost::thread(&CPregameServer::handleConnection, this, pc);
@@ -355,7 +355,7 @@ void CVCMIServer::newGame()
 {
 	CConnection &c = *firstConnection;
 	ui8 clients;
-	c >> clients; //how many clients should be connected 
+	c >> clients; //how many clients should be connected
 	assert(clients == 1); //multi goes now by newPregame, TODO: custom lobbies
 
 	CGameHandler *gh = initGhFromHostingConnection(c);
@@ -469,14 +469,14 @@ void CVCMIServer::loadGame()
 // 		char sig[8];
 // 		CMapHeader dum;
 // 		StartInfo *si;
-// 
+//
 // 		CLoadFile lf(CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::LIB_SAVEGAME)));
 // 		lf >> sig >> dum >> si;
 // 		logNetwork->infoStream() <<"Reading save signature";
-// 
+//
 // 		lf >> *VLC;
 // 		logNetwork->infoStream() <<"Reading handlers";
-// 
+//
 // 		lf >> (gh.gs);
 // 		c.addStdVecItems(gh.gs);
 // 		logNetwork->infoStream() <<"Reading gamestate";
@@ -493,7 +493,7 @@ void CVCMIServer::loadGame()
 	CConnection* cc; //tcp::socket * ss;
 	for(int i=0; i<clients; i++)
 	{
-		if(!i) 
+		if(!i)
 		{
 			cc = &c;
 		}
@@ -508,7 +508,7 @@ void CVCMIServer::loadGame()
 				continue;
 			}
 			cc = new CConnection(s,NAME);
-		}	
+		}
 		gh.conns.insert(cc);
 	}
 
@@ -531,7 +531,7 @@ static void handleCommandOptions(int argc, char *argv[])
 		{
 			po::store(po::parse_command_line(argc, argv, opts), cmdLineOptions);
 		}
-		catch(std::exception &e) 
+		catch(std::exception &e)
 		{
 			std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl;
 		}

+ 8 - 8
server/NetPacksServer.cpp

@@ -89,7 +89,7 @@ bool MoveHero::applyGh( CGameHandler *gh )
 bool CastleTeleportHero::applyGh( CGameHandler *gh )
 {
 	ERROR_IF_NOT_OWNS(hid);
-	
+
 	return gh->teleportHero(hid,dest,source,gh->getPlayerAt(c));
 }
 
@@ -126,7 +126,7 @@ bool GarrisonHeroSwap::applyGh( CGameHandler *gh )
 {
 	const CGTownInstance * town = gh->getTown(tid);
 	if (!PLAYER_OWNS(tid) && !( town->garrisonHero && PLAYER_OWNS(town->garrisonHero->id) ) )
-		ERROR_AND_RETURN;//neither town nor garrisoned hero (if present) is ours 
+		ERROR_AND_RETURN;//neither town nor garrisoned hero (if present) is ours
 	return gh->garrisonSwap(tid);
 }
 
@@ -201,7 +201,7 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh )
 }
 
 bool SetFormation::applyGh( CGameHandler *gh )
-{	
+{
 	ERROR_IF_NOT_OWNS(hid);
 	return gh->setFormation(hid,formation);
 }
@@ -209,7 +209,7 @@ bool SetFormation::applyGh( CGameHandler *gh )
 bool HireHero::applyGh( CGameHandler *gh )
 {
 	const CGObjectInstance *obj = gh->getObj(tid);
-	const CGTownInstance *town = dynamic_cast<const CGTownInstance *>(obj);
+	const CGTownInstance *town = dynamic_ptr_cast<CGTownInstance>(obj);
 	if(town && PlayerRelations::ENEMIES == gh->getPlayerRelations(obj->tempOwner, gh->getPlayerAt(c)))
 		COMPLAIN_AND_RETURN("Can't buy hero in enemy town!");
 
@@ -240,16 +240,16 @@ bool MakeAction::applyGh( CGameHandler *gh )
 {
 	const BattleInfo *b = GS(gh)->curB;
 	if(!b) ERROR_AND_RETURN;
-	
+
 	if(b->tacticDistance)
 	{
-		if(ba.actionType != Battle::WALK  &&  ba.actionType != Battle::END_TACTIC_PHASE  
+		if(ba.actionType != Battle::WALK  &&  ba.actionType != Battle::END_TACTIC_PHASE
 			&& ba.actionType != Battle::RETREAT && ba.actionType != Battle::SURRENDER)
 			ERROR_AND_RETURN;
-		if(gh->connections[b->sides[b->tacticsSide].color] != c) 
+		if(gh->connections[b->sides[b->tacticsSide].color] != c)
 			ERROR_AND_RETURN;
 	}
-	else if(gh->connections[b->battleGetStackByID(b->activeStack)->owner] != c) 
+	else if(gh->connections[b->battleGetStackByID(b->activeStack)->owner] != c)
 		ERROR_AND_RETURN;
 
 	return gh->makeBattleAction(ba);

+ 14 - 0
server/StdInc.h

@@ -22,3 +22,17 @@ inline const T * dynamic_ptr_cast(const F * ptr)
 	return nullptr;
 	#endif
 }
+
+template<class T, class F>
+inline T * dynamic_ptr_cast(F * ptr)
+{
+	#ifndef __APPLE__
+  return dynamic_cast<T*>(ptr);
+	#else
+	if (!strcmp(typeid(*ptr).name(), typeid(T).name()))
+	{
+		return static_cast<T*>(ptr);
+	}
+	return nullptr;
+	#endif
+}