1
0
forked from 0ad/0ad

Fix OOS introduced by pathfinder threading preparation diff d592bf9cb6

Following d592bf9cb6, paths were computed at the end of turn N, and then
messages were sent at the beginning of turn N+1. However, the path
requests were removed at the end of turn N and so weren't serialised,
and neither were computed paths. This meant rejoiners would OOS when the
game was serialised with pending path results.

To fix this in preparation for threading, the architecture needs to
change slightly so that requests are kept and serialised correctly, and
rejoiners can compute the paths after deserialisation, in order to send
the messages at the beginning of turn N+1.

Fixes #5604

Reported By: elexis
Differential Revision: https://code.wildfiregames.com/D2317
This was SVN commit r22979.
This commit is contained in:
wraitii 2019-09-23 06:38:16 +00:00
parent 83b7dac3f4
commit 92ad6a61fa
2 changed files with 23 additions and 14 deletions

View File

@ -185,6 +185,15 @@ void CCmpPathfinder::HandleMessage(const CMessage& msg, bool UNUSED(global))
m_TerrainDirty = true;
UpdateGrid();
break;
case MT_Deserialized:
UpdateGrid();
// In case we were serialised with requests pending, we need to process them.
if (!m_ShortPathRequests.empty() || !m_LongPathRequests.empty())
{
ENSURE(CmpPtr<ICmpObstructionManager>(GetSystemEntity()));
StartProcessingMoves(false);
}
break;
}
}
@ -773,6 +782,10 @@ void CCmpPathfinder::FetchAsyncResultsAndSendMessages()
{
PROFILE2("FetchAsyncResults");
// We may now clear existing requests.
m_ShortPathRequests.clear();
m_LongPathRequests.clear();
// WARNING: the order in which moves are pulled must be consistent when using 1 or n workers.
// We fetch in the same order we inserted in, but we push moves backwards, so this works.
std::vector<PathResult> results;
@ -794,8 +807,8 @@ void CCmpPathfinder::FetchAsyncResultsAndSendMessages()
void CCmpPathfinder::StartProcessingMoves(bool useMax)
{
std::vector<LongPathRequest> longRequests = PopMovesToProcess(m_LongPathRequests, useMax, m_MaxSameTurnMoves);
std::vector<ShortPathRequest> shortRequests = PopMovesToProcess(m_ShortPathRequests, useMax, m_MaxSameTurnMoves - longRequests.size());
std::vector<LongPathRequest> longRequests = GetMovesToProcess(m_LongPathRequests, useMax, m_MaxSameTurnMoves);
std::vector<ShortPathRequest> shortRequests = GetMovesToProcess(m_ShortPathRequests, useMax, m_MaxSameTurnMoves - longRequests.size());
PushRequestsToWorkers(longRequests);
PushRequestsToWorkers(shortRequests);
@ -805,25 +818,20 @@ void CCmpPathfinder::StartProcessingMoves(bool useMax)
}
template <typename T>
std::vector<T> CCmpPathfinder::PopMovesToProcess(std::vector<T>& requests, bool useMax, size_t maxMoves)
std::vector<T> CCmpPathfinder::GetMovesToProcess(std::vector<T>& requests, bool useMax, size_t maxMoves)
{
std::vector<T> poppedRequests;
// Keep the original requests in which we need to serialize.
std::vector<T> copiedRequests;
if (useMax)
{
size_t amount = std::min(requests.size(), maxMoves);
if (amount > 0)
{
poppedRequests.insert(poppedRequests.begin(), std::make_move_iterator(requests.end() - amount), std::make_move_iterator(requests.end()));
requests.erase(requests.end() - amount, requests.end());
}
copiedRequests.insert(copiedRequests.begin(), requests.end() - amount, requests.end());
}
else
{
poppedRequests.swap(requests);
requests.clear();
}
copiedRequests = requests;
return poppedRequests;
return copiedRequests;
}
template <typename T>

View File

@ -87,6 +87,7 @@ protected:
public:
static void ClassInit(CComponentManager& componentManager)
{
componentManager.SubscribeToMessageType(MT_Deserialized);
componentManager.SubscribeToMessageType(MT_Update);
componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
componentManager.SubscribeToMessageType(MT_TerrainChanged);
@ -225,7 +226,7 @@ public:
virtual void StartProcessingMoves(bool useMax);
template <typename T>
std::vector<T> PopMovesToProcess(std::vector<T>& requests, bool useMax = false, size_t maxMoves = 0);
std::vector<T> GetMovesToProcess(std::vector<T>& requests, bool useMax = false, size_t maxMoves = 0);
template <typename T>
void PushRequestsToWorkers(std::vector<T>& from);