[SCM] qtbase packaging branch, ubuntu, updated. ubuntu/5.5.1+dfsg-13ubuntu2-10-ga6888e3

Timo Jyrinki timo at moszumanska.debian.org
Tue Feb 23 14:11:02 UTC 2016


Gitweb-URL: http://git.debian.org/?p=pkg-kde/qt/qtbase.git;a=commitdiff;h=7d2247e

The following commit has been merged in the ubuntu branch:
commit 7d2247e1344fa3b9227d8516d42f2e411d0402d6
Author: Timo Jyrinki <timo.jyrinki at canonical.com>
Date:   Tue Feb 23 14:07:19 2016 +0000

    debian/patches/Fix-for-deferredDelete-bug-when-calling-the-glib-loo.patch
    
    * debian/patches/Fix-for-deferredDelete-bug-when-calling-the-glib-loo.patch:
      - Fix DeferredDelete events handling. (LP: #1460970)
---
 debian/changelog                                   |   2 +
 ...erredDelete-bug-when-calling-the-glib-loo.patch | 330 +++++++++++++++++++++
 debian/patches/series                              |   1 +
 3 files changed, 333 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 5b128d1..e9252b0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,6 +2,8 @@ qtbase-opensource-src (5.5.1+dfsg-14ubuntu2) UNRELEASED; urgency=medium
 
   * debian/patches/enable-tests.patch: some qnetworkcookiejar tests have 
     started failing without any Qt changes (LP: #1548686)
+  * debian/patches/Fix-for-deferredDelete-bug-when-calling-the-glib-loo.patch:
+    - Fix DeferredDelete events handling. (LP: #1460970)
 
  -- Timo Jyrinki <timo-jyrinki at ubuntu.com>  Fri, 19 Feb 2016 08:46:28 +0000
 
diff --git a/debian/patches/Fix-for-deferredDelete-bug-when-calling-the-glib-loo.patch b/debian/patches/Fix-for-deferredDelete-bug-when-calling-the-glib-loo.patch
new file mode 100644
index 0000000..48f3283
--- /dev/null
+++ b/debian/patches/Fix-for-deferredDelete-bug-when-calling-the-glib-loo.patch
@@ -0,0 +1,330 @@
+From c5d49725779292a04fed599eb7f508d334ffc5c3 Mon Sep 17 00:00:00 2001
+From: Paolo Angelelli <paolo.angelelli at theqtcompany.com>
+Date: Thu, 3 Dec 2015 10:57:55 +0100
+Subject: [PATCH] Fix for deferredDelete() bug when calling the glib loop
+ directly
+
+This patch makes sure that all events posted using Qt on top of the
+GLib event loop have the loopLevel counter incremented.
+This is done since Qt depends on the fact that all deleteLater() calls
+are issued within the scope of some signal handler (in other words,
+triggered by the chain sendEvent() -> notifyInternal2()).
+There is a side effect though: in the conditions affected by this
+patch, that is deleteLater()s issued within a glib event handler for
+example, manually calling processEvents() or sendPostedEvents() with
+or without the QEvent::DeferredDelete flag has the same effect, and
+deferred deleted events are always processed.
+While this is not a currently working feature which the patch breaks,
+this side effect seems to be difficult to avoid without separating
+sendPostedEvents() and processEvents() into a public and a private
+method, in order to detect when they are manually called.
+Such change could perhaps be done for Qt6.
+An autotest for QTBUG-36434 is also included.
+Autotesting for QTBUG-32859 seems to be more challenging in this
+respect, due to its dependency on GLib.
+
+Task-number: QTBUG-18434
+Task-number: QTBUG-32859
+Task-number: QTBUG-36434
+Change-Id: Ib89175aa27c9e38bca68ae254d182b2cd21cf7e9
+Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart at woboq.com>
+---
+ src/corelib/kernel/qabstracteventdispatcher.cpp   |  2 +-
+ src/corelib/kernel/qcoreapplication.cpp           | 46 ++++++++---
+ src/corelib/thread/qthread.cpp                    |  2 +-
+ src/corelib/thread/qthread_p.h                    | 11 +--
+ src/plugins/platforms/cocoa/qcocoamenu.mm         |  2 +-
+ src/plugins/platforms/cocoa/qcocoamenuloader.mm   |  2 +-
+ tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 97 +++++++++++++++++++++++
+ 7 files changed, 143 insertions(+), 19 deletions(-)
+
+diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp
+index 31369f9..907b3cc 100644
+--- a/src/corelib/kernel/qabstracteventdispatcher.cpp
++++ b/src/corelib/kernel/qabstracteventdispatcher.cpp
+@@ -458,7 +458,7 @@ bool QAbstractEventDispatcher::filterNativeEvent(const QByteArray &eventType, vo
+     if (!d->eventFilters.isEmpty()) {
+         // Raise the loopLevel so that deleteLater() calls in or triggered
+         // by event_filter() will be processed from the main event loop.
+-        QScopedLoopLevelCounter loopLevelCounter(d->threadData);
++        QScopedScopeLevelCounter scopeLevelCounter(d->threadData);
+         for (int i = 0; i < d->eventFilters.size(); ++i) {
+             QAbstractNativeEventFilter *filter = d->eventFilters.at(i);
+             if (!filter)
+diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
+index 60f3dc0..42bda25 100644
+--- a/src/corelib/kernel/qcoreapplication.cpp
++++ b/src/corelib/kernel/qcoreapplication.cpp
+@@ -980,7 +980,7 @@ bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
+     // call overhead.
+     QObjectPrivate *d = receiver->d_func();
+     QThreadData *threadData = d->threadData;
+-    QScopedLoopLevelCounter loopLevelCounter(threadData);
++    QScopedScopeLevelCounter scopeLevelCounter(threadData);
+     return notify(receiver, event);
+ }
+ 
+@@ -1193,6 +1193,9 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)
+ */
+ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime)
+ {
++    // ### Qt 6: consider splitting this method into a public and a private
++    //           one, so that a user-invoked processEvents can be detected
++    //           and handled properly.
+     QThreadData *data = QThreadData::current();
+     if (!data->hasEventDispatcher())
+         return;
+@@ -1396,8 +1399,24 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
+ 
+     if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {
+         // remember the current running eventloop for DeferredDelete
+-        // events posted in the receiver's thread
+-        static_cast<QDeferredDeleteEvent *>(event)->level = data->loopLevel;
++        // events posted in the receiver's thread.
++
++        // Events sent by non-Qt event handlers (such as glib) may not
++        // have the scopeLevel set correctly. The scope level makes sure that
++        // code like this:
++        //     foo->deleteLater();
++        //     qApp->processEvents(); // without passing QEvent::DeferredDelete
++        // will not cause "foo" to be deleted before returning to the event loop.
++
++        // If the scope level is 0 while loopLevel != 0, we are called from a
++        // non-conformant code path, and our best guess is that the scope level
++        // should be 1. (Loop level 0 is special: it means that no event loops
++        // are running.)
++        int loopLevel = data->loopLevel;
++        int scopeLevel = data->scopeLevel;
++        if (scopeLevel == 0 && loopLevel != 0)
++            scopeLevel = 1;
++        static_cast<QDeferredDeleteEvent *>(event)->level = loopLevel + scopeLevel;
+     }
+ 
+     // delete the event on exceptions to protect against memory leaks till the event is
+@@ -1474,6 +1493,9 @@ bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEven
+ */
+ void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type)
+ {
++    // ### Qt 6: consider splitting this method into a public and a private
++    //           one, so that a user-invoked sendPostedEvents can be detected
++    //           and handled properly.
+     QThreadData *data = QThreadData::current();
+ 
+     QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data);
+@@ -1565,15 +1587,19 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
+         }
+ 
+         if (pe.event->type() == QEvent::DeferredDelete) {
+-            // DeferredDelete events are only sent when we are explicitly asked to
+-            // (s.a. QEvent::DeferredDelete), and then only if the event loop that
+-            // posted the event has returned.
+-            int loopLevel = static_cast<QDeferredDeleteEvent *>(pe.event)->loopLevel();
++            // DeferredDelete events are sent either
++            // 1) when the event loop that posted the event has returned; or
++            // 2) if explicitly requested (with QEvent::DeferredDelete) for
++            //    events posted by the current event loop; or
++            // 3) if the event was posted before the outermost event loop.
++
++            int eventLevel = static_cast<QDeferredDeleteEvent *>(pe.event)->loopLevel();
++            int loopLevel = data->loopLevel + data->scopeLevel;
+             const bool allowDeferredDelete =
+-                (loopLevel > data->loopLevel
+-                 || (!loopLevel && data->loopLevel > 0)
++                (eventLevel > loopLevel
++                 || (!eventLevel && loopLevel > 0)
+                  || (event_type == QEvent::DeferredDelete
+-                     && loopLevel == data->loopLevel));
++                     && eventLevel == loopLevel));
+             if (!allowDeferredDelete) {
+                 // cannot send deferred delete
+                 if (!event_type && !receiver) {
+diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
+index 14209d8..69f8d72 100644
+--- a/src/corelib/thread/qthread.cpp
++++ b/src/corelib/thread/qthread.cpp
+@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
+ */
+ 
+ QThreadData::QThreadData(int initialRefCount)
+-    : _ref(initialRefCount), loopLevel(0), thread(0), threadId(0),
++    : _ref(initialRefCount), loopLevel(0), scopeLevel(0), thread(0), threadId(0),
+       eventDispatcher(0), quitNow(false), canWait(true), isAdopted(false)
+ {
+     // fprintf(stderr, "QThreadData %p created
", this);
+diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
+index 39a41f1..5f7d01f 100644
+--- a/src/corelib/thread/qthread_p.h
++++ b/src/corelib/thread/qthread_p.h
+@@ -280,6 +280,7 @@ private:
+ 
+ public:
+     int loopLevel;
++    int scopeLevel;
+ 
+     QStack<QEventLoop *> eventLoops;
+     QPostEventList postEventList;
+@@ -295,15 +296,15 @@ public:
+     bool isAdopted;
+ };
+ 
+-class QScopedLoopLevelCounter
++class QScopedScopeLevelCounter
+ {
+     QThreadData *threadData;
+ public:
+-    inline QScopedLoopLevelCounter(QThreadData *threadData)
++    inline QScopedScopeLevelCounter(QThreadData *threadData)
+         : threadData(threadData)
+-    { ++threadData->loopLevel; }
+-    inline ~QScopedLoopLevelCounter()
+-    { --threadData->loopLevel; }
++    { ++threadData->scopeLevel; }
++    inline ~QScopedScopeLevelCounter()
++    { --threadData->scopeLevel; }
+ };
+ 
+ // thread wrapper for the main() thread
+diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
+index 8091ba8..8c576c7 100644
+--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
++++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
+@@ -128,7 +128,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate);
+ - (void) itemFired:(NSMenuItem*) item
+ {
+     QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]);
+-    QScopedLoopLevelCounter loopLevelCounter(QGuiApplicationPrivate::instance()->threadData);
++    QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
+     QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
+     static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
+     activatedSignal.invoke(cocoaItem, Qt::QueuedConnection);
+diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+index d73b9a8..e440a90 100644
+--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
++++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+@@ -308,7 +308,7 @@ QT_END_NAMESPACE
+ 
+     if ([item tag]) {
+         QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]);
+-        QScopedLoopLevelCounter loopLevelCounter(QGuiApplicationPrivate::instance()->threadData);
++        QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
+         cocoaItem->activated();
+     }
+ }
+diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+index 0f45ba4..540284f 100644
+--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
++++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+@@ -142,6 +142,7 @@ private slots:
+     void qmlConnect();
+     void exceptions();
+     void noDeclarativeParentChangedOnDestruction();
++    void deleteLaterInAboutToBlockHandler();
+ };
+ 
+ struct QObjectCreatedOnShutdown
+@@ -5789,6 +5790,102 @@ void tst_QObject::connectFunctorWithContext()
+     context->deleteLater();
+ }
+ 
++class StatusChanger : public QObject
++{
++    Q_OBJECT
++public:
++    StatusChanger(int *status) : m_status(status)
++    {
++    }
++    ~StatusChanger()
++    {
++        *m_status = 2;
++    }
++private:
++    int *m_status;
++};
++
++class DispatcherWatcher : public QObject
++{
++    Q_OBJECT
++public:
++    DispatcherWatcher(QEventLoop &e, int *statusAwake, int *statusAboutToBlock) :
++        m_statusAboutToBlock(statusAboutToBlock),
++        m_statusAwake(statusAwake),
++        m_eventLoop(&e),
++        m_aboutToBlocks(0),
++        m_awakes(0)
++    {
++        awake = new StatusChanger(statusAwake);
++        abouttoblock = new StatusChanger(statusAboutToBlock);
++        QCOMPARE(*statusAwake, 1);
++        QCOMPARE(*statusAboutToBlock, 1);
++        connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), this, SLOT(onAwake()));
++        connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()), this, SLOT(onAboutToBlock()));
++
++    }
++
++    ~DispatcherWatcher()
++    {
++        if (awake)
++            awake->deleteLater();
++        if (abouttoblock)
++            abouttoblock->deleteLater();
++    }
++
++public slots:
++    // The order of these 2 handlers differs on different event dispatchers
++    void onAboutToBlock()
++    {
++        if (abouttoblock) {
++            abouttoblock->deleteLater();
++            abouttoblock = 0;
++        }
++        ++m_aboutToBlocks;
++    }
++    void onAwake()
++    {
++        if (awake) {
++            awake->deleteLater();
++            awake = 0;
++        }
++        ++m_awakes;
++
++    }
++    void onSignal1()
++    {
++        // Status check. At this point the event loop should have spinned enough to delete all the objects.
++        QCOMPARE(*m_statusAwake, 2);
++        QCOMPARE(*m_statusAboutToBlock, 2);
++        QMetaObject::invokeMethod(m_eventLoop, "quit", Qt::QueuedConnection);
++    }
++
++private:
++    StatusChanger *awake;
++    StatusChanger *abouttoblock;
++    QEventLoop    *m_eventLoop;
++    int *m_statusAwake;
++    int *m_statusAboutToBlock;
++    int m_aboutToBlocks;
++    int m_awakes;
++};
++
++
++void tst_QObject::deleteLaterInAboutToBlockHandler()
++{
++    int statusAwake        = 1;
++    int statusAboutToBlock = 1;
++    QEventLoop e;
++    DispatcherWatcher dw(e, &statusAwake, &statusAboutToBlock);
++    QTimer::singleShot(2000, &dw, &DispatcherWatcher::onSignal1);
++
++    QCOMPARE(statusAwake, 1);
++    QCOMPARE(statusAboutToBlock, 1);
++    e.exec();
++    QCOMPARE(statusAwake, 2);
++    QCOMPARE(statusAboutToBlock, 2);
++}
++
+ class MyFunctor
+ {
+ public:
+-- 
+2.7.0
+
diff --git a/debian/patches/series b/debian/patches/series
index f0a16db..816aa6d 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -25,6 +25,7 @@ xcb_dont_select_XInput_events_on_root_window.patch
 xcb_fix_drag_and_drop_when_window_is_hidden.patch
 fix_not_delivering_focus.patch
 fix_potential_division_by_zero.patch
+Fix-for-deferredDelete-bug-when-calling-the-glib-loo.patch
 
 # Debian specific.
 gnukfreebsd.diff

-- 
qtbase packaging



More information about the pkg-kde-commits mailing list