diff options
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 115 |
1 files changed, 78 insertions, 37 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 9ab952362c..e3e0f570e7 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1,41 +1,33 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore 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$ ** ****************************************************************************/ @@ -63,6 +55,7 @@ #include <qsharedpointer.h> #include <private/qorderedmutexlocker_p.h> +#include <private/qhooks_p.h> #include <new> @@ -138,6 +131,7 @@ static inline QMutex *signalSlotLock(const QObject *o) uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]); } +// ### Qt >= 5.6, remove qt_add/removeObject extern "C" Q_CORE_EXPORT void qt_addObject(QObject *) {} @@ -223,13 +217,17 @@ QObjectPrivate::QObjectPrivate(int version) QObjectPrivate::~QObjectPrivate() { if (extraData && !extraData->runningTimers.isEmpty()) { - // unregister pending timers - if (threadData->eventDispatcher.load()) - threadData->eventDispatcher.load()->unregisterTimers(q_ptr); - - // release the timer ids back to the pool - for (int i = 0; i < extraData->runningTimers.size(); ++i) - QAbstractEventDispatcherPrivate::releaseTimerId(extraData->runningTimers.at(i)); + if (Q_LIKELY(threadData->thread == QThread::currentThread())) { + // unregister pending timers + if (threadData->eventDispatcher.load()) + threadData->eventDispatcher.load()->unregisterTimers(q_ptr); + + // release the timer ids back to the pool + for (int i = 0; i < extraData->runningTimers.size(); ++i) + QAbstractEventDispatcherPrivate::releaseTimerId(extraData->runningTimers.at(i)); + } else { + qWarning("QObject::~QObject: Timers cannot be stopped from another thread"); + } } if (postedEvents) @@ -820,6 +818,8 @@ QObject::QObject(QObject *parent) } } qt_addObject(this); + if (Q_UNLIKELY(qtHookData[QHooks::AddQObject])) + reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this); } /*! @@ -851,6 +851,8 @@ QObject::QObject(QObjectPrivate &dd, QObject *parent) } } qt_addObject(this); + if (Q_UNLIKELY(qtHookData[QHooks::AddQObject])) + reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this); } /*! @@ -1028,6 +1030,8 @@ QObject::~QObject() d->deleteChildren(); qt_removeObject(this); + if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject])) + reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(this); if (d->parent) // remove it from parent object d->setParent_helper(0); @@ -1607,15 +1611,18 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) { Q_D(QObject); - if (interval < 0) { + if (Q_UNLIKELY(interval < 0)) { qWarning("QObject::startTimer: Timers cannot have negative intervals"); return 0; } - - if (!d->threadData->eventDispatcher.load()) { + if (Q_UNLIKELY(!d->threadData->eventDispatcher.load())) { qWarning("QObject::startTimer: Timers can only be used with threads started with QThread"); return 0; } + if (Q_UNLIKELY(thread() != QThread::currentThread())) { + qWarning("QObject::startTimer: Timers cannot be started from another thread"); + return 0; + } int timerId = d->threadData->eventDispatcher.load()->registerTimer(interval, timerType, this); if (!d->extraData) d->extraData = new QObjectPrivate::ExtraData; @@ -1635,6 +1642,10 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) void QObject::killTimer(int id) { Q_D(QObject); + if (Q_UNLIKELY(thread() != QThread::currentThread())) { + qWarning("QObject::killTimer: Timers cannot be stopped from another thread"); + return; + } if (id) { int at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1; if (at == -1) { @@ -3305,7 +3316,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, while (c) { if (c->receiver && (receiver == 0 || (c->receiver == receiver - && (method_index < 0 || c->method() == method_index) + && (method_index < 0 || (!c->isSlotObject && c->method() == method_index)) && (slot == 0 || (c->isSlotObject && c->slotObj->compare(slot)))))) { bool needToUnlock = false; QMutex *receiverMutex = 0; @@ -3508,7 +3519,8 @@ void QMetaObject::connectSlotsByName(QObject *o) \a signal must be in the signal index range (see QObjectPrivate::signalIndex()). */ -static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv) +static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv, + QMutexLocker &locker) { const int *argumentTypes = c->argumentTypes.load(); if (!argumentTypes && argumentTypes != &DIRECT_CONNECTION_ONLY) { @@ -3533,8 +3545,28 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect Q_CHECK_PTR(args); types[0] = 0; // return type args[0] = 0; // return value - for (int n = 1; n < nargs; ++n) - args[n] = QMetaType::create((types[n] = argumentTypes[n-1]), argv[n]); + + if (nargs > 1) { + for (int n = 1; n < nargs; ++n) + types[n] = argumentTypes[n-1]; + + locker.unlock(); + for (int n = 1; n < nargs; ++n) + args[n] = QMetaType::create(types[n], argv[n]); + locker.relock(); + + if (!c->receiver) { + locker.unlock(); + // we have been disconnected while the mutex was unlocked + for (int n = 1; n < nargs; ++n) + QMetaType::destroy(types[n], args[n]); + free(types); + free(args); + locker.relock(); + return; + } + } + QMetaCallEvent *ev = c->isSlotObject ? new QMetaCallEvent(c->slotObj, sender, signal, nargs, types, args) : new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs, types, args); @@ -3634,7 +3666,7 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i // put into the event queue if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread) || (c->connectionType == Qt::QueuedConnection)) { - queued_activate(sender, signal_index, c, argv ? argv : empty_argv); + queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker); continue; #ifndef QT_NO_THREAD } else if (c->connectionType == Qt::BlockingQueuedConnection) { @@ -3974,6 +4006,11 @@ void QObject::dumpObjectInfo() c = c->nextConnectionList; continue; } + if (c->isSlotObject) { + qDebug(" <functor or function pointer>"); + c = c->nextConnectionList; + continue; + } const QMetaObject *receiverMetaObject = c->receiver->metaObject(); const QMetaMethod method = receiverMetaObject->method(c->method()); qDebug(" --> %s::%s %s", @@ -3992,11 +4029,15 @@ void QObject::dumpObjectInfo() if (d->senders) { for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) { - const QMetaMethod slot = metaObject()->method(s->method()); - qDebug(" <-- %s::%s %s", + QByteArray slotName = QByteArrayLiteral("<unknown>"); + if (!s->isSlotObject) { + const QMetaMethod slot = metaObject()->method(s->method()); + slotName = slot.methodSignature(); + } + qDebug(" <-- %s::%s %s", s->sender->metaObject()->className(), s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()), - slot.methodSignature().constData()); + slotName.constData()); } } else { qDebug(" <None>"); |