summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qglobalstatic.cpp8
-rw-r--r--src/corelib/global/qglobalstatic.h3
-rw-r--r--tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp24
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");