diff options
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/animation/qabstractanimation.cpp | 77 | ||||
-rw-r--r-- | src/corelib/animation/qabstractanimation_p.h | 11 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemwatcher.cpp | 5 | ||||
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 53 | ||||
-rw-r--r-- | src/corelib/kernel/qobject_p.h | 28 | ||||
-rw-r--r-- | src/corelib/thread/qmutex.h | 18 |
6 files changed, 109 insertions, 83 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 82b3003..01570ad 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -173,11 +173,12 @@ QUnifiedTimer::QUnifiedTimer() : time.invalidate(); } -QUnifiedTimer *QUnifiedTimer::instance() + +QUnifiedTimer *QUnifiedTimer::instance(bool create) { QUnifiedTimer *inst; #ifndef QT_NO_THREAD - if (!unifiedTimer()->hasLocalData()) { + if (create && !unifiedTimer()->hasLocalData()) { inst = new QUnifiedTimer; unifiedTimer()->setLocalData(inst); } else { @@ -190,10 +191,16 @@ QUnifiedTimer *QUnifiedTimer::instance() return inst; } +QUnifiedTimer *QUnifiedTimer::instance() +{ + return instance(true); +} + void QUnifiedTimer::ensureTimerUpdate() { - if (isPauseTimerActive) - updateAnimationsTime(); + QUnifiedTimer *inst = QUnifiedTimer::instance(false); + if (inst && inst->isPauseTimerActive) + inst->updateAnimationsTime(); } void QUnifiedTimer::updateAnimationsTime() @@ -219,6 +226,13 @@ void QUnifiedTimer::updateAnimationsTime() } } +void QUnifiedTimer::updateAnimationTimer() +{ + QUnifiedTimer *inst = QUnifiedTimer::instance(false); + if (inst) + inst->restartAnimationTimer(); +} + void QUnifiedTimer::restartAnimationTimer() { if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) { @@ -269,34 +283,41 @@ void QUnifiedTimer::timerEvent(QTimerEvent *event) void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel) { - registerRunningAnimation(animation); + QUnifiedTimer *inst = instance(true); //we create the instance if needed + inst->registerRunningAnimation(animation); if (isTopLevel) { Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer); QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true; - animationsToStart << animation; - if (!startStopAnimationTimer.isActive()) - startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); + inst->animationsToStart << animation; + if (!inst->startStopAnimationTimer.isActive()) + inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst); } } void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) { - unregisterRunningAnimation(animation); + QUnifiedTimer *inst = QUnifiedTimer::instance(false); + if (inst) { + //at this point the unified timer should have been created + //but it might also have been already destroyed in case the application is shutting down - if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer) - return; + inst->unregisterRunningAnimation(animation); - int idx = animations.indexOf(animation); - if (idx != -1) { - animations.removeAt(idx); - // this is needed if we unregister an animation while its running - if (idx <= currentAnimationIdx) - --currentAnimationIdx; + if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer) + return; - if (animations.isEmpty() && !startStopAnimationTimer.isActive()) - startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); - } else { - animationsToStart.removeOne(animation); + int idx = inst->animations.indexOf(animation); + if (idx != -1) { + inst->animations.removeAt(idx); + // this is needed if we unregister an animation while its running + if (idx <= inst->currentAnimationIdx) + --inst->currentAnimationIdx; + + if (inst->animations.isEmpty() && !inst->startStopAnimationTimer.isActive()) + inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst); + } else { + inst->animationsToStart.removeOne(animation); + } } QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false; } @@ -371,11 +392,11 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped; if (oldState == QAbstractAnimation::Running) { if (newState == QAbstractAnimation::Paused && hasRegisteredTimer) - QUnifiedTimer::instance()->ensureTimerUpdate(); + QUnifiedTimer::ensureTimerUpdate(); //the animation, is not running any more - QUnifiedTimer::instance()->unregisterAnimation(q); + QUnifiedTimer::unregisterAnimation(q); } else if (newState == QAbstractAnimation::Running) { - QUnifiedTimer::instance()->registerAnimation(q, isTopLevel); + QUnifiedTimer::registerAnimation(q, isTopLevel); } q->updateState(newState, oldState); @@ -397,7 +418,7 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) if (oldState == QAbstractAnimation::Stopped) { if (isTopLevel) { // currentTime needs to be updated if pauseTimer is active - QUnifiedTimer::instance()->ensureTimerUpdate(); + QUnifiedTimer::ensureTimerUpdate(); q->setCurrentTime(totalCurrentTime); } } @@ -456,7 +477,7 @@ QAbstractAnimation::~QAbstractAnimation() d->state = Stopped; emit stateChanged(oldState, d->state); if (oldState == QAbstractAnimation::Running) - QUnifiedTimer::instance()->unregisterAnimation(this); + QUnifiedTimer::unregisterAnimation(this); } } @@ -555,14 +576,14 @@ void QAbstractAnimation::setDirection(Direction direction) // the commands order below is important: first we need to setCurrentTime with the old direction, // then update the direction on this and all children and finally restart the pauseTimer if needed if (d->hasRegisteredTimer) - QUnifiedTimer::instance()->ensureTimerUpdate(); + QUnifiedTimer::ensureTimerUpdate(); d->direction = direction; updateDirection(direction); if (d->hasRegisteredTimer) // needed to update the timer interval in case of a pause animation - QUnifiedTimer::instance()->restartAnimationTimer(); + QUnifiedTimer::updateAnimationTimer(); emit directionChanged(direction); } diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index 2282cdb..fcfe824 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -124,9 +124,10 @@ private: public: //XXX this is needed by dui static Q_CORE_EXPORT QUnifiedTimer *instance(); + static QUnifiedTimer *instance(bool create); - void registerAnimation(QAbstractAnimation *animation, bool isTopLevel); - void unregisterAnimation(QAbstractAnimation *animation); + static void registerAnimation(QAbstractAnimation *animation, bool isTopLevel); + static void unregisterAnimation(QAbstractAnimation *animation); //defines the timing interval. Default is DEFAULT_TIMER_INTERVAL void setTimingInterval(int interval) @@ -151,13 +152,13 @@ public: this is used for updating the currentTime of all animations in case the pause timer is active or, otherwise, only of the animation passed as parameter. */ - void ensureTimerUpdate(); + static void ensureTimerUpdate(); /* this will evaluate the need of restarting the pause timer in case there is still some pause animations running. */ - void restartAnimationTimer(); + static void updateAnimationTimer(); protected: void timerEvent(QTimerEvent *); @@ -187,6 +188,8 @@ private: void registerRunningAnimation(QAbstractAnimation *animation); void unregisterRunningAnimation(QAbstractAnimation *animation); + void restartAnimationTimer(); + void updateAnimationsTime(); int closestPauseAnimationTimeToFinish(); }; diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index 00af3fd..18c3c9f 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -426,6 +426,11 @@ QFileSystemWatcher::QFileSystemWatcher(const QStringList &paths, QObject *parent /*! Destroys the file system watcher. + + \note To avoid deadlocks on shutdown, all instances of QFileSystemWatcher + need to be destroyed before QCoreApplication. Note that passing + QCoreApplication::instance() as the parent object when creating + QFileSystemWatcher is not sufficient. */ QFileSystemWatcher::~QFileSystemWatcher() { diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index c13d829..6a6db51 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -101,7 +101,7 @@ static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0); /** \internal * mutex to be locked when accessing the connectionlists or the senders list */ -static QMutex *signalSlotLock(const QObject *o) +static inline QMutex *signalSlotLock(const QObject *o) { if (!signalSlotMutexes) { QMutexPool *mp = new QMutexPool; @@ -393,27 +393,6 @@ void QObjectPrivate::cleanConnectionLists() } } -QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, - Sender *sender) -{ - Sender *previousSender = receiver->d_func()->currentSender; - receiver->d_func()->currentSender = sender; - return previousSender; -} - -void QObjectPrivate::resetCurrentSender(QObject *receiver, - Sender *currentSender, - Sender *previousSender) -{ - // ref is set to zero when this object is deleted during the metacall - if (currentSender->ref == 1) - receiver->d_func()->currentSender = previousSender; - // if we've recursed, we need to tell the caller about the objects deletion - if (previousSender) - previousSender->ref = currentSender->ref; -} - - typedef QMultiHash<QObject *, QObject **> GuardHash; Q_GLOBAL_STATIC(GuardHash, guardHash) Q_GLOBAL_STATIC(QMutex, guardHashLock) @@ -880,19 +859,14 @@ QObject::~QObject() if (d->declarativeData) QAbstractDeclarativeData::destroyed(d->declarativeData, this); - { - QMutex *signalSlotMutex = 0; - QT_TRY { - signalSlotMutex = signalSlotLock(this); - } QT_CATCH(const std::bad_alloc &) { - // out of memory - swallow to prevent a crash - } - QMutexLocker locker(signalSlotMutex); + // set ref to zero to indicate that this object has been deleted + if (d->currentSender != 0) + d->currentSender->ref = 0; + d->currentSender = 0; - // set ref to zero to indicate that this object has been deleted - if (d->currentSender != 0) - d->currentSender->ref = 0; - d->currentSender = 0; + if (d->connectionLists || d->senders) { + QMutex *signalSlotMutex = signalSlotLock(this); + QMutexLocker locker(signalSlotMutex); // disconnect all receivers if (d->connectionLists) { @@ -910,7 +884,7 @@ QObject::~QObject() } QMutex *m = signalSlotLock(c->receiver); - bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); + bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); if (c->receiver) { *c->prev = c->next; @@ -938,7 +912,7 @@ QObject::~QObject() QObject *sender = node->sender; QMutex *m = signalSlotLock(sender); node->prev = &node; - bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); + bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); //the node has maybe been removed while the mutex was unlocked in relock? if (!node || node->sender != sender) { m->unlock(); @@ -972,7 +946,8 @@ QObject::~QObject() qt_removeObject(this); - QCoreApplication::removePostedEvents(this); + if (d->postedEvents) + QCoreApplication::removePostedEvents(this, 0); if (d->parent) // remove it from parent object d->setParent_helper(0); @@ -3231,9 +3206,9 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign argv ? argv : empty_argv); } - QMutexLocker locker(signalSlotLock(sender)); QThreadData *currentThreadData = QThreadData::current(); + QMutexLocker locker(signalSlotLock(sender)); QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; if (!connectionLists) { locker.unlock(); @@ -3329,7 +3304,7 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign if (connectionLists->orphaned) { if (!connectionLists->inUse) delete connectionLists; - } else { + } else if (connectionLists->dirty) { sender->d_func()->cleanConnectionLists(); } diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 341b3e9..4800e6a 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -156,9 +156,9 @@ public: void removePendingChildInsertedEvents(QObject *child); #endif - static Sender *setCurrentSender(QObject *receiver, + static inline Sender *setCurrentSender(QObject *receiver, Sender *sender); - static void resetCurrentSender(QObject *receiver, + static inline void resetCurrentSender(QObject *receiver, Sender *currentSender, Sender *previousSender); static int *setDeleteWatch(QObjectPrivate *d, int *newWatch); @@ -215,9 +215,29 @@ public: inline bool QObjectPrivate::isSignalConnected(uint signal_index) const { return signal_index >= sizeof(connectedSignals) * 8 + || (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f)) || qt_signal_spy_callback_set.signal_begin_callback - || qt_signal_spy_callback_set.signal_end_callback - || (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f))); + || qt_signal_spy_callback_set.signal_end_callback); +} + +inline QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, + Sender *sender) +{ + Sender *previousSender = receiver->d_func()->currentSender; + receiver->d_func()->currentSender = sender; + return previousSender; +} + +inline void QObjectPrivate::resetCurrentSender(QObject *receiver, + Sender *currentSender, + Sender *previousSender) +{ + // ref is set to zero when this object is deleted during the metacall + if (currentSender->ref == 1) + receiver->d_func()->currentSender = previousSender; + // if we've recursed, we need to tell the caller about the objects deletion + if (previousSender) + previousSender->ref = currentSender->ref; } diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 677412e..509f300 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -95,21 +95,23 @@ class Q_CORE_EXPORT QMutexLocker { public: inline explicit QMutexLocker(QMutex *m) - : val(reinterpret_cast<quintptr>(m)) { - Q_ASSERT_X((val & quintptr(1u)) == quintptr(0), + Q_ASSERT_X((reinterpret_cast<quintptr>(m) & quintptr(1u)) == quintptr(0), "QMutexLocker", "QMutex pointer is misaligned"); - relock(); + if (m) { + m->lock(); + val = reinterpret_cast<quintptr>(m) | quintptr(1u); + } else { + val = 0; + } } inline ~QMutexLocker() { unlock(); } inline void unlock() { - if (val) { - if ((val & quintptr(1u)) == quintptr(1u)) { - val &= ~quintptr(1u); - mutex()->unlock(); - } + if ((val & quintptr(1u)) == quintptr(1u)) { + val &= ~quintptr(1u); + mutex()->unlock(); } } |