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); wxCRIT_SECT_DECLARE_MEMBER(cs);
LARGE_INTEGER freq; LARGE_INTEGER freq;
bool init; 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__ #endif // __WINDOWS__
@@ -79,10 +91,11 @@ const int MICROSECONDS_PER_SECOND = 1000*1000;
void wxStopWatch::DoStart() void wxStopWatch::DoStart()
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
if ( !gs_perfCounter.init ) PerfCounter& perfCounter = GetPerfCounterState();
if ( !perfCounter.init )
{ {
wxCRIT_SECT_LOCKER(lock, gs_perfCounter.cs); wxCRIT_SECT_LOCKER(lock, perfCounter.cs);
::QueryPerformanceFrequency(&gs_perfCounter.freq); ::QueryPerformanceFrequency(&perfCounter.freq);
// Just a sanity check: it's not supposed to happen but verify that // Just a sanity check: it's not supposed to happen but verify that
// ::QueryPerformanceCounter() succeeds so that we can really use it. // ::QueryPerformanceCounter() succeeds so that we can really use it.
@@ -92,10 +105,10 @@ void wxStopWatch::DoStart()
wxLogDebug("QueryPerformanceCounter() unexpected failed (%s), " wxLogDebug("QueryPerformanceCounter() unexpected failed (%s), "
"will not use it.", wxSysErrorMsg()); "will not use it.", wxSysErrorMsg());
gs_perfCounter.freq.QuadPart = 0; perfCounter.freq.QuadPart = 0;
} }
gs_perfCounter.init = true; perfCounter.init = true;
} }
#endif // __WINDOWS__ #endif // __WINDOWS__
@@ -107,8 +120,8 @@ wxLongLong wxStopWatch::GetClockFreq() const
#ifdef __WINDOWS__ #ifdef __WINDOWS__
// Under MSW we use the high resolution performance counter timer which has // Under MSW we use the high resolution performance counter timer which has
// its own frequency (usually related to the CPU clock speed). // its own frequency (usually related to the CPU clock speed).
if ( gs_perfCounter.CanBeUsed() ) if ( GetPerfCounterState().CanBeUsed() )
return gs_perfCounter.freq.QuadPart; return GetPerfCounterState().freq.QuadPart;
#endif // __WINDOWS__ #endif // __WINDOWS__
#ifdef HAVE_GETTIMEOFDAY #ifdef HAVE_GETTIMEOFDAY
@@ -136,7 +149,7 @@ void wxStopWatch::Start(long t0)
wxLongLong wxStopWatch::GetCurrentClockValue() const wxLongLong wxStopWatch::GetCurrentClockValue() const
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
if ( gs_perfCounter.CanBeUsed() ) if ( GetPerfCounterState().CanBeUsed() )
{ {
LARGE_INTEGER counter; LARGE_INTEGER counter;
::QueryPerformanceCounter(&counter); ::QueryPerformanceCounter(&counter);