Fix static initialization order problem in wxStopWatch under MSW.

Don't rely on the static global gs_perfCounter being already initialized when
wxStopWatch::DoStart() is called, this may not be the case if wxStopWatch
variable is global.

Work around this by wrapping the variable inside a function to ensure that it
is initialized before being used.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76986 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2014-08-03 12:47:30 +00:00
parent f88585b4ab
commit e393f96dcc

View File

@ -67,7 +67,19 @@ struct PerfCounter
wxCRIT_SECT_DECLARE_MEMBER(cs);
LARGE_INTEGER freq;
bool init;
} gs_perfCounter;
};
// Return the global perf counter state.
//
// This is wrapped in a function to avoid initialization order problems,
// otherwise simply creating a global wxStopWatch variable could crash because
// it would be using a (possibly) still uninitialized critical section.
PerfCounter& GetPerfCounterState()
{
static PerfCounter s_perfCounter;
return s_perfCounter;
}
#endif // __WINDOWS__
@ -79,10 +91,11 @@ const int MICROSECONDS_PER_SECOND = 1000*1000;
void wxStopWatch::DoStart()
{
#ifdef __WINDOWS__
if ( !gs_perfCounter.init )
PerfCounter& perfCounter = GetPerfCounterState();
if ( !perfCounter.init )
{
wxCRIT_SECT_LOCKER(lock, gs_perfCounter.cs);
::QueryPerformanceFrequency(&gs_perfCounter.freq);
wxCRIT_SECT_LOCKER(lock, perfCounter.cs);
::QueryPerformanceFrequency(&perfCounter.freq);
// Just a sanity check: it's not supposed to happen but verify that
// ::QueryPerformanceCounter() succeeds so that we can really use it.
@ -92,10 +105,10 @@ void wxStopWatch::DoStart()
wxLogDebug("QueryPerformanceCounter() unexpected failed (%s), "
"will not use it.", wxSysErrorMsg());
gs_perfCounter.freq.QuadPart = 0;
perfCounter.freq.QuadPart = 0;
}
gs_perfCounter.init = true;
perfCounter.init = true;
}
#endif // __WINDOWS__
@ -107,8 +120,8 @@ wxLongLong wxStopWatch::GetClockFreq() const
#ifdef __WINDOWS__
// Under MSW we use the high resolution performance counter timer which has
// its own frequency (usually related to the CPU clock speed).
if ( gs_perfCounter.CanBeUsed() )
return gs_perfCounter.freq.QuadPart;
if ( GetPerfCounterState().CanBeUsed() )
return GetPerfCounterState().freq.QuadPart;
#endif // __WINDOWS__
#ifdef HAVE_GETTIMEOFDAY
@ -136,7 +149,7 @@ void wxStopWatch::Start(long t0)
wxLongLong wxStopWatch::GetCurrentClockValue() const
{
#ifdef __WINDOWS__
if ( gs_perfCounter.CanBeUsed() )
if ( GetPerfCounterState().CanBeUsed() )
{
LARGE_INTEGER counter;
::QueryPerformanceCounter(&counter);