Title: [221361] releases/WebKitGTK/webkit-2.18/Source/WebKit
Revision
221361
Author
carlo...@webkit.org
Date
2017-08-30 03:12:18 -0700 (Wed, 30 Aug 2017)

Log Message

Merge r221238 - [GTK][WPE] ASSERTION FAILED: !isOpen() in WebKit::IconDatabase::~IconDatabase()
https://bugs.webkit.org/show_bug.cgi?id=175719

Reviewed by Michael Catanzaro.

This is happening always when running /webkit2/WebKitFaviconDatabase/favicon-database-test in debug builds. The
last step we do is removing all icons, then the test finishes, which destroys the WebKitFaviconDatabase object
that closes the icon database on dispose. The problem is that removing all icons schedules a main thread
notification and IconDatabase is not considered closed until all main thread callbacks have been dispatched. This
is never going to happen in the test, because the main loop is no longer running at that point. I don't think
it's worth it to consider the database open while main thread callbacks are pending, they are just notifications
and the client is no longer insterested on them afer closing the database. I think it's bettter and simpler to
simply cancel the pending callbacks on database close. That ensures that isOpen() after close() is always
false. This patch adds a helper private class to schedule notifications to the main thread that can be cancelled
on database close. It also removes the didClose() notification because it was unused and because it's pointless
now that we know the database is closed after close().

* UIProcess/API/glib/IconDatabase.cpp:
(WebKit::IconDatabase::open): Mark the main thread notifier as active.
(WebKit::IconDatabase::close): Mark the main thread notifier as not active.
(WebKit::IconDatabase::IconDatabase): Remove m_mainThreadCallbackCount initialization.
(WebKit::IconDatabase::isOpen const): Do what isOpenBesidesMainThreadCallbacks() used to do.
(WebKit::IconDatabase::removeAllIconsOnThread): Remove the notification because it's currently unused.
(WebKit::IconDatabase::dispatchDidImportIconURLForPageURLOnMainThread): Use MainThreadNotifier.
(WebKit::IconDatabase::dispatchDidImportIconDataForPageURLOnMainThread): Ditto.
(WebKit::IconDatabase::dispatchDidFinishURLImportOnMainThread): Ditto.
(WebKit::IconDatabase::isOpenBesidesMainThreadCallbacks const): Deleted.
(WebKit::IconDatabase::checkClosedAfterMainThreadCallback): Deleted.
(WebKit::IconDatabase::dispatchDidRemoveAllIconsOnMainThread): Deleted.
* UIProcess/API/glib/IconDatabase.h:
(WebKit::IconDatabaseClient::didChangeIconForPageURL):
(WebKit::IconDatabaseClient::didFinishURLImport):
(WebKit::IconDatabase::MainThreadNotifier::MainThreadNotifier):
(WebKit::IconDatabase::MainThreadNotifier::setActive):
(WebKit::IconDatabase::MainThreadNotifier::notify):
(WebKit::IconDatabase::MainThreadNotifier::stop):
(WebKit::IconDatabase::MainThreadNotifier::timerFired):
(WebKit::IconDatabaseClient::didRemoveAllIcons): Deleted.
(WebKit::IconDatabaseClient::didClose): Deleted.

Modified Paths

Diff

Modified: releases/WebKitGTK/webkit-2.18/Source/WebKit/ChangeLog (221360 => 221361)


--- releases/WebKitGTK/webkit-2.18/Source/WebKit/ChangeLog	2017-08-30 10:09:40 UTC (rev 221360)
+++ releases/WebKitGTK/webkit-2.18/Source/WebKit/ChangeLog	2017-08-30 10:12:18 UTC (rev 221361)
@@ -1,3 +1,45 @@
+2017-08-28  Carlos Garcia Campos  <cgar...@igalia.com>
+
+        [GTK][WPE] ASSERTION FAILED: !isOpen() in WebKit::IconDatabase::~IconDatabase()
+        https://bugs.webkit.org/show_bug.cgi?id=175719
+
+        Reviewed by Michael Catanzaro.
+
+        This is happening always when running /webkit2/WebKitFaviconDatabase/favicon-database-test in debug builds. The
+        last step we do is removing all icons, then the test finishes, which destroys the WebKitFaviconDatabase object
+        that closes the icon database on dispose. The problem is that removing all icons schedules a main thread
+        notification and IconDatabase is not considered closed until all main thread callbacks have been dispatched. This
+        is never going to happen in the test, because the main loop is no longer running at that point. I don't think
+        it's worth it to consider the database open while main thread callbacks are pending, they are just notifications
+        and the client is no longer insterested on them afer closing the database. I think it's bettter and simpler to
+        simply cancel the pending callbacks on database close. That ensures that isOpen() after close() is always
+        false. This patch adds a helper private class to schedule notifications to the main thread that can be cancelled
+        on database close. It also removes the didClose() notification because it was unused and because it's pointless
+        now that we know the database is closed after close().
+
+        * UIProcess/API/glib/IconDatabase.cpp:
+        (WebKit::IconDatabase::open): Mark the main thread notifier as active.
+        (WebKit::IconDatabase::close): Mark the main thread notifier as not active.
+        (WebKit::IconDatabase::IconDatabase): Remove m_mainThreadCallbackCount initialization.
+        (WebKit::IconDatabase::isOpen const): Do what isOpenBesidesMainThreadCallbacks() used to do.
+        (WebKit::IconDatabase::removeAllIconsOnThread): Remove the notification because it's currently unused.
+        (WebKit::IconDatabase::dispatchDidImportIconURLForPageURLOnMainThread): Use MainThreadNotifier.
+        (WebKit::IconDatabase::dispatchDidImportIconDataForPageURLOnMainThread): Ditto.
+        (WebKit::IconDatabase::dispatchDidFinishURLImportOnMainThread): Ditto.
+        (WebKit::IconDatabase::isOpenBesidesMainThreadCallbacks const): Deleted.
+        (WebKit::IconDatabase::checkClosedAfterMainThreadCallback): Deleted.
+        (WebKit::IconDatabase::dispatchDidRemoveAllIconsOnMainThread): Deleted.
+        * UIProcess/API/glib/IconDatabase.h:
+        (WebKit::IconDatabaseClient::didChangeIconForPageURL):
+        (WebKit::IconDatabaseClient::didFinishURLImport):
+        (WebKit::IconDatabase::MainThreadNotifier::MainThreadNotifier):
+        (WebKit::IconDatabase::MainThreadNotifier::setActive):
+        (WebKit::IconDatabase::MainThreadNotifier::notify):
+        (WebKit::IconDatabase::MainThreadNotifier::stop):
+        (WebKit::IconDatabase::MainThreadNotifier::timerFired):
+        (WebKit::IconDatabaseClient::didRemoveAllIcons): Deleted.
+        (WebKit::IconDatabaseClient::didClose): Deleted.
+
 2017-08-23  Chris Dumez  <cdu...@apple.com>
 
         Regression(r221059): NetworkDataTask::didReceiveResponse() should not use PolicyUse for HTTP/0.9

Modified: releases/WebKitGTK/webkit-2.18/Source/WebKit/UIProcess/API/glib/IconDatabase.cpp (221360 => 221361)


--- releases/WebKitGTK/webkit-2.18/Source/WebKit/UIProcess/API/glib/IconDatabase.cpp	2017-08-30 10:09:40 UTC (rev 221360)
+++ releases/WebKitGTK/webkit-2.18/Source/WebKit/UIProcess/API/glib/IconDatabase.cpp	2017-08-30 10:12:18 UTC (rev 221361)
@@ -86,7 +86,6 @@
     void didImportIconURLForPageURL(const String&) override { }
     void didImportIconDataForPageURL(const String&) override { }
     void didChangeIconForPageURL(const String&) override { }
-    void didRemoveAllIcons() override { }
     void didFinishURLImport() override { }
 };
 
@@ -210,6 +209,8 @@
         return false;
     }
 
+    m_mainThreadNotifier.setActive(true);
+
     m_databaseDirectory = directory.isolatedCopy();
 
     // Formulate the full path for the database file
@@ -232,6 +233,8 @@
 {
     ASSERT_NOT_SYNC_THREAD();
 
+    m_mainThreadNotifier.stop();
+
     if (m_syncThreadRunning) {
         // Set the flag to tell the sync thread to wrap it up
         m_threadTerminationRequested = true;
@@ -249,11 +252,6 @@
 
     m_syncDB.close();
 
-    // If there are still main thread callbacks in flight then the database might not actually be closed yet.
-    // But if it is closed, notify the client now.
-    if (!isOpen() && m_client)
-        m_client->didClose();
-
     m_client = nullptr;
 }
 
@@ -734,7 +732,6 @@
 
 IconDatabase::IconDatabase()
     : m_syncTimer(RunLoop::main(), this, &IconDatabase::syncTimerFired)
-    , m_mainThreadCallbackCount(0)
     , m_client(defaultClient())
 {
     LOG(IconDatabase, "Creating IconDatabase %p", this);
@@ -780,11 +777,6 @@
 
 bool IconDatabase::isOpen() const
 {
-    return isOpenBesidesMainThreadCallbacks() || m_mainThreadCallbackCount;
-}
-
-bool IconDatabase::isOpenBesidesMainThreadCallbacks() const
-{
     LockHolder locker(m_syncLock);
     return m_syncThreadRunning || m_syncDB.isOpen();
 }
@@ -1619,9 +1611,6 @@
     m_syncDB.clearAllTables();
     m_syncDB.runVacuumCommand();
     createDatabaseTables(m_syncDB);
-
-    LOG(IconDatabase, "Dispatching notification that we removed all icons");
-    dispatchDidRemoveAllIconsOnMainThread();
 }
 
 void IconDatabase::deleteAllPreparedStatements()
@@ -1932,32 +1921,13 @@
     }
 }
 
-void IconDatabase::checkClosedAfterMainThreadCallback()
-{
-    ASSERT_NOT_SYNC_THREAD();
-
-    // If there are still callbacks in flight from the sync thread we cannot possibly be closed.
-    if (--m_mainThreadCallbackCount)
-        return;
-
-    // Even if there's no more pending callbacks the database might otherwise still be open.
-    if (isOpenBesidesMainThreadCallbacks())
-        return;
-
-    // This database is now actually closed! But first notify the client.
-    if (m_client)
-        m_client->didClose();
-}
-
 void IconDatabase::dispatchDidImportIconURLForPageURLOnMainThread(const String& pageURL)
 {
     ASSERT_ICON_SYNC_THREAD();
-    ++m_mainThreadCallbackCount;
 
-    callOnMainThread([this, pageURL = pageURL.isolatedCopy()] {
+    m_mainThreadNotifier.notify([this, pageURL = pageURL.isolatedCopy()] {
         if (m_client)
             m_client->didImportIconURLForPageURL(pageURL);
-        checkClosedAfterMainThreadCallback();
     });
 }
 
@@ -1964,36 +1934,20 @@
 void IconDatabase::dispatchDidImportIconDataForPageURLOnMainThread(const String& pageURL)
 {
     ASSERT_ICON_SYNC_THREAD();
-    ++m_mainThreadCallbackCount;
 
-    callOnMainThread([this, pageURL = pageURL.isolatedCopy()] {
+    m_mainThreadNotifier.notify([this, pageURL = pageURL.isolatedCopy()] {
         if (m_client)
             m_client->didImportIconDataForPageURL(pageURL);
-        checkClosedAfterMainThreadCallback();
     });
 }
 
-void IconDatabase::dispatchDidRemoveAllIconsOnMainThread()
-{
-    ASSERT_ICON_SYNC_THREAD();
-    ++m_mainThreadCallbackCount;
-
-    callOnMainThread([this] {
-        if (m_client)
-            m_client->didRemoveAllIcons();
-        checkClosedAfterMainThreadCallback();
-    });
-}
-
 void IconDatabase::dispatchDidFinishURLImportOnMainThread()
 {
     ASSERT_ICON_SYNC_THREAD();
-    ++m_mainThreadCallbackCount;
 
-    callOnMainThread([this] {
+    m_mainThreadNotifier.notify([this] {
         if (m_client)
             m_client->didFinishURLImport();
-        checkClosedAfterMainThreadCallback();
     });
 }
 

Modified: releases/WebKitGTK/webkit-2.18/Source/WebKit/UIProcess/API/glib/IconDatabase.h (221360 => 221361)


--- releases/WebKitGTK/webkit-2.18/Source/WebKit/UIProcess/API/glib/IconDatabase.h	2017-08-30 10:09:40 UTC (rev 221360)
+++ releases/WebKitGTK/webkit-2.18/Source/WebKit/UIProcess/API/glib/IconDatabase.h	2017-08-30 10:12:18 UTC (rev 221361)
@@ -33,6 +33,7 @@
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
 #include <wtf/RunLoop.h>
+#include <wtf/glib/RunLoopSourcePriority.h>
 #include <wtf/text/StringHash.h>
 #include <wtf/text/WTFString.h>
 
@@ -49,9 +50,7 @@
     virtual void didImportIconURLForPageURL(const String&) { }
     virtual void didImportIconDataForPageURL(const String&) { }
     virtual void didChangeIconForPageURL(const String&) { }
-    virtual void didRemoveAllIcons() { }
     virtual void didFinishURLImport() { }
-    virtual void didClose() { }
 };
 
 class IconDatabase {
@@ -172,6 +171,65 @@
         int m_retainCount { 0 };
     };
 
+    class MainThreadNotifier {
+    public:
+        MainThreadNotifier()
+            : m_timer(RunLoop::main(), this, &MainThreadNotifier::timerFired)
+        {
+            m_timer.setPriority(RunLoopSourcePriority::MainThreadDispatcherTimer);
+        }
+
+        void setActive(bool active)
+        {
+            m_isActive.store(active);
+        }
+
+        void notify(Function<void()>&& notification)
+        {
+            if (!m_isActive.load())
+                return;
+
+            {
+                LockHolder locker(m_notificationQueueLock);
+                m_notificationQueue.append(WTFMove(notification));
+            }
+
+            if (!m_timer.isActive())
+                m_timer.startOneShot(0_s);
+        }
+
+        void stop()
+        {
+            setActive(false);
+            m_timer.stop();
+            LockHolder locker(m_notificationQueueLock);
+            m_notificationQueue.clear();
+        }
+
+    private:
+        void timerFired()
+        {
+            Deque<Function<void()>> notificationQueue;
+            {
+                LockHolder locker(m_notificationQueueLock);
+                notificationQueue = WTFMove(m_notificationQueue);
+            }
+
+            if (!m_isActive.load())
+                return;
+
+            while (!notificationQueue.isEmpty()) {
+                auto function = notificationQueue.takeFirst();
+                function();
+            }
+        }
+
+        Deque<Function<void()>> m_notificationQueue;
+        Lock m_notificationQueueLock;
+        Atomic<bool> m_isActive;
+        RunLoop::Timer<MainThreadNotifier> m_timer;
+    };
+
 // *** Main Thread Only ***
 public:
     IconDatabase();
@@ -287,9 +345,6 @@
     void performRetainIconForPageURL(const String&, int retainCount);
     void performReleaseIconForPageURL(const String&, int releaseCount);
 
-    bool isOpenBesidesMainThreadCallbacks() const;
-    void checkClosedAfterMainThreadCallback();
-
     bool m_initialPruningComplete { false };
 
     void setIconURLForPageURLInSQLDatabase(const String&, const String&);
@@ -306,9 +361,7 @@
     // Methods to dispatch client callbacks on the main thread
     void dispatchDidImportIconURLForPageURLOnMainThread(const String&);
     void dispatchDidImportIconDataForPageURLOnMainThread(const String&);
-    void dispatchDidRemoveAllIconsOnMainThread();
     void dispatchDidFinishURLImportOnMainThread();
-    std::atomic<uint32_t> m_mainThreadCallbackCount;
 
     // The client is set by the main thread before the thread starts, and from then on is only used by the sync thread
     std::unique_ptr<IconDatabaseClient> m_client;
@@ -329,6 +382,8 @@
     std::unique_ptr<WebCore::SQLiteStatement> m_updateIconDataStatement;
     std::unique_ptr<WebCore::SQLiteStatement> m_setIconInfoStatement;
     std::unique_ptr<WebCore::SQLiteStatement> m_setIconDataStatement;
+
+    MainThreadNotifier m_mainThreadNotifier;
 };
 
 } // namespace WebKit
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to