Title: [117501] trunk/Source/WebCore
Revision
117501
Author
kl...@webkit.org
Date
2012-05-17 14:49:43 -0700 (Thu, 17 May 2012)

Log Message

IconDatabase: Move icon retain/release off of the main thread.
<http://webkit.org/b/85799>
<rdar://problem/9507113>

Reviewed by Brady Eidson.

Batch up the retain/release operations and execute them as part of the sync thread loop.
The batch execution is guarded by a new mutex (m_urlsToRetainOrReleaseLock.)
This avoids blocking the main thread on m_urlAndIconLock for basic retain/release.

There is one exception; if there are pending retain/release operations in synchronousIconForPageURL,
it will acquire the lock and flush the operations.

There should be no behavior change, this is only meant to reduce lock contention.

* loader/icon/PageURLRecord.h:
(WebCore::PageURLRecord::retain):
(WebCore::PageURLRecord::release):

    Added a 'count' argument to these so we can batch up the operations in IconDatabase.

* loader/icon/IconDatabase.h:
* loader/icon/IconDatabase.cpp:
(WebCore::IconDatabase::performScheduleOrDeferSyncTimer):
(WebCore::IconDatabase::performScheduleOrDeferSyncTimerOnMainThread):
(WebCore::IconDatabase::scheduleOrDeferSyncTimer):

    Perform the the timer scheduling on the main thread as it can be done on a different
    thread by way of retainIconForPageURL or releaseIconForPageURL.

(WebCore::IconDatabase::synchronousIconForPageURL):
(WebCore::IconDatabase::retainIconForPageURL):
(WebCore::IconDatabase::performRetainIconForPageURL):
(WebCore::IconDatabase::releaseIconForPageURL):
(WebCore::IconDatabase::performReleaseIconForPageURL):
(WebCore::IconDatabase::retainedPageURLCount):
(WebCore::IconDatabase::IconDatabase):
(WebCore::IconDatabase::performURLImport):
(WebCore::IconDatabase::syncThreadMainLoop):
(WebCore::IconDatabase::performPendingRetainAndReleaseOperations):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (117500 => 117501)


--- trunk/Source/WebCore/ChangeLog	2012-05-17 21:46:02 UTC (rev 117500)
+++ trunk/Source/WebCore/ChangeLog	2012-05-17 21:49:43 UTC (rev 117501)
@@ -1,3 +1,46 @@
+2012-05-15  Andreas Kling  <kl...@webkit.org>
+
+        IconDatabase: Move icon retain/release off of the main thread.
+        <http://webkit.org/b/85799>
+        <rdar://problem/9507113>
+
+        Reviewed by Brady Eidson.
+
+        Batch up the retain/release operations and execute them as part of the sync thread loop.
+        The batch execution is guarded by a new mutex (m_urlsToRetainOrReleaseLock.)
+        This avoids blocking the main thread on m_urlAndIconLock for basic retain/release.
+
+        There is one exception; if there are pending retain/release operations in synchronousIconForPageURL,
+        it will acquire the lock and flush the operations.
+
+        There should be no behavior change, this is only meant to reduce lock contention.
+
+        * loader/icon/PageURLRecord.h:
+        (WebCore::PageURLRecord::retain):
+        (WebCore::PageURLRecord::release):
+
+            Added a 'count' argument to these so we can batch up the operations in IconDatabase.
+
+        * loader/icon/IconDatabase.h:
+        * loader/icon/IconDatabase.cpp:
+        (WebCore::IconDatabase::performScheduleOrDeferSyncTimer):
+        (WebCore::IconDatabase::performScheduleOrDeferSyncTimerOnMainThread):
+        (WebCore::IconDatabase::scheduleOrDeferSyncTimer):
+
+            Perform the the timer scheduling on the main thread as it can be done on a different
+            thread by way of retainIconForPageURL or releaseIconForPageURL.
+
+        (WebCore::IconDatabase::synchronousIconForPageURL):
+        (WebCore::IconDatabase::retainIconForPageURL):
+        (WebCore::IconDatabase::performRetainIconForPageURL):
+        (WebCore::IconDatabase::releaseIconForPageURL):
+        (WebCore::IconDatabase::performReleaseIconForPageURL):
+        (WebCore::IconDatabase::retainedPageURLCount):
+        (WebCore::IconDatabase::IconDatabase):
+        (WebCore::IconDatabase::performURLImport):
+        (WebCore::IconDatabase::syncThreadMainLoop):
+        (WebCore::IconDatabase::performPendingRetainAndReleaseOperations):
+
 2012-05-17  Julien Chaffraix  <jchaffr...@webkit.org>
 
         Kill RenderLayer::relativePositionOffset(LayoutUnit& relX, LayoutUnit& relY) and cleanup RenderInline::clippedOverflowRectForRepaint

Modified: trunk/Source/WebCore/loader/icon/IconDatabase.cpp (117500 => 117501)


--- trunk/Source/WebCore/loader/icon/IconDatabase.cpp	2012-05-17 21:46:02 UTC (rev 117500)
+++ trunk/Source/WebCore/loader/icon/IconDatabase.cpp	2012-05-17 21:49:43 UTC (rev 117501)
@@ -222,6 +222,9 @@
         return 0;
 
     MutexLocker locker(m_urlAndIconLock);
+
+    if (m_retainOrReleaseIconRequested)
+        performPendingRetainAndReleaseOperations();
     
     String pageURLCopy; // Creates a null string for easy testing
     
@@ -389,18 +392,20 @@
     return m_defaultIconRecord->image(size);
 }
 
+void IconDatabase::retainIconForPageURL(const String& pageURL)
+{
+    ASSERT_NOT_SYNC_THREAD();
 
-void IconDatabase::retainIconForPageURL(const String& pageURLOriginal)
-{    
-    ASSERT_NOT_SYNC_THREAD();
-    
-    // Cannot do anything with pageURLOriginal that would end up storing it without deep copying first
-    
-    if (!isEnabled() || !documentCanHaveIcon(pageURLOriginal))
+    if (!isEnabled() || !documentCanHaveIcon(pageURL))
         return;
        
-    MutexLocker locker(m_urlAndIconLock);
+    MutexLocker locker(m_urlsToRetainOrReleaseLock);
+    m_urlsToRetain.add(pageURL);
+    scheduleOrDeferSyncTimer();
+}
 
+void IconDatabase::performRetainIconForPageURL(const String& pageURLOriginal, int retainCount)
+{
     PageURLRecord* record = m_pageURLToRecordMap.get(pageURLOriginal);
     
     String pageURL;
@@ -412,7 +417,7 @@
         m_pageURLToRecordMap.set(pageURL, record);
     }
     
-    if (!record->retain()) {
+    if (!record->retain(retainCount)) {
         if (pageURL.isNull())
             pageURL = pageURLOriginal.isolatedCopy();
 
@@ -434,17 +439,23 @@
     }
 }
 
-void IconDatabase::releaseIconForPageURL(const String& pageURLOriginal)
+void IconDatabase::releaseIconForPageURL(const String& pageURL)
 {
     ASSERT_NOT_SYNC_THREAD();
         
     // Cannot do anything with pageURLOriginal that would end up storing it without deep copying first
     
-    if (!isEnabled() || !documentCanHaveIcon(pageURLOriginal))
+    if (!isEnabled() || !documentCanHaveIcon(pageURL))
         return;
-    
-    MutexLocker locker(m_urlAndIconLock);
 
+    MutexLocker locker(m_urlsToRetainOrReleaseLock);
+    m_urlsToRelease.add(pageURL);
+    m_retainOrReleaseIconRequested = true;
+    scheduleOrDeferSyncTimer();
+}
+
+void IconDatabase::performReleaseIconForPageURL(const String& pageURLOriginal, int releaseCount)
+{
     // Check if this pageURL is actually retained
     if (!m_retainedPageURLs.contains(pageURLOriginal)) {
         LOG_ERROR("Attempting to release icon for URL %s which is not retained", urlForLogging(pageURLOriginal).ascii().data());
@@ -458,7 +469,7 @@
     ASSERT(pageRecord->retainCount() > 0);
         
     // If it still has a positive retain count, store the new count and bail
-    if (pageRecord->release())
+    if (pageRecord->release(releaseCount))
         return;
         
     // This pageRecord has now been fully released.  Do the appropriate cleanup
@@ -498,9 +509,6 @@
     }
     
     delete pageRecord;
-
-    if (isOpen())
-        scheduleOrDeferSyncTimer();
 }
 
 void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal, const String& iconURLOriginal)
@@ -736,6 +744,10 @@
 size_t IconDatabase::retainedPageURLCount()
 {
     MutexLocker locker(m_urlAndIconLock);
+
+    if (m_retainOrReleaseIconRequested)
+        performPendingRetainAndReleaseOperations();
+
     return m_retainedPageURLs.size();
 }
 
@@ -762,6 +774,7 @@
 IconDatabase::IconDatabase()
     : m_syncTimer(this, &IconDatabase::syncTimerFired)
     , m_syncThreadRunning(false)
+    , m_scheduleOrDeferSyncTimerRequested(false)
     , m_isEnabled(false)
     , m_privateBrowsingEnabled(false)
     , m_threadTerminationRequested(false)
@@ -823,17 +836,30 @@
     m_syncCondition.signal();
 }
 
+void IconDatabase::performScheduleOrDeferSyncTimer()
+{
+    m_syncTimer.startOneShot(updateTimerDelay);
+    m_scheduleOrDeferSyncTimerRequested = false;
+}
+
+void IconDatabase::performScheduleOrDeferSyncTimerOnMainThread(void* context)
+{
+    static_cast<IconDatabase*>(context)->performScheduleOrDeferSyncTimer();
+}
+
 void IconDatabase::scheduleOrDeferSyncTimer()
 {
     ASSERT_NOT_SYNC_THREAD();
 
-    if (!m_syncTimer.isActive()) {
-        // The following is balanced by the call to enableSuddenTermination in the
-        // syncTimerFired function.
-        disableSuddenTermination();
-    }
+    if (m_scheduleOrDeferSyncTimerRequested)
+        return;
 
-    m_syncTimer.startOneShot(updateTimerDelay);
+    // The following is balanced by the call to enableSuddenTermination in the
+    // syncTimerFired function.
+    disableSuddenTermination();
+
+    m_scheduleOrDeferSyncTimerRequested = true;
+    callOnMainThread(performScheduleOrDeferSyncTimerOnMainThread, this);
 }
 
 void IconDatabase::syncTimerFired(Timer<IconDatabase>*)
@@ -1306,7 +1332,10 @@
     // Keep a set of ones that are retained and pending notification
     {
         MutexLocker locker(m_urlAndIconLock);
-        
+
+        if (m_retainOrReleaseIconRequested)
+            performPendingRetainAndReleaseOperations();
+
         for (unsigned i = 0; i < urls.size(); ++i) {
             if (!m_retainedPageURLs.contains(urls[i])) {
                 PageURLRecord* record = m_pageURLToRecordMap.get(urls[i]);
@@ -1387,6 +1416,11 @@
         // Then, if the thread should be quitting, quit now!
         if (m_threadTerminationRequested)
             break;
+
+        if (m_retainOrReleaseIconRequested) {
+            MutexLocker locker(m_urlAndIconLock);
+            performPendingRetainAndReleaseOperations();
+        }
         
         bool didAnyWork = true;
         while (didAnyWork) {
@@ -1471,6 +1505,25 @@
     }
 }
 
+void IconDatabase::performPendingRetainAndReleaseOperations()
+{
+    ASSERT(m_retainOrReleaseIconRequested);
+
+    // NOTE: The caller is assumed to hold m_urlAndIconLock.
+    ASSERT(!m_urlAndIconLock.tryLock());
+
+    MutexLocker vectorLocker(m_urlsToRetainOrReleaseLock);
+
+    for (HashCountedSet<String>::const_iterator it = m_urlsToRetain.begin(), end = m_urlsToRetain.end(); it != end; ++it)
+        performRetainIconForPageURL(it->first, it->second);
+    for (HashCountedSet<String>::const_iterator it = m_urlsToRelease.begin(), end = m_urlsToRelease.end(); it != end; ++it)
+        performReleaseIconForPageURL(it->first, it->second);
+
+    m_urlsToRetain.clear();
+    m_urlsToRelease.clear();
+    m_retainOrReleaseIconRequested = false;
+}
+
 bool IconDatabase::readFromDatabase()
 {
     ASSERT_ICON_SYNC_THREAD();

Modified: trunk/Source/WebCore/loader/icon/IconDatabase.h (117500 => 117501)


--- trunk/Source/WebCore/loader/icon/IconDatabase.h	2012-05-17 21:46:02 UTC (rev 117500)
+++ trunk/Source/WebCore/loader/icon/IconDatabase.h	2012-05-17 21:49:43 UTC (rev 117501)
@@ -29,6 +29,7 @@
 
 #include "IconDatabaseBase.h"
 #include "Timer.h"
+#include <wtf/HashCountedSet.h>
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
 #include <wtf/Noncopyable.h>
@@ -135,6 +136,11 @@
 
     RefPtr<IconRecord> m_defaultIconRecord;
 
+    static void performScheduleOrDeferSyncTimerOnMainThread(void*);
+    void performScheduleOrDeferSyncTimer();
+
+    bool m_scheduleOrDeferSyncTimerRequested;
+
 // *** Any Thread ***
 public:
     virtual bool isOpen() const;
@@ -159,6 +165,7 @@
     bool m_iconURLImportComplete;
     bool m_syncThreadHasWorkToDo;
     bool m_disabledSuddenTerminationForSyncThread;
+    bool m_retainOrReleaseIconRequested;
 
     Mutex m_urlAndIconLock;
     // Holding m_urlAndIconLock is required when accessing any of the following data structures or the objects they contain
@@ -177,6 +184,11 @@
     HashSet<String> m_pageURLsInterestedInIcons;
     HashSet<IconRecord*> m_iconsPendingReading;
 
+    Mutex m_urlsToRetainOrReleaseLock;
+    // Holding m_urlsToRetainOrReleaseLock is required when accessing any of the following data structures.
+    HashCountedSet<String> m_urlsToRetain;
+    HashCountedSet<String> m_urlsToRelease;
+
 // *** Sync Thread Only ***
 public:
     // Should be used only on the sync thread and only by the Safari 2 Icons import procedure
@@ -202,6 +214,8 @@
     void removeAllIconsOnThread();
     void deleteAllPreparedStatements();
     void* cleanupSyncThread();
+    void performRetainIconForPageURL(const String&, int retainCount);
+    void performReleaseIconForPageURL(const String&, int releaseCount);
 
     // Record (on disk) whether or not Safari 2-style icons were imported (once per dataabse)
     bool imported();
@@ -220,7 +234,9 @@
     PassRefPtr<SharedBuffer> getImageDataForIconURLFromSQLDatabase(const String& iconURL);
     void removeIconFromSQLDatabase(const String& iconURL);
     void writeIconSnapshotToSQLDatabase(const IconSnapshot&);    
-    
+
+    void performPendingRetainAndReleaseOperations();
+
     // Methods to dispatch client callbacks on the main thread
     void dispatchDidImportIconURLForPageURLOnMainThread(const String&);
     void dispatchDidImportIconDataForPageURLOnMainThread(const String&);

Modified: trunk/Source/WebCore/loader/icon/PageURLRecord.h (117500 => 117501)


--- trunk/Source/WebCore/loader/icon/PageURLRecord.h	2012-05-17 21:46:02 UTC (rev 117500)
+++ trunk/Source/WebCore/loader/icon/PageURLRecord.h	2012-05-17 21:49:43 UTC (rev 117501)
@@ -69,13 +69,19 @@
     PageURLSnapshot snapshot(bool forDeletion = false) const;
 
     // Returns false if the page wasn't retained beforehand, true if the retain count was already 1 or higher
-    inline bool retain() { return m_retainCount++; }
+    bool retain(int count)
+    {
+        bool wasRetained = m_retainCount > 0;
+        m_retainCount += count;
+        return wasRetained;
+    }
 
     // Returns true if the page is still retained after the call.  False if the retain count just dropped to 0
-    inline bool release()
+    bool release(int count)
     {
-        ASSERT(m_retainCount > 0);
-        return --m_retainCount;
+        ASSERT(m_retainCount >= count);
+        m_retainCount -= count;
+        return m_retainCount > 0;
     }
 
     inline int retainCount() const { return m_retainCount; }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to