Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From 12c7d239d0862dc5787754b1075e719c190dfa7a Mon Sep 17 00:00:00 2001
- From: Thiago Macieira <thiago.macieira@nokia.com>
- Date: Fri, 14 Jan 2011 18:41:11 +0100
- Subject: [PATCH] Replace try/catch blocks in favour of destructors in the event loop.
- This has two direct benefits:
- 1) compiles regardless of -fno-exceptions: no need for #ifndef
- QT_NO_EXCEPTIONS or QT_TRY/QT_CATCH
- 2) no QT_RETHROW either, which means the backtrace of an application
- crashing due to an uncaught exception will include the actual throw
- point.
- Reviewed-by:
- ---
- src/corelib/kernel/qcoreapplication.cpp | 101 +++++++++++++-----------
- src/corelib/kernel/qeventloop.cpp | 60 +++++++-------
- src/corelib/kernel/qobject.cpp | 130 ++++++++++++++++--------------
- 3 files changed, 154 insertions(+), 137 deletions(-)
- diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
- index 381be34..90842f7 100644
- --- a/src/corelib/kernel/qcoreapplication.cpp
- +++ b/src/corelib/kernel/qcoreapplication.cpp
- @@ -772,7 +772,16 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
- // call overhead.
- QObjectPrivate *d = receiver->d_func();
- QThreadData *threadData = d->threadData;
- - ++threadData->loopLevel;
- +
- + // Exception-safety without try/catch
- + struct Incrementer {
- + int &variable;
- + inline Incrementer(int &variable) : variable(variable)
- + { ++variable; }
- + inline ~Incrementer()
- + { --variable; }
- + };
- + Incrementer inc(threadData->loopLevel);
- #ifdef QT_JAMBI_BUILD
- int deleteWatch = 0;
- @@ -783,12 +792,7 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
- #endif
- bool returnValue;
- - QT_TRY {
- - returnValue = notify(receiver, event);
- - } QT_CATCH (...) {
- - --threadData->loopLevel;
- - QT_RETHROW;
- - }
- + returnValue = notify(receiver, event);
- #ifdef QT_JAMBI_BUILD
- // Restore the previous state if the object was not deleted..
- @@ -797,7 +801,6 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
- }
- QObjectPrivate::resetDeleteWatch(d, oldDeleteWatch, deleteWatch);
- #endif
- - --threadData->loopLevel;
- return returnValue;
- }
- @@ -1371,6 +1374,40 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
- int &i = (!event_type && !receiver) ? data->postEventList.startOffset : startOffset;
- data->postEventList.insertionOffset = data->postEventList.size();
- + // Exception-safe cleaning up without the need for a try/catch block
- + struct CleanUp {
- + QObject *receiver;
- + int event_type;
- + QThreadData *data;
- + bool exceptionCaught;
- +
- + inline CleanUp(QObject *receiver, int event_type, QThreadData *data) :
- + receiver(receiver), event_type(event_type), data(data), exceptionCaught(true)
- + {}
- + inline ~CleanUp()
- + {
- + if (exceptionCaught) {
- + // since we were interrupted, we need another pass to make sure we clean everything up
- + data->canWait = false;
- + }
- +
- + --data->postEventList.recursion;
- + if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher)
- + data->eventDispatcher->wakeUp();
- +
- + // clear the global list, i.e. remove everything that was
- + // delivered.
- + if (!event_type && !receiver && data->postEventList.startOffset >= 0) {
- + const QPostEventList::iterator it = data->postEventList.begin();
- + data->postEventList.erase(it, it + data->postEventList.startOffset);
- + data->postEventList.insertionOffset -= data->postEventList.startOffset;
- + Q_ASSERT(data->postEventList.insertionOffset >= 0);
- + data->postEventList.startOffset = 0;
- + }
- + }
- + };
- + CleanUp cleanup(receiver, event_type, data);
- +
- while (i < data->postEventList.size()) {
- // avoid live-lock
- if (i >= data->postEventList.insertionOffset)
- @@ -1409,7 +1446,7 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
- // first, we diddle the event so that we can deliver
- // it, and that no one will try to touch it later.
- pe.event->posted = false;
- - QEvent * e = pe.event;
- + QScopedPointer<QEvent> e(pe.event);
- QObject * r = pe.receiver;
- --r->d_func()->postedEvents;
- @@ -1419,49 +1456,23 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
- // for the next event.
- const_cast<QPostEvent &>(pe).event = 0;
- - locker.unlock();
- - // after all that work, it's time to deliver the event.
- -#ifdef QT_NO_EXCEPTIONS
- - QCoreApplication::sendEvent(r, e);
- -#else
- - try {
- - QCoreApplication::sendEvent(r, e);
- - } catch (...) {
- - delete e;
- - locker.relock();
- -
- - // since we were interrupted, we need another pass to make sure we clean everything up
- - data->canWait = false;
- -
- - // uglehack: copied from below
- - --data->postEventList.recursion;
- - if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher)
- - data->eventDispatcher->wakeUp();
- - throw; // rethrow
- - }
- -#endif
- + struct MutexUnlocker
- + {
- + QMutexLocker &m;
- + MutexUnlocker(QMutexLocker &m) : m(m) { m.unlock(); }
- + ~MutexUnlocker() { m.relock(); }
- + };
- + MutexUnlocker unlocker(locker);
- - delete e;
- - locker.relock();
- + // after all that work, it's time to deliver the event.
- + QCoreApplication::sendEvent(r, e.data());
- // careful when adding anything below this point - the
- // sendEvent() call might invalidate any invariants this
- // function depends on.
- }
- - --data->postEventList.recursion;
- - if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher)
- - data->eventDispatcher->wakeUp();
- -
- - // clear the global list, i.e. remove everything that was
- - // delivered.
- - if (!event_type && !receiver && data->postEventList.startOffset >= 0) {
- - const QPostEventList::iterator it = data->postEventList.begin();
- - data->postEventList.erase(it, it + data->postEventList.startOffset);
- - data->postEventList.insertionOffset -= data->postEventList.startOffset;
- - Q_ASSERT(data->postEventList.insertionOffset >= 0);
- - data->postEventList.startOffset = 0;
- - }
- + cleanup.exceptionCaught = false;
- }
- /*!
- diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp
- index e78f86a..e1a76d5 100644
- --- a/src/corelib/kernel/qeventloop.cpp
- +++ b/src/corelib/kernel/qeventloop.cpp
- @@ -182,46 +182,44 @@ int QEventLoop::exec(ProcessEventsFlags flags)
- qWarning("QEventLoop::exec: instance %p has already called exec()", this);
- return -1;
- }
- - d->inExec = true;
- - d->exit = false;
- - ++d->threadData->loopLevel;
- - d->threadData->eventLoops.push(this);
- +
- + struct LoopReference {
- + QEventLoopPrivate *d;
- +
- + bool exceptionCaught;
- + LoopReference(QEventLoopPrivate *d) : d(d), exceptionCaught(true)
- + {
- + d->inExec = true;
- + d->exit = false;
- + ++d->threadData->loopLevel;
- + d->threadData->eventLoops.push(d->q_func());
- + }
- +
- + ~LoopReference()
- + {
- + if (exceptionCaught) {
- + qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
- + "exceptions from an event handler is not supported in Qt. You must\n"
- + "reimplement QApplication::notify() and catch all exceptions there.\n");
- + }
- + QEventLoop *eventLoop = d->threadData->eventLoops.pop();
- + Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
- + Q_UNUSED(eventLoop); // --release warning
- + d->inExec = false;
- + --d->threadData->loopLevel;
- + }
- + };
- + LoopReference ref(d);
- // remove posted quit events when entering a new event loop
- QCoreApplication *app = QCoreApplication::instance();
- if (app && app->thread() == thread())
- QCoreApplication::removePostedEvents(app, QEvent::Quit);
- -#if defined(QT_NO_EXCEPTIONS)
- while (!d->exit)
- processEvents(flags | WaitForMoreEvents | EventLoopExec);
- -#else
- - try {
- - while (!d->exit)
- - processEvents(flags | WaitForMoreEvents | EventLoopExec);
- - } catch (...) {
- - qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
- - "exceptions from an event handler is not supported in Qt. You must\n"
- - "reimplement QApplication::notify() and catch all exceptions there.\n");
- -
- - // copied from below
- - QEventLoop *eventLoop = d->threadData->eventLoops.pop();
- - Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
- - Q_UNUSED(eventLoop); // --release warning
- - d->inExec = false;
- - --d->threadData->loopLevel;
- -
- - throw;
- - }
- -#endif
- -
- - // copied above
- - QEventLoop *eventLoop = d->threadData->eventLoops.pop();
- - Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
- - Q_UNUSED(eventLoop); // --release warning
- - d->inExec = false;
- - --d->threadData->loopLevel;
- + ref.exceptionCaught = false;
- return d->returnCode;
- }
- diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
- index 644c83f..178df9c 100644
- --- a/src/corelib/kernel/qobject.cpp
- +++ b/src/corelib/kernel/qobject.cpp
- @@ -125,6 +125,39 @@ extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *)
- }
- }
- +struct QConnectionSenderSwitcher {
- + QObject *receiver;
- + QObjectPrivate::Sender *previousSender;
- + QObjectPrivate::Sender currentSender;
- + bool switched;
- +
- + inline QConnectionSenderSwitcher() : switched(false) {}
- +
- + inline QConnectionSenderSwitcher(QObject *receiver, QObject *sender, int signal_absolute_id)
- + {
- + switchSender(receiver, sender, signal_absolute_id);
- + }
- +
- + inline void switchSender(QObject *receiver, QObject *sender, int signal_absolute_id)
- + {
- + this->receiver = receiver;
- + currentSender.sender = sender;
- + currentSender.signal = signal_absolute_id;
- + currentSender.ref = 1;
- + previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender);
- + switched = true;
- + }
- +
- + inline ~QConnectionSenderSwitcher()
- + {
- + if (switched)
- + QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender);
- + }
- +private:
- + Q_DISABLE_COPY(QConnectionSenderSwitcher)
- +};
- +
- +
- void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0;
- void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0;
- void (*QAbstractDeclarativeData::objectNameChanged)(QAbstractDeclarativeData *, QObject *) = 0;
- @@ -1204,23 +1237,10 @@ bool QObject::event(QEvent *e)
- {
- d_func()->inEventHandler = false;
- QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e);
- - QObjectPrivate::Sender currentSender;
- - currentSender.sender = const_cast<QObject*>(mce->sender());
- - currentSender.signal = mce->signalId();
- - currentSender.ref = 1;
- - QObjectPrivate::Sender * const previousSender =
- - QObjectPrivate::setCurrentSender(this, ¤tSender);
- -#if defined(QT_NO_EXCEPTIONS)
- +
- + QConnectionSenderSwitcher sw(this, const_cast<QObject*>(mce->sender()), mce->signalId());
- +
- mce->placeMetaCall(this);
- -#else
- - QT_TRY {
- - mce->placeMetaCall(this);
- - } QT_CATCH(...) {
- - QObjectPrivate::resetCurrentSender(this, ¤tSender, previousSender);
- - QT_RETHROW;
- - }
- -#endif
- - QObjectPrivate::resetCurrentSender(this, ¤tSender, previousSender);
- break;
- }
- @@ -2910,7 +2930,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
- type &= Qt::UniqueConnection - 1;
- }
- - QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
- + QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
- c->sender = s;
- c->receiver = r;
- c->method = method_index;
- @@ -2918,16 +2938,11 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
- c->argumentTypes = types;
- c->nextConnectionList = 0;
- - QT_TRY {
- - QObjectPrivate::get(s)->addConnection(signal_index, c);
- - } QT_CATCH(...) {
- - delete c;
- - QT_RETHROW;
- - }
- + QObjectPrivate::get(s)->addConnection(signal_index, c.data());
- c->prev = &(QObjectPrivate::get(r)->senders);
- c->next = *c->prev;
- - *c->prev = c;
- + *c->prev = c.data();
- if (c->next)
- c->next->prev = &c->next;
- @@ -2938,6 +2953,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
- sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
- }
- + c.take(); // stop tracking
- return true;
- }
- @@ -3219,19 +3235,42 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
- QThreadData *currentThreadData = QThreadData::current();
- + {
- QMutexLocker locker(signalSlotLock(sender));
- - QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists;
- - if (!connectionLists) {
- + struct ConnectionListsRef {
- + QObjectConnectionListVector *connectionLists;
- + ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists)
- + {
- + if (connectionLists)
- + ++connectionLists->inUse;
- + }
- + ~ConnectionListsRef()
- + {
- + if (!connectionLists)
- + return;
- +
- + --connectionLists->inUse;
- + Q_ASSERT(connectionLists->inUse >= 0);
- + if (connectionLists->orphaned) {
- + if (!connectionLists->inUse)
- + delete connectionLists;
- + }
- + }
- +
- + QObjectConnectionListVector *operator->() const { return connectionLists; }
- + };
- + ConnectionListsRef connectionLists = sender->d_func()->connectionLists;
- + if (!connectionLists.connectionLists) {
- locker.unlock();
- if (qt_signal_spy_callback_set.signal_end_callback != 0)
- qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index);
- return;
- }
- - ++connectionLists->inUse;
- if (signal_index >= connectionLists->count()) {
- signal_index = -2; //for "all signals";
- }
- +
- do {
- QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;
- if (!c) continue;
- @@ -3259,14 +3298,11 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
- }
- const int method = c->method;
- - QObjectPrivate::Sender currentSender;
- const bool receiverInSameThread = currentThreadData == receiver->d_func()->threadData;
- - QObjectPrivate::Sender *previousSender = 0;
- + QConnectionSenderSwitcher sw;
- +
- if (receiverInSameThread) {
- - currentSender.sender = sender;
- - currentSender.signal = signal_absolute_index;
- - currentSender.ref = 1;
- - previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender);
- + sw.switchSender(receiver, sender, signal_absolute_index);
- }
- locker.unlock();
- @@ -3276,32 +3312,13 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
- argv ? argv : empty_argv);
- }
- -#if defined(QT_NO_EXCEPTIONS)
- metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
- -#else
- - QT_TRY {
- - metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
- - } QT_CATCH(...) {
- - locker.relock();
- - if (receiverInSameThread)
- - QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender);
- -
- - --connectionLists->inUse;
- - Q_ASSERT(connectionLists->inUse >= 0);
- - if (connectionLists->orphaned && !connectionLists->inUse)
- - delete connectionLists;
- - QT_RETHROW;
- - }
- -#endif
- if (qt_signal_spy_callback_set.slot_end_callback != 0)
- qt_signal_spy_callback_set.slot_end_callback(receiver, method);
- locker.relock();
- - if (receiverInSameThread)
- - QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender);
- -
- if (connectionLists->orphaned)
- break;
- } while (c != last && (c = c->nextConnectionList) != 0);
- @@ -3310,17 +3327,8 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
- break;
- } while (signal_index >= 0 && (signal_index = -1)); //start over for -1 (all signal)
- - --connectionLists->inUse;
- - Q_ASSERT(connectionLists->inUse >= 0);
- - if (connectionLists->orphaned) {
- - if (!connectionLists->inUse)
- - delete connectionLists;
- - } else if (connectionLists->dirty) {
- - sender->d_func()->cleanConnectionLists();
- }
- - locker.unlock();
- -
- if (qt_signal_spy_callback_set.signal_end_callback != 0)
- qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index);
- --
- 1.7.3.2.431.ge2f5c
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement