diff options
-rw-r--r-- | src/corelib/global/qglobalstatic.cpp | 8 | ||||
-rw-r--r-- | src/corelib/global/qglobalstatic.h | 3 | ||||
-rw-r--r-- | tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp | 24 |
3 files changed, 30 insertions, 5 deletions
diff --git a/src/corelib/global/qglobalstatic.cpp b/src/corelib/global/qglobalstatic.cpp index 7caa2e9848..8474d132b4 100644 --- a/src/corelib/global/qglobalstatic.cpp +++ b/src/corelib/global/qglobalstatic.cpp @@ -288,9 +288,11 @@ structure so holder's destructor can set the guard variable to the value -2 (destroyed) when the type has finished destruction. Since we need to set the guard \b after the destruction has finished, this code needs to be in a - base struct's destructor. A holder structure is used to avoid creating two - statics, which the ABI might require duplicating the thread-safe control - structures for. + base struct's destructor. And it only sets to -2 (destroyed) if it finds + the guard at -1 (initialized): this is done to ensure that the guard isn't + set to -2 in the event the type's constructor threw an exception. A holder + structure is used to avoid creating two statics, which the ABI might + require duplicating the thread-safe control structures for. The other implementation is similar to Qt 4's Q_GLOBAL_STATIC, but unlike that one, it uses a \l QBasicMutex to provide locking. It is also more diff --git a/src/corelib/global/qglobalstatic.h b/src/corelib/global/qglobalstatic.h index 336512eac3..a6268e057e 100644 --- a/src/corelib/global/qglobalstatic.h +++ b/src/corelib/global/qglobalstatic.h @@ -68,7 +68,8 @@ enum GuardValues { { \ struct HolderBase { \ ~HolderBase() Q_DECL_NOTHROW \ - { guard.store(QtGlobalStatic::Destroyed); } \ + { if (guard.load() == QtGlobalStatic::Initialized) \ + guard.store(QtGlobalStatic::Destroyed); } \ }; \ static struct Holder : public HolderBase { \ Type value; \ diff --git a/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp b/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp index b9aa70fe80..131b37f821 100644 --- a/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp +++ b/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp @@ -50,6 +50,7 @@ private Q_SLOTS: void api(); void constVolatile(); void exception(); + void threadedException(); void threadStressTest(); void afterDestruction(); }; @@ -107,6 +108,11 @@ struct ThrowingType { static QBasicAtomicInt constructedCount; static QBasicAtomicInt destructedCount; + ThrowingType() + { + throw 0; + } + ThrowingType(QBasicAtomicInt &throwControl) { constructedCount.ref(); @@ -115,12 +121,28 @@ struct ThrowingType } ~ThrowingType() { destructedCount.ref(); } }; + QBasicAtomicInt ThrowingType::constructedCount = Q_BASIC_ATOMIC_INITIALIZER(0); QBasicAtomicInt ThrowingType::destructedCount = Q_BASIC_ATOMIC_INITIALIZER(0); +Q_GLOBAL_STATIC(ThrowingType, throwingGS) +void tst_QGlobalStatic::exception() +{ + bool exceptionCaught = false; + try { + throwingGS(); + } catch (int) { + exceptionCaught = true; + } + QVERIFY(exceptionCaught); + QCOMPARE(Q_QGS_throwingGS::guard.load(), 0); + QVERIFY(!throwingGS.exists()); + QVERIFY(!throwingGS.isDestroyed()); +} + QBasicAtomicInt exceptionControlVar = Q_BASIC_ATOMIC_INITIALIZER(1); Q_GLOBAL_STATIC_WITH_ARGS(ThrowingType, exceptionGS, (exceptionControlVar)) -void tst_QGlobalStatic::exception() +void tst_QGlobalStatic::threadedException() { if (exceptionControlVar.load() != 1) QSKIP("This test cannot be run more than once"); |