154cc92f96
- Update to 5.3.1 * Bugfix release, for more details please see: http://blog.qt.digia.com/blog/2014/06/25/qt-5-3-1-released/ - Drop libqt5-fix-the-modal-dialogs-can-go-behind.patch, merged upstream - Added patches from upstream: 0001-Do-not-overwrite-existing-event-mask-of-root-window.patch -- QTBUG-39648 0002-Properly-check-which-OpenGL-features-are-supported.patch -- QTBUG-39730 0003-Fix-data-race-on-QLoggingCategory-when-using-qDebug-.patch -- Fix data race on QLoggingCategory 0004-QDBus-fix-data-race-on-isDebugging-bool.patch -- fix data race on isDebugging bool 0005-Translate-Super-Hyper-keys-to-MetaModifier.patch -- QTBUG-38428 OBS-URL: https://build.opensuse.org/request/show/238711 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/libqt5-qtbase?expand=0&rev=22
237 lines
8.1 KiB
Diff
237 lines
8.1 KiB
Diff
From 884b38157689a893ace0a4c793fab921167abb2c Mon Sep 17 00:00:00 2001
|
|
From: David Faure <david.faure@kdab.com>
|
|
Date: Sun, 8 Jun 2014 21:46:24 +0200
|
|
Subject: [PATCH 1/1] Fix data race on QLoggingCategory when using qDebug from
|
|
multiple threads
|
|
|
|
setEnabled() would race with isEnabled()/isDebugEnabled()/etc.
|
|
|
|
Change-Id: I2004cba81d5417a634b97f5c2f98d3a4ab71770d
|
|
Reviewed-by: David Faure <david.faure@kdab.com>
|
|
---
|
|
src/corelib/arch/qatomic_bootstrap.h | 4 ++-
|
|
src/corelib/io/qloggingcategory.cpp | 36 ++++++++++++++++++--------
|
|
src/corelib/io/qloggingcategory.h | 35 +++++++++++++++++++------
|
|
tests/auto/corelib/io/qdebug/qdebug.pro | 2 +-
|
|
tests/auto/corelib/io/qdebug/tst_qdebug.cpp | 40 +++++++++++++++++++++++++++++
|
|
5 files changed, 97 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/src/corelib/arch/qatomic_bootstrap.h b/src/corelib/arch/qatomic_bootstrap.h
|
|
index 7f17387..0d6843a 100644
|
|
--- a/src/corelib/arch/qatomic_bootstrap.h
|
|
+++ b/src/corelib/arch/qatomic_bootstrap.h
|
|
@@ -67,8 +67,10 @@ template <typename T> struct QAtomicOps: QGenericAtomicOps<QAtomicOps<T> >
|
|
return --_q_value != 0;
|
|
}
|
|
|
|
- static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW
|
|
+ static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW
|
|
{
|
|
+ if (currentValue)
|
|
+ *currentValue = _q_value;
|
|
if (_q_value == expectedValue) {
|
|
_q_value = newValue;
|
|
return true;
|
|
diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp
|
|
index 518052e..45fab11 100644
|
|
--- a/src/corelib/io/qloggingcategory.cpp
|
|
+++ b/src/corelib/io/qloggingcategory.cpp
|
|
@@ -50,6 +50,18 @@ const char qtDefaultCategoryName[] = "default";
|
|
Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory,
|
|
(qtDefaultCategoryName))
|
|
|
|
+#ifndef Q_ATOMIC_INT8_IS_SUPPORTED
|
|
+static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
|
|
+{
|
|
+ const int bit = 1 << shift;
|
|
+
|
|
+ if (enable)
|
|
+ atomic->fetchAndOrRelaxed(bit);
|
|
+ else
|
|
+ atomic->fetchAndAndRelaxed(~bit);
|
|
+}
|
|
+#endif
|
|
+
|
|
/*!
|
|
\class QLoggingCategory
|
|
\inmodule QtCore
|
|
@@ -171,13 +183,11 @@ Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory,
|
|
*/
|
|
QLoggingCategory::QLoggingCategory(const char *category)
|
|
: d(0),
|
|
- name(0),
|
|
- enabledDebug(true),
|
|
- enabledWarning(true),
|
|
- enabledCritical(true)
|
|
+ name(0)
|
|
{
|
|
Q_UNUSED(d);
|
|
Q_UNUSED(placeholder);
|
|
+ enabled.store(0x01010101); // enabledDebug = enabledWarning = enabledCritical = true;
|
|
|
|
const bool isDefaultCategory
|
|
= (category == 0) || (strcmp(category, qtDefaultCategoryName) == 0);
|
|
@@ -249,9 +259,9 @@ QLoggingCategory::~QLoggingCategory()
|
|
bool QLoggingCategory::isEnabled(QtMsgType msgtype) const
|
|
{
|
|
switch (msgtype) {
|
|
- case QtDebugMsg: return enabledDebug;
|
|
- case QtWarningMsg: return enabledWarning;
|
|
- case QtCriticalMsg: return enabledCritical;
|
|
+ case QtDebugMsg: return isDebugEnabled();
|
|
+ case QtWarningMsg: return isWarningEnabled();
|
|
+ case QtCriticalMsg: return isCriticalEnabled();
|
|
case QtFatalMsg: return true;
|
|
}
|
|
return false;
|
|
@@ -270,9 +280,15 @@ bool QLoggingCategory::isEnabled(QtMsgType msgtype) const
|
|
void QLoggingCategory::setEnabled(QtMsgType type, bool enable)
|
|
{
|
|
switch (type) {
|
|
- case QtDebugMsg: enabledDebug = enable; break;
|
|
- case QtWarningMsg: enabledWarning = enable; break;
|
|
- case QtCriticalMsg: enabledCritical = enable; break;
|
|
+#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
|
|
+ case QtDebugMsg: bools.enabledDebug.store(enable); break;
|
|
+ case QtWarningMsg: bools.enabledWarning.store(enable); break;
|
|
+ case QtCriticalMsg: bools.enabledCritical.store(enable); break;
|
|
+#else
|
|
+ case QtDebugMsg: setBoolLane(&enabled, enable, DebugShift); break;
|
|
+ case QtWarningMsg: setBoolLane(&enabled, enable, WarningShift); break;
|
|
+ case QtCriticalMsg: setBoolLane(&enabled, enable, CriticalShift); break;
|
|
+#endif
|
|
case QtFatalMsg: break;
|
|
}
|
|
}
|
|
diff --git a/src/corelib/io/qloggingcategory.h b/src/corelib/io/qloggingcategory.h
|
|
index 4aec8e6..573af21 100644
|
|
--- a/src/corelib/io/qloggingcategory.h
|
|
+++ b/src/corelib/io/qloggingcategory.h
|
|
@@ -57,10 +57,15 @@ public:
|
|
bool isEnabled(QtMsgType type) const;
|
|
void setEnabled(QtMsgType type, bool enable);
|
|
|
|
- bool isDebugEnabled() const { return enabledDebug; }
|
|
- bool isWarningEnabled() const { return enabledWarning; }
|
|
- bool isCriticalEnabled() const { return enabledCritical; }
|
|
-
|
|
+#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
|
|
+ bool isDebugEnabled() const { return bools.enabledDebug.load(); }
|
|
+ bool isWarningEnabled() const { return bools.enabledWarning.load(); }
|
|
+ bool isCriticalEnabled() const { return bools.enabledCritical.load(); }
|
|
+#else
|
|
+ bool isDebugEnabled() const { return enabled.load() >> DebugShift & 1; }
|
|
+ bool isWarningEnabled() const { return enabled.load() >> WarningShift & 1; }
|
|
+ bool isCriticalEnabled() const { return enabled.load() >> CriticalShift & 1; }
|
|
+#endif
|
|
const char *categoryName() const { return name; }
|
|
|
|
// allows usage of both factory method and variable in qCX macros
|
|
@@ -78,10 +83,24 @@ private:
|
|
void *d; // reserved for future use
|
|
const char *name;
|
|
|
|
- bool enabledDebug;
|
|
- bool enabledWarning;
|
|
- bool enabledCritical;
|
|
- bool placeholder[5]; // reserve for future use
|
|
+#ifdef Q_BIG_ENDIAN
|
|
+ enum { DebugShift = 0, WarningShift = 8, CriticalShift = 16 };
|
|
+#else
|
|
+ enum { DebugShift = 24, WarningShift = 16, CriticalShift = 8 };
|
|
+#endif
|
|
+
|
|
+ struct AtomicBools {
|
|
+#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
|
|
+ QBasicAtomicInteger<bool> enabledDebug;
|
|
+ QBasicAtomicInteger<bool> enabledWarning;
|
|
+ QBasicAtomicInteger<bool> enabledCritical;
|
|
+#endif
|
|
+ };
|
|
+ union {
|
|
+ AtomicBools bools;
|
|
+ QBasicAtomicInt enabled;
|
|
+ };
|
|
+ bool placeholder[4]; // reserve for future use
|
|
};
|
|
|
|
#define Q_DECLARE_LOGGING_CATEGORY(name) \
|
|
diff --git a/tests/auto/corelib/io/qdebug/qdebug.pro b/tests/auto/corelib/io/qdebug/qdebug.pro
|
|
index 820c17f..5e902bb 100644
|
|
--- a/tests/auto/corelib/io/qdebug/qdebug.pro
|
|
+++ b/tests/auto/corelib/io/qdebug/qdebug.pro
|
|
@@ -1,5 +1,5 @@
|
|
CONFIG += testcase parallel_test
|
|
TARGET = tst_qdebug
|
|
-QT = core testlib
|
|
+QT = core testlib concurrent
|
|
SOURCES = tst_qdebug.cpp
|
|
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
|
|
diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
|
|
index 80144db..8fd830a 100644
|
|
--- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
|
|
+++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
|
|
@@ -44,6 +44,9 @@
|
|
#include <QtCore/QtDebug>
|
|
#include <QtTest/QtTest>
|
|
|
|
+#include <QtConcurrentRun>
|
|
+#include <QFutureSynchronizer>
|
|
+
|
|
class tst_QDebug: public QObject
|
|
{
|
|
Q_OBJECT
|
|
@@ -59,6 +62,7 @@ private slots:
|
|
void qDebugQLatin1String() const;
|
|
void textStreamModifiers() const;
|
|
void defaultMessagehandler() const;
|
|
+ void threadSafety() const;
|
|
};
|
|
|
|
void tst_QDebug::assignment() const
|
|
@@ -305,5 +309,41 @@ void tst_QDebug::defaultMessagehandler() const
|
|
QVERIFY(same);
|
|
}
|
|
|
|
+QMutex s_mutex;
|
|
+QStringList s_messages;
|
|
+QSemaphore s_sema;
|
|
+
|
|
+static void threadSafeMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
|
+{
|
|
+ QMutexLocker lock(&s_mutex);
|
|
+ s_messages.append(msg);
|
|
+ Q_UNUSED(type);
|
|
+ Q_UNUSED(context);
|
|
+}
|
|
+
|
|
+static void doDebug() // called in each thread
|
|
+{
|
|
+ s_sema.acquire();
|
|
+ qDebug() << "doDebug";
|
|
+}
|
|
+
|
|
+void tst_QDebug::threadSafety() const
|
|
+{
|
|
+ MessageHandlerSetter mhs(threadSafeMessageHandler);
|
|
+ const int numThreads = 10;
|
|
+ QThreadPool::globalInstance()->setMaxThreadCount(numThreads);
|
|
+ QFutureSynchronizer<void> sync;
|
|
+ for (int i = 0; i < numThreads; ++i) {
|
|
+ sync.addFuture(QtConcurrent::run(&doDebug));
|
|
+ }
|
|
+ s_sema.release(numThreads);
|
|
+ sync.waitForFinished();
|
|
+ QMutexLocker lock(&s_mutex);
|
|
+ QCOMPARE(s_messages.count(), numThreads);
|
|
+ for (int i = 0; i < numThreads; ++i) {
|
|
+ QCOMPARE(s_messages.at(i), QStringLiteral("doDebug"));
|
|
+ }
|
|
+}
|
|
+
|
|
QTEST_MAIN(tst_QDebug);
|
|
#include "tst_qdebug.moc"
|
|
--
|
|
1.9.3
|
|
|