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 <cstdarg>
#include "lib/module_init.h" #include "lib/module_init.h"
#include "lib/posix/posix_pthread.h"
#include "lib/posix/posix_time.h" #include "lib/posix/posix_time.h"
# include "lib/sysdep/cpu.h" # include "lib/sysdep/cpu.h"
#if OS_WIN #if OS_WIN
@ -81,33 +82,16 @@ void timer_LatchStartTime()
#endif #endif
} }
static pthread_mutex_t ensure_monotonic_mutex = PTHREAD_MUTEX_INITIALIZER;
// NB: does not guarantee strict monotonicity - callers must avoid // NB: does not guarantee strict monotonicity - callers must avoid
// dividing by the difference of two equal times. // 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) static void EnsureMonotonic(double& newTime)
{ {
i64 newRepresentation; pthread_mutex_lock(&ensure_monotonic_mutex);
memcpy(&newRepresentation, &newTime, sizeof(newRepresentation)); static double maxTime;
maxTime = std::max(maxTime, newTime);
// representation of the latest time reported by any thread newTime = maxTime;
static volatile i64 maxRepresentation; // initially 0.0 pthread_mutex_unlock(&ensure_monotonic_mutex);
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;
} }

View File

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