Pause the game instead of blocking when link graph jobs lag.
Check if the job is still running one date fract tick before it is due to join and if so pause the game until its done. This avoids the main thread being blocked on a thread join. Show if pause is due to link graph job in status bar, update network messages. This does not apply for network clients.
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include "demands.h"
|
||||
#include "mcf.h"
|
||||
#include "flowmapper.h"
|
||||
#include "../command_func.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -49,6 +50,16 @@ void LinkGraphSchedule::SpawnNext()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the next finished job, if available.
|
||||
*/
|
||||
bool LinkGraphSchedule::IsJoinWithUnfinishedJobDue() const
|
||||
{
|
||||
if (this->running.empty()) return false;
|
||||
const LinkGraphJob *next = this->running.front();
|
||||
return next->IsFinished() && !next->IsJobCompleted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the next finished job, if available.
|
||||
*/
|
||||
@@ -78,6 +89,21 @@ void LinkGraphSchedule::JoinNext()
|
||||
for (uint i = 0; i < lengthof(instance.handlers); ++i) {
|
||||
instance.handlers[i]->Run(*job);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that this it not guaranteed to be an atomic write and there are no memory barriers or other protections.
|
||||
* Readers of this variable in another thread may see an out of date value.
|
||||
* However this is OK as this will only happen just as a job is completing, and the real synchronisation is provided
|
||||
* by the thread join operation. In the worst case the main thread will be paused for longer than strictly necessary before
|
||||
* joining.
|
||||
* This is just a hint variable to avoid performing the join excessively early and blocking the main thread.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && (__cplusplus >= 201103L || defined(__STDCXX_VERSION__) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__))
|
||||
__atomic_store_n(&(job->job_completed), true, __ATOMIC_RELAXED);
|
||||
#else
|
||||
job->job_completed = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,6 +166,29 @@ LinkGraphSchedule::~LinkGraphSchedule()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause the game if on the next _date_fract tick, we would do a join with the next
|
||||
* link graph job, but it is still running.
|
||||
* If we previous paused, unpause if the job is now ready to be joined with
|
||||
*/
|
||||
void StateGameLoop_LinkGraphPauseControl()
|
||||
{
|
||||
if (_pause_mode & PM_PAUSED_LINK_GRAPH) {
|
||||
/* We are paused waiting on a job, check the job every tick */
|
||||
if (!LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
|
||||
DoCommandP(0, PM_PAUSED_LINK_GRAPH, 0, CMD_PAUSE);
|
||||
}
|
||||
} else if (_pause_mode == PM_UNPAUSED && _tick_skip_counter == 0 &&
|
||||
_date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 1) {
|
||||
if (_date % _settings_game.linkgraph.recalc_interval == _settings_game.linkgraph.recalc_interval / 2) {
|
||||
/* perform check one _date_fract tick before we would join */
|
||||
if (LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
|
||||
DoCommandP(0, PM_PAUSED_LINK_GRAPH, 1, CMD_PAUSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn or join a link graph job or compress a link graph if any link graph is
|
||||
* due to do so.
|
||||
|
Reference in New Issue
Block a user