SHARE
TWEET

Untitled

a guest Jul 17th, 2017 113 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. From 12c7d239d0862dc5787754b1075e719c190dfa7a Mon Sep 17 00:00:00 2001
  2. From: Thiago Macieira <thiago.macieira@nokia.com>
  3. Date: Fri, 14 Jan 2011 18:41:11 +0100
  4. Subject: [PATCH] Replace try/catch blocks in favour of destructors in the event loop.
  5.  
  6. This has two direct benefits:
  7. 1) compiles regardless of -fno-exceptions: no need for #ifndef
  8. QT_NO_EXCEPTIONS or QT_TRY/QT_CATCH
  9.  
  10. 2) no QT_RETHROW either, which means the backtrace of an application
  11. crashing due to an uncaught exception will include the actual throw
  12. point.
  13.  
  14. Reviewed-by:
  15. ---
  16. src/corelib/kernel/qcoreapplication.cpp |  101 +++++++++++++-----------
  17.  src/corelib/kernel/qeventloop.cpp       |   60 +++++++-------
  18.  src/corelib/kernel/qobject.cpp          |  130 ++++++++++++++++--------------
  19.  3 files changed, 154 insertions(+), 137 deletions(-)
  20.  
  21. diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
  22. index 381be34..90842f7 100644
  23. --- a/src/corelib/kernel/qcoreapplication.cpp
  24. +++ b/src/corelib/kernel/qcoreapplication.cpp
  25. @@ -772,7 +772,16 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
  26.      // call overhead.
  27.      QObjectPrivate *d = receiver->d_func();
  28.      QThreadData *threadData = d->threadData;
  29. -    ++threadData->loopLevel;
  30. +
  31. +    // Exception-safety without try/catch
  32. +    struct Incrementer {
  33. +        int &variable;
  34. +        inline Incrementer(int &variable) : variable(variable)
  35. +        { ++variable; }
  36. +        inline ~Incrementer()
  37. +        { --variable; }
  38. +    };
  39. +    Incrementer inc(threadData->loopLevel);
  40.  
  41.  #ifdef QT_JAMBI_BUILD
  42.      int deleteWatch = 0;
  43. @@ -783,12 +792,7 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
  44.  #endif
  45.  
  46.      bool returnValue;
  47. -    QT_TRY {
  48. -        returnValue = notify(receiver, event);
  49. -    } QT_CATCH (...) {
  50. -        --threadData->loopLevel;
  51. -        QT_RETHROW;
  52. -    }
  53. +    returnValue = notify(receiver, event);
  54.  
  55.  #ifdef QT_JAMBI_BUILD
  56.      // Restore the previous state if the object was not deleted..
  57. @@ -797,7 +801,6 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
  58.      }
  59.      QObjectPrivate::resetDeleteWatch(d, oldDeleteWatch, deleteWatch);
  60.  #endif
  61. -    --threadData->loopLevel;
  62.      return returnValue;
  63.  }
  64.  
  65. @@ -1371,6 +1374,40 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
  66.      int &i = (!event_type && !receiver) ? data->postEventList.startOffset : startOffset;
  67.      data->postEventList.insertionOffset = data->postEventList.size();
  68.  
  69. +    // Exception-safe cleaning up without the need for a try/catch block
  70. +    struct CleanUp {
  71. +        QObject *receiver;
  72. +        int event_type;
  73. +        QThreadData *data;
  74. +        bool exceptionCaught;
  75. +
  76. +        inline CleanUp(QObject *receiver, int event_type, QThreadData *data) :
  77. +            receiver(receiver), event_type(event_type), data(data), exceptionCaught(true)
  78. +        {}
  79. +        inline ~CleanUp()
  80. +        {
  81. +            if (exceptionCaught) {
  82. +                // since we were interrupted, we need another pass to make sure we clean everything up
  83. +                data->canWait = false;
  84. +            }
  85. +
  86. +            --data->postEventList.recursion;
  87. +            if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher)
  88. +                data->eventDispatcher->wakeUp();
  89. +
  90. +            // clear the global list, i.e. remove everything that was
  91. +            // delivered.
  92. +            if (!event_type && !receiver && data->postEventList.startOffset >= 0) {
  93. +                const QPostEventList::iterator it = data->postEventList.begin();
  94. +                data->postEventList.erase(it, it + data->postEventList.startOffset);
  95. +                data->postEventList.insertionOffset -= data->postEventList.startOffset;
  96. +                Q_ASSERT(data->postEventList.insertionOffset >= 0);
  97. +                data->postEventList.startOffset = 0;
  98. +            }
  99. +        }
  100. +    };
  101. +    CleanUp cleanup(receiver, event_type, data);
  102. +
  103.      while (i < data->postEventList.size()) {
  104.          // avoid live-lock
  105.          if (i >= data->postEventList.insertionOffset)
  106. @@ -1409,7 +1446,7 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
  107.          // first, we diddle the event so that we can deliver
  108.          // it, and that no one will try to touch it later.
  109.          pe.event->posted = false;
  110. -        QEvent * e = pe.event;
  111. +        QScopedPointer<QEvent> e(pe.event);
  112.          QObject * r = pe.receiver;
  113.  
  114.          --r->d_func()->postedEvents;
  115. @@ -1419,49 +1456,23 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
  116.          // for the next event.
  117.          const_cast<QPostEvent &>(pe).event = 0;
  118.  
  119. -        locker.unlock();
  120. -        // after all that work, it's time to deliver the event.
  121. -#ifdef QT_NO_EXCEPTIONS
  122. -        QCoreApplication::sendEvent(r, e);
  123. -#else
  124. -        try {
  125. -            QCoreApplication::sendEvent(r, e);
  126. -        } catch (...) {
  127. -            delete e;
  128. -            locker.relock();
  129. -
  130. -            // since we were interrupted, we need another pass to make sure we clean everything up
  131. -            data->canWait = false;
  132. -
  133. -            // uglehack: copied from below
  134. -            --data->postEventList.recursion;
  135. -            if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher)
  136. -                data->eventDispatcher->wakeUp();
  137. -            throw;              // rethrow
  138. -        }
  139. -#endif
  140. +        struct MutexUnlocker
  141. +        {
  142. +            QMutexLocker &m;
  143. +            MutexUnlocker(QMutexLocker &m) : m(m) { m.unlock(); }
  144. +            ~MutexUnlocker() { m.relock(); }
  145. +        };
  146. +        MutexUnlocker unlocker(locker);
  147.  
  148. -        delete e;
  149. -        locker.relock();
  150. +        // after all that work, it's time to deliver the event.
  151. +        QCoreApplication::sendEvent(r, e.data());
  152.  
  153.          // careful when adding anything below this point - the
  154.          // sendEvent() call might invalidate any invariants this
  155.          // function depends on.
  156.      }
  157.  
  158. -    --data->postEventList.recursion;
  159. -    if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher)
  160. -        data->eventDispatcher->wakeUp();
  161. -
  162. -    // clear the global list, i.e. remove everything that was
  163. -    // delivered.
  164. -    if (!event_type && !receiver && data->postEventList.startOffset >= 0) {
  165. -        const QPostEventList::iterator it = data->postEventList.begin();
  166. -        data->postEventList.erase(it, it + data->postEventList.startOffset);
  167. -        data->postEventList.insertionOffset -= data->postEventList.startOffset;
  168. -        Q_ASSERT(data->postEventList.insertionOffset >= 0);
  169. -        data->postEventList.startOffset = 0;
  170. -    }
  171. +    cleanup.exceptionCaught = false;
  172.  }
  173.  
  174.  /*!
  175. diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp
  176. index e78f86a..e1a76d5 100644
  177. --- a/src/corelib/kernel/qeventloop.cpp
  178. +++ b/src/corelib/kernel/qeventloop.cpp
  179. @@ -182,46 +182,44 @@ int QEventLoop::exec(ProcessEventsFlags flags)
  180.          qWarning("QEventLoop::exec: instance %p has already called exec()", this);
  181.          return -1;
  182.      }
  183. -    d->inExec = true;
  184. -    d->exit = false;
  185. -    ++d->threadData->loopLevel;
  186. -    d->threadData->eventLoops.push(this);
  187. +
  188. +    struct LoopReference {
  189. +        QEventLoopPrivate *d;
  190. +
  191. +        bool exceptionCaught;
  192. +        LoopReference(QEventLoopPrivate *d) : d(d), exceptionCaught(true)
  193. +        {
  194. +            d->inExec = true;
  195. +            d->exit = false;
  196. +            ++d->threadData->loopLevel;
  197. +            d->threadData->eventLoops.push(d->q_func());
  198. +        }
  199. +
  200. +        ~LoopReference()
  201. +        {
  202. +            if (exceptionCaught) {
  203. +                qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
  204. +                         "exceptions from an event handler is not supported in Qt. You must\n"
  205. +                         "reimplement QApplication::notify() and catch all exceptions there.\n");
  206. +            }
  207. +            QEventLoop *eventLoop = d->threadData->eventLoops.pop();
  208. +            Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
  209. +            Q_UNUSED(eventLoop); // --release warning
  210. +            d->inExec = false;
  211. +            --d->threadData->loopLevel;
  212. +        }
  213. +    };
  214. +    LoopReference ref(d);
  215.  
  216.      // remove posted quit events when entering a new event loop
  217.      QCoreApplication *app = QCoreApplication::instance();
  218.      if (app && app->thread() == thread())
  219.          QCoreApplication::removePostedEvents(app, QEvent::Quit);
  220.  
  221. -#if defined(QT_NO_EXCEPTIONS)
  222.      while (!d->exit)
  223.          processEvents(flags | WaitForMoreEvents | EventLoopExec);
  224. -#else
  225. -    try {
  226. -        while (!d->exit)
  227. -            processEvents(flags | WaitForMoreEvents | EventLoopExec);
  228. -    } catch (...) {
  229. -        qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
  230. -                 "exceptions from an event handler is not supported in Qt. You must\n"
  231. -                 "reimplement QApplication::notify() and catch all exceptions there.\n");
  232. -
  233. -        // copied from below
  234. -        QEventLoop *eventLoop = d->threadData->eventLoops.pop();
  235. -        Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
  236. -        Q_UNUSED(eventLoop); // --release warning
  237. -        d->inExec = false;
  238. -        --d->threadData->loopLevel;
  239. -
  240. -        throw;
  241. -    }
  242. -#endif
  243. -
  244. -    // copied above
  245. -    QEventLoop *eventLoop = d->threadData->eventLoops.pop();
  246. -    Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
  247. -    Q_UNUSED(eventLoop); // --release warning
  248. -    d->inExec = false;
  249. -    --d->threadData->loopLevel;
  250.  
  251. +    ref.exceptionCaught = false;
  252.      return d->returnCode;
  253.  }
  254.  
  255. diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
  256. index 644c83f..178df9c 100644
  257. --- a/src/corelib/kernel/qobject.cpp
  258. +++ b/src/corelib/kernel/qobject.cpp
  259. @@ -125,6 +125,39 @@ extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *)
  260.      }
  261.  }
  262.  
  263. +struct QConnectionSenderSwitcher {
  264. +    QObject *receiver;
  265. +    QObjectPrivate::Sender *previousSender;
  266. +    QObjectPrivate::Sender currentSender;
  267. +    bool switched;
  268. +
  269. +    inline QConnectionSenderSwitcher() : switched(false) {}
  270. +
  271. +    inline QConnectionSenderSwitcher(QObject *receiver, QObject *sender, int signal_absolute_id)
  272. +    {
  273. +        switchSender(receiver, sender, signal_absolute_id);
  274. +    }
  275. +
  276. +    inline void switchSender(QObject *receiver, QObject *sender, int signal_absolute_id)
  277. +    {
  278. +        this->receiver = receiver;
  279. +        currentSender.sender = sender;
  280. +        currentSender.signal = signal_absolute_id;
  281. +        currentSender.ref = 1;
  282. +        previousSender = QObjectPrivate::setCurrentSender(receiver, &currentSender);
  283. +        switched = true;
  284. +    }
  285. +
  286. +    inline ~QConnectionSenderSwitcher()
  287. +    {
  288. +        if (switched)
  289. +            QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
  290. +    }
  291. +private:
  292. +    Q_DISABLE_COPY(QConnectionSenderSwitcher)
  293. +};
  294. +
  295. +
  296.  void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0;
  297.  void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0;
  298.  void (*QAbstractDeclarativeData::objectNameChanged)(QAbstractDeclarativeData *, QObject *) = 0;
  299. @@ -1204,23 +1237,10 @@ bool QObject::event(QEvent *e)
  300.          {
  301.              d_func()->inEventHandler = false;
  302.              QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e);
  303. -            QObjectPrivate::Sender currentSender;
  304. -            currentSender.sender = const_cast<QObject*>(mce->sender());
  305. -            currentSender.signal = mce->signalId();
  306. -            currentSender.ref = 1;
  307. -            QObjectPrivate::Sender * const previousSender =
  308. -                QObjectPrivate::setCurrentSender(this, &currentSender);
  309. -#if defined(QT_NO_EXCEPTIONS)
  310. +
  311. +            QConnectionSenderSwitcher sw(this, const_cast<QObject*>(mce->sender()), mce->signalId());
  312. +
  313.              mce->placeMetaCall(this);
  314. -#else
  315. -            QT_TRY {
  316. -                mce->placeMetaCall(this);
  317. -            } QT_CATCH(...) {
  318. -                QObjectPrivate::resetCurrentSender(this, &currentSender, previousSender);
  319. -                QT_RETHROW;
  320. -            }
  321. -#endif
  322. -            QObjectPrivate::resetCurrentSender(this, &currentSender, previousSender);
  323.              break;
  324.          }
  325.  
  326. @@ -2910,7 +2930,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
  327.          type &= Qt::UniqueConnection - 1;
  328.      }
  329.  
  330. -    QObjectPrivate::Connection *c = new QObjectPrivate::Connection;
  331. +    QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
  332.      c->sender = s;
  333.      c->receiver = r;
  334.      c->method = method_index;
  335. @@ -2918,16 +2938,11 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
  336.      c->argumentTypes = types;
  337.      c->nextConnectionList = 0;
  338.  
  339. -    QT_TRY {
  340. -        QObjectPrivate::get(s)->addConnection(signal_index, c);
  341. -    } QT_CATCH(...) {
  342. -        delete c;
  343. -        QT_RETHROW;
  344. -    }
  345. +    QObjectPrivate::get(s)->addConnection(signal_index, c.data());
  346.  
  347.      c->prev = &(QObjectPrivate::get(r)->senders);
  348.      c->next = *c->prev;
  349. -    *c->prev = c;
  350. +    *c->prev = c.data();
  351.      if (c->next)
  352.          c->next->prev = &c->next;
  353.  
  354. @@ -2938,6 +2953,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
  355.          sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
  356.      }
  357.  
  358. +    c.take(); // stop tracking
  359.      return true;
  360.  }
  361.  
  362. @@ -3219,19 +3235,42 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
  363.  
  364.      QThreadData *currentThreadData = QThreadData::current();
  365.  
  366. +    {
  367.      QMutexLocker locker(signalSlotLock(sender));
  368. -    QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists;
  369. -    if (!connectionLists) {
  370. +    struct ConnectionListsRef {
  371. +        QObjectConnectionListVector *connectionLists;
  372. +        ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists)
  373. +        {
  374. +            if (connectionLists)
  375. +                ++connectionLists->inUse;
  376. +        }
  377. +        ~ConnectionListsRef()
  378. +        {
  379. +            if (!connectionLists)
  380. +                return;
  381. +
  382. +            --connectionLists->inUse;
  383. +            Q_ASSERT(connectionLists->inUse >= 0);
  384. +            if (connectionLists->orphaned) {
  385. +                if (!connectionLists->inUse)
  386. +                    delete connectionLists;
  387. +            }
  388. +        }
  389. +
  390. +        QObjectConnectionListVector *operator->() const { return connectionLists; }
  391. +    };
  392. +    ConnectionListsRef connectionLists = sender->d_func()->connectionLists;
  393. +    if (!connectionLists.connectionLists) {
  394.          locker.unlock();
  395.          if (qt_signal_spy_callback_set.signal_end_callback != 0)
  396.              qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index);
  397.          return;
  398.      }
  399. -    ++connectionLists->inUse;
  400.      if (signal_index >= connectionLists->count()) {
  401.          signal_index = -2; //for "all signals";
  402.      }
  403.  
  404. +
  405.      do {
  406.          QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;
  407.          if (!c) continue;
  408. @@ -3259,14 +3298,11 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
  409.              }
  410.  
  411.              const int method = c->method;
  412. -            QObjectPrivate::Sender currentSender;
  413.              const bool receiverInSameThread = currentThreadData == receiver->d_func()->threadData;
  414. -            QObjectPrivate::Sender *previousSender = 0;
  415. +            QConnectionSenderSwitcher sw;
  416. +
  417.              if (receiverInSameThread) {
  418. -                currentSender.sender = sender;
  419. -                currentSender.signal = signal_absolute_index;
  420. -                currentSender.ref = 1;
  421. -                previousSender = QObjectPrivate::setCurrentSender(receiver, &currentSender);
  422. +                sw.switchSender(receiver, sender, signal_absolute_index);
  423.              }
  424.              locker.unlock();
  425.  
  426. @@ -3276,32 +3312,13 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
  427.                                                                 argv ? argv : empty_argv);
  428.              }
  429.  
  430. -#if defined(QT_NO_EXCEPTIONS)
  431.              metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
  432. -#else
  433. -            QT_TRY {
  434. -                metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
  435. -            } QT_CATCH(...) {
  436. -                locker.relock();
  437. -                if (receiverInSameThread)
  438. -                    QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
  439. -
  440. -                --connectionLists->inUse;
  441. -                Q_ASSERT(connectionLists->inUse >= 0);
  442. -                if (connectionLists->orphaned && !connectionLists->inUse)
  443. -                    delete connectionLists;
  444. -                QT_RETHROW;
  445. -            }
  446. -#endif
  447.  
  448.              if (qt_signal_spy_callback_set.slot_end_callback != 0)
  449.                  qt_signal_spy_callback_set.slot_end_callback(receiver, method);
  450.  
  451.              locker.relock();
  452.  
  453. -            if (receiverInSameThread)
  454. -                QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
  455. -
  456.              if (connectionLists->orphaned)
  457.                  break;
  458.          } while (c != last && (c = c->nextConnectionList) != 0);
  459. @@ -3310,17 +3327,8 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
  460.              break;
  461.      } while (signal_index >= 0 && (signal_index = -1)); //start over for -1 (all signal)
  462.  
  463. -    --connectionLists->inUse;
  464. -    Q_ASSERT(connectionLists->inUse >= 0);
  465. -    if (connectionLists->orphaned) {
  466. -        if (!connectionLists->inUse)
  467. -            delete connectionLists;
  468. -    } else if (connectionLists->dirty) {
  469. -        sender->d_func()->cleanConnectionLists();
  470.      }
  471.  
  472. -    locker.unlock();
  473. -
  474.      if (qt_signal_spy_callback_set.signal_end_callback != 0)
  475.          qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index);
  476.  
  477. --
  478. 1.7.3.2.431.ge2f5c
RAW Paste Data
Top