1
0
forked from 0ad/0ad

Fixes race condition in EnsureMonotonic on 32-bit builds, which was causing unreliable timer behavior, fixes #1729

This was SVN commit r12927.
This commit is contained in:
historic_bruno 2012-12-03 13:24:12 +00:00
parent ad3fbc543d
commit e91a918164
2 changed files with 10 additions and 26 deletions

View File

@ -34,6 +34,7 @@
#include <cstdarg>
#include "lib/module_init.h"
#include "lib/posix/posix_pthread.h"
#include "lib/posix/posix_time.h"
# include "lib/sysdep/cpu.h"
#if OS_WIN
@ -81,33 +82,16 @@ void timer_LatchStartTime()
#endif
}
static pthread_mutex_t ensure_monotonic_mutex = PTHREAD_MUTEX_INITIALIZER;
// NB: does not guarantee strict monotonicity - callers must avoid
// dividing by the difference of two equal times.
// (this avoids having to update maxRepresentation when
// updating newTime to the (more recent) oldTime)
static void EnsureMonotonic(double& newTime)
{
i64 newRepresentation;
memcpy(&newRepresentation, &newTime, sizeof(newRepresentation));
// representation of the latest time reported by any thread
static volatile i64 maxRepresentation; // initially 0.0
retry:
const i64 oldRepresentation = maxRepresentation; // latch
double oldTime;
memcpy(&oldTime, &oldRepresentation, sizeof(oldTime));
// a previous or concurrent call got a more recent time -
// return that and avoid updating maxRepresentation.
if(newTime < oldTime)
{
newTime = oldTime;
return;
}
if(!cpu_CAS64(&maxRepresentation, oldRepresentation, newRepresentation))
goto retry;
pthread_mutex_lock(&ensure_monotonic_mutex);
static double maxTime;
maxTime = std::max(maxTime, newTime);
newTime = maxTime;
pthread_mutex_unlock(&ensure_monotonic_mutex);
}

View File

@ -142,11 +142,11 @@ static void* RunEngine(void* data)
// Calculate frame length
{
double time = timer_Time();
const double time = timer_Time();
static double last_time = time;
// TODO: why is this sometimes negative, if timer_Time ensures monotonic results?
float realFrameLength = std::max(0.0f, (float)(time-last_time));
const double realFrameLength = time-last_time;
last_time = time;
ENSURE(realFrameLength >= 0.0);
// TODO: filter out big jumps, e.g. when having done a lot of slow
// processing in the last frame
state.realFrameLength = realFrameLength;