<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[168918] trunk/Source/WebKit2</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/168918">168918</a></dd>
<dt>Author</dt> <dd>mrowe@apple.com</dd>
<dt>Date</dt> <dd>2014-05-15 17:11:39 -0700 (Thu, 15 May 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>&lt;https://webkit.org/b/132976&gt; Move discovery of sharing services off the main thread

Discovery of sharing services can require disk access and IPC. Since the interface to
ServicesController is already asynchronous, we can easily perform the discovery on a
background queue. This can eliminate tens to hundreds of milliseconds worth of work
from the main thread when creating the first web process.

Reviewed by Brady Eidson.

* UIProcess/mac/ServicesController.h:
* UIProcess/mac/ServicesController.mm:
(WebKit::ServicesController::ServicesController):
(WebKit::ServicesController::refreshExistingServices): Bail out early if we're already
in the process of refreshing the services. Kick the discovery over to a background queue,
with it hopping back to the main queue to update the actual state and notify any contexts
that were interested.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessmacServicesControllerh">trunk/Source/WebKit2/UIProcess/mac/ServicesController.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessmacServicesControllermm">trunk/Source/WebKit2/UIProcess/mac/ServicesController.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (168917 => 168918)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-05-16 00:02:53 UTC (rev 168917)
+++ trunk/Source/WebKit2/ChangeLog        2014-05-16 00:11:39 UTC (rev 168918)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2014-05-15  Mark Rowe  &lt;mrowe@apple.com&gt;
+
+        &lt;https://webkit.org/b/132976&gt; Move discovery of sharing services off the main thread
+
+        Discovery of sharing services can require disk access and IPC. Since the interface to
+        ServicesController is already asynchronous, we can easily perform the discovery on a
+        background queue. This can eliminate tens to hundreds of milliseconds worth of work
+        from the main thread when creating the first web process.
+
+        Reviewed by Brady Eidson.
+
+        * UIProcess/mac/ServicesController.h:
+        * UIProcess/mac/ServicesController.mm:
+        (WebKit::ServicesController::ServicesController):
+        (WebKit::ServicesController::refreshExistingServices): Bail out early if we're already
+        in the process of refreshing the services. Kick the discovery over to a background queue,
+        with it hopping back to the main queue to update the actual state and notify any contexts
+        that were interested.
+
</ins><span class="cx"> 2014-05-15  Dan Bernstein  &lt;mitz@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fixed a typo in a comment and updated previous change log entry.
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessmacServicesControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/mac/ServicesController.h (168917 => 168918)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/mac/ServicesController.h        2014-05-16 00:02:53 UTC (rev 168917)
+++ trunk/Source/WebKit2/UIProcess/mac/ServicesController.h        2014-05-16 00:11:39 UTC (rev 168918)
</span><span class="lines">@@ -51,9 +51,10 @@
</span><span class="cx"> private:
</span><span class="cx">     ServicesController();
</span><span class="cx"> 
</span><del>-    void refreshExistingServicesTimerFired();
</del><ins>+    void refreshExistingServices();
</ins><span class="cx"> 
</span><del>-    RunLoop::Timer&lt;ServicesController&gt; m_refreshExistingServicesTimer;
</del><ins>+    dispatch_queue_t m_refreshQueue;
+    bool m_isRefreshing;
</ins><span class="cx"> 
</span><span class="cx">     bool m_hasImageServices;
</span><span class="cx">     bool m_hasSelectionServices;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessmacServicesControllermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/mac/ServicesController.mm (168917 => 168918)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/mac/ServicesController.mm        2014-05-16 00:02:53 UTC (rev 168917)
+++ trunk/Source/WebKit2/UIProcess/mac/ServicesController.mm        2014-05-16 00:11:39 UTC (rev 168918)
</span><span class="lines">@@ -57,45 +57,57 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ServicesController::ServicesController()
</span><del>-    : m_refreshExistingServicesTimer(RunLoop::main(), this, &amp;ServicesController::refreshExistingServicesTimerFired)
</del><ins>+    : m_refreshQueue(dispatch_queue_create(&quot;com.apple.WebKit.ServicesController&quot;, DISPATCH_QUEUE_SERIAL))
+    , m_isRefreshing(false)
</ins><span class="cx">     , m_hasImageServices(false)
</span><span class="cx">     , m_hasSelectionServices(false)
</span><span class="cx"> {
</span><del>-    m_refreshExistingServicesTimer.startOneShot(0);
</del><ins>+    refreshExistingServices();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ServicesController::refreshExistingServices(WebContext* context)
</span><span class="cx"> {
</span><del>-    ASSERT(context);
</del><ins>+    ASSERT_ARG(context, context);
+    ASSERT([NSThread isMainThread]);
</ins><span class="cx"> 
</span><span class="cx">     m_contextsToNotify.add(context);
</span><del>-    m_refreshExistingServicesTimer.startOneShot(0);
</del><ins>+    refreshExistingServices();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesController::refreshExistingServicesTimerFired()
</del><ins>+void ServicesController::refreshExistingServices()
</ins><span class="cx"> {
</span><del>-    static NeverDestroyed&lt;NSImage *&gt; image([[NSImage alloc] init]);
-    RetainPtr&lt;NSSharingServicePicker&gt;  picker = adoptNS([[NSSharingServicePicker alloc] initWithItems:@[ image ]]);
-    [picker setStyle:NSSharingServicePickerStyleRollover];
</del><ins>+    if (m_isRefreshing)
+        return;
</ins><span class="cx"> 
</span><del>-    bool hasImageServices = picker.get().menu;
</del><ins>+    m_isRefreshing = true;
+    dispatch_async(m_refreshQueue, ^{
+        static NeverDestroyed&lt;NSImage *&gt; image([[NSImage alloc] init]);
+        RetainPtr&lt;NSSharingServicePicker&gt;  picker = adoptNS([[NSSharingServicePicker alloc] initWithItems:@[ image ]]);
+        [picker setStyle:NSSharingServicePickerStyleRollover];
</ins><span class="cx"> 
</span><del>-    static NeverDestroyed&lt;NSAttributedString *&gt; attributedString([[NSAttributedString alloc] initWithString:@&quot;a&quot;]);
-    picker = adoptNS([[NSSharingServicePicker alloc] initWithItems:@[ attributedString ]]);
-    [picker setStyle:NSSharingServicePickerStyleTextSelection];
</del><ins>+        bool hasImageServices = picker.get().menu;
</ins><span class="cx"> 
</span><del>-    bool hasSelectionServices = picker.get().menu;
</del><ins>+        static NeverDestroyed&lt;NSAttributedString *&gt; attributedString([[NSAttributedString alloc] initWithString:@&quot;a&quot;]);
+        picker = adoptNS([[NSSharingServicePicker alloc] initWithItems:@[ attributedString ]]);
+        [picker setStyle:NSSharingServicePickerStyleTextSelection];
</ins><span class="cx"> 
</span><del>-    bool notifyContexts = (hasImageServices != m_hasImageServices) || (hasSelectionServices != m_hasSelectionServices);
-    m_hasSelectionServices = hasSelectionServices;
-    m_hasImageServices = hasImageServices;
</del><ins>+        bool hasSelectionServices = picker.get().menu;
</ins><span class="cx"> 
</span><del>-    if (notifyContexts) {
-        for (const RefPtr&lt;WebContext&gt;&amp; context : m_contextsToNotify)
-            context-&gt;sendToAllProcesses(Messages::WebProcess::SetEnabledServices(m_hasImageServices, m_hasSelectionServices));
-    }
</del><ins>+        dispatch_async(dispatch_get_main_queue(), ^{
+            bool notifyContexts = (hasImageServices != m_hasImageServices) || (hasSelectionServices != m_hasSelectionServices);
+            m_hasSelectionServices = hasSelectionServices;
+            m_hasImageServices = hasImageServices;
</ins><span class="cx"> 
</span><del>-    m_contextsToNotify.clear();
</del><ins>+            if (notifyContexts) {
+                for (const RefPtr&lt;WebContext&gt;&amp; context : m_contextsToNotify)
+                    context-&gt;sendToAllProcesses(Messages::WebProcess::SetEnabledServices(m_hasImageServices, m_hasSelectionServices));
+            }
+
+            m_contextsToNotify.clear();
+
+            m_isRefreshing = false;
+        });
+    });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre>
</div>
</div>

</body>
</html>