summaryrefslogtreecommitdiffstats
path: root/src/dbus/qdbusintegrator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dbus/qdbusintegrator.cpp')
-rw-r--r--src/dbus/qdbusintegrator.cpp133
1 files changed, 109 insertions, 24 deletions
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index ab0aee355d..f27d45b142 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1,40 +1,32 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtDBus module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -42,6 +34,7 @@
#include "qdbusintegrator_p.h"
#include <qcoreapplication.h>
+#include <qelapsedtimer.h>
#include <qdebug.h>
#include <qmetaobject.h>
#include <qobject.h>
@@ -76,15 +69,21 @@ QT_BEGIN_NAMESPACE
static QBasicAtomicInt isDebugging = Q_BASIC_ATOMIC_INITIALIZER(-1);
#define qDBusDebug if (::isDebugging == 0); else qDebug
-Q_GLOBAL_STATIC_WITH_ARGS(const QString, orgFreedesktopDBusString, (QLatin1String(DBUS_SERVICE_DBUS)))
+static inline QString orgFreedesktopDBusString()
+{
+ return QStringLiteral(DBUS_SERVICE_DBUS);
+}
static inline QString dbusServiceString()
-{ return *orgFreedesktopDBusString(); }
+{
+ return orgFreedesktopDBusString();
+}
+
static inline QString dbusInterfaceString()
{
// it's the same string, but just be sure
- Q_ASSERT(*orgFreedesktopDBusString() == QLatin1String(DBUS_INTERFACE_DBUS));
- return *orgFreedesktopDBusString();
+ Q_ASSERT(orgFreedesktopDBusString() == QLatin1String(DBUS_INTERFACE_DBUS));
+ return orgFreedesktopDBusString();
}
static inline QDebug operator<<(QDebug dbg, const QThread *th)
@@ -1927,9 +1926,95 @@ int QDBusConnectionPrivate::send(const QDBusMessage& message)
return serial;
}
+// small helper to note long running blocking dbus calls.
+// these are generally a sign of fragile software (too long a call can either
+// lead to bad user experience, if it's running on the GUI thread for instance)
+// or break completely under load (hitting the call timeout).
+//
+// as a result, this is something we want to watch for.
+class QDBusBlockingCallWatcher
+{
+public:
+ QDBusBlockingCallWatcher(const QDBusMessage &message)
+ : m_message(message), m_maxCallTimeoutMs(0)
+ {
+#if defined(QT_NO_DEBUG)
+ // when in a release build, we default these to off.
+ // this means that we only affect code that explicitly enables the warning.
+ static int mainThreadWarningAmount = -1;
+ static int otherThreadWarningAmount = -1;
+#else
+ static int mainThreadWarningAmount = 200;
+ static int otherThreadWarningAmount = 500;
+#endif
+ static bool initializedAmounts = false;
+ static QBasicMutex initializeMutex;
+ QMutexLocker locker(&initializeMutex);
+
+ if (!initializedAmounts) {
+ int tmp = 0;
+ QByteArray env;
+ bool ok = true;
+
+ env = qgetenv("Q_DBUS_BLOCKING_CALL_MAIN_THREAD_WARNING_MS");
+ if (!env.isEmpty()) {
+ tmp = env.toInt(&ok);
+ if (ok)
+ mainThreadWarningAmount = tmp;
+ else
+ qWarning("QDBusBlockingCallWatcher: Q_DBUS_BLOCKING_CALL_MAIN_THREAD_WARNING_MS must be an integer; value ignored");
+ }
+
+ env = qgetenv("Q_DBUS_BLOCKING_CALL_OTHER_THREAD_WARNING_MS");
+ if (!env.isEmpty()) {
+ tmp = env.toInt(&ok);
+ if (ok)
+ otherThreadWarningAmount = tmp;
+ else
+ qWarning("QDBusBlockingCallWatcher: Q_DBUS_BLOCKING_CALL_OTHER_THREAD_WARNING_MS must be an integer; value ignored");
+ }
+
+ initializedAmounts = true;
+ }
+
+ locker.unlock();
+
+ // if this call is running on the main thread, we have a much lower
+ // tolerance for delay because any long-term delay will wreck user
+ // interactivity.
+ if (qApp && qApp->thread() == QThread::currentThread())
+ m_maxCallTimeoutMs = mainThreadWarningAmount;
+ else
+ m_maxCallTimeoutMs = otherThreadWarningAmount;
+
+ m_callTimer.start();
+ }
+
+ ~QDBusBlockingCallWatcher()
+ {
+ if (m_maxCallTimeoutMs < 0)
+ return; // disabled
+
+ if (m_callTimer.elapsed() >= m_maxCallTimeoutMs) {
+ qWarning("QDBusConnection: warning: blocking call took a long time (%d ms, max for this thread is %d ms) to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"",
+ int(m_callTimer.elapsed()), m_maxCallTimeoutMs,
+ qPrintable(m_message.service()), qPrintable(m_message.path()),
+ qPrintable(m_message.interface()), qPrintable(m_message.member()));
+ }
+ }
+
+private:
+ QDBusMessage m_message;
+ int m_maxCallTimeoutMs;
+ QElapsedTimer m_callTimer;
+};
+
+
QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
int sendMode, int timeout)
{
+ QDBusBlockingCallWatcher watcher(message);
+
checkThread();
if ((sendMode == QDBus::BlockWithGui || sendMode == QDBus::Block)
&& isServiceRegisteredByThread(message.service()))
@@ -2265,7 +2350,7 @@ QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
watchedServices.erase(sit);
disconnectSignal(dbusServiceString(), QString(), dbusInterfaceString(),
QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
- this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+ this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString)));
}
}
}