daily pastebin goal
83%
SHARE
TWEET

Untitled

a guest Jul 17th, 2017 352 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
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top