<!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>[192226] releases/WebKitGTK/webkit-2.10/Source/bmalloc</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/192226">192226</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2015-11-10 03:28:49 -0800 (Tue, 10 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/191741">r191741</a> - bmalloc: AsyncTask should handle destruction
https://bugs.webkit.org/show_bug.cgi?id=150648

Reviewed by Mark Lam.

So we can use it in more places.

* bmalloc/AsyncTask.h: Use std::thread instead of pthread because it
should be more portable.

(bmalloc::Function&gt;::AsyncTask): Renamed Signaled to RunRequested for
clarity. Added an ExitRequested state.

(bmalloc::Function&gt;::~AsyncTask): Wait for our child thread to exit
before destroying ourselves because our child thread will modify our
data (and might modify our client's data). Note that we only need to
wait for the last child thread since any prior child thread, having
reached the Exited condition, is guaranteed not to read or write any
data.

(bmalloc::Function&gt;::run):
(bmalloc::Function&gt;::runSlowCase): Updated for interface changes. Also
changed to use our WebKit style for condition signal: Hold the lock
during the signal and always notify all. Technically, neither is necessary,
but it is easier to understand the code this way, and harder to make
mistakes.

(bmalloc::Function&gt;::threadEntryPoint):
(bmalloc::Function&gt;::threadRunLoop): Handle the new ExitRequested state.
Technically, this state has no meaningful difference from the Exited
state, but it is nice to be explicit.

(bmalloc::Function&gt;::join): Deleted.
(bmalloc::Function&gt;::pthreadEntryPoint): Deleted.
(bmalloc::Function&gt;::entryPoint): Deleted.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit210SourcebmallocChangeLog">releases/WebKitGTK/webkit-2.10/Source/bmalloc/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit210SourcebmallocbmallocAsyncTaskh">releases/WebKitGTK/webkit-2.10/Source/bmalloc/bmalloc/AsyncTask.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="releasesWebKitGTKwebkit210SourcebmallocChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.10/Source/bmalloc/ChangeLog (192225 => 192226)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.10/Source/bmalloc/ChangeLog        2015-11-10 11:27:32 UTC (rev 192225)
+++ releases/WebKitGTK/webkit-2.10/Source/bmalloc/ChangeLog        2015-11-10 11:28:49 UTC (rev 192226)
</span><span class="lines">@@ -1,3 +1,41 @@
</span><ins>+2015-10-29  Geoffrey Garen  &lt;ggaren@apple.com&gt;
+
+        bmalloc: AsyncTask should handle destruction
+        https://bugs.webkit.org/show_bug.cgi?id=150648
+
+        Reviewed by Mark Lam.
+
+        So we can use it in more places.
+
+        * bmalloc/AsyncTask.h: Use std::thread instead of pthread because it
+        should be more portable.
+
+        (bmalloc::Function&gt;::AsyncTask): Renamed Signaled to RunRequested for
+        clarity. Added an ExitRequested state.
+
+        (bmalloc::Function&gt;::~AsyncTask): Wait for our child thread to exit
+        before destroying ourselves because our child thread will modify our
+        data (and might modify our client's data). Note that we only need to
+        wait for the last child thread since any prior child thread, having
+        reached the Exited condition, is guaranteed not to read or write any
+        data.
+
+        (bmalloc::Function&gt;::run):
+        (bmalloc::Function&gt;::runSlowCase): Updated for interface changes. Also
+        changed to use our WebKit style for condition signal: Hold the lock
+        during the signal and always notify all. Technically, neither is necessary,
+        but it is easier to understand the code this way, and harder to make
+        mistakes.
+
+        (bmalloc::Function&gt;::threadEntryPoint):
+        (bmalloc::Function&gt;::threadRunLoop): Handle the new ExitRequested state.
+        Technically, this state has no meaningful difference from the Exited
+        state, but it is nice to be explicit.
+
+        (bmalloc::Function&gt;::join): Deleted.
+        (bmalloc::Function&gt;::pthreadEntryPoint): Deleted.
+        (bmalloc::Function&gt;::entryPoint): Deleted.
+
</ins><span class="cx"> 2015-10-15  Geoffrey Garen  &lt;ggaren@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         bmalloc: per-thread cache data structure should be smaller
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit210SourcebmallocbmallocAsyncTaskh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.10/Source/bmalloc/bmalloc/AsyncTask.h (192225 => 192226)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.10/Source/bmalloc/bmalloc/AsyncTask.h        2015-11-10 11:27:32 UTC (rev 192225)
+++ releases/WebKitGTK/webkit-2.10/Source/bmalloc/bmalloc/AsyncTask.h        2015-11-10 11:28:49 UTC (rev 192226)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -31,7 +31,6 @@
</span><span class="cx"> #include &quot;Mutex.h&quot;
</span><span class="cx"> #include &lt;atomic&gt;
</span><span class="cx"> #include &lt;condition_variable&gt;
</span><del>-#include &lt;pthread.h&gt;
</del><span class="cx"> #include &lt;thread&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace bmalloc {
</span><span class="lines">@@ -40,26 +39,27 @@
</span><span class="cx"> class AsyncTask {
</span><span class="cx"> public:
</span><span class="cx">     AsyncTask(Object&amp;, const Function&amp;);
</span><ins>+    ~AsyncTask();
</ins><span class="cx"> 
</span><span class="cx">     void run();
</span><del>-    void join();
</del><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    enum State { Exited, Sleeping, Running, Signaled };
</del><ins>+    enum State { Exited, ExitRequested, Sleeping, Running, RunRequested };
</ins><span class="cx"> 
</span><span class="cx">     static const constexpr std::chrono::seconds exitDelay = std::chrono::seconds(1);
</span><span class="cx"> 
</span><span class="cx">     void runSlowCase();
</span><span class="cx"> 
</span><del>-    static void* pthreadEntryPoint(void*);
-    void entryPoint();
</del><ins>+    static void threadEntryPoint(AsyncTask*);
+    void threadRunLoop();
</ins><span class="cx"> 
</span><span class="cx">     std::atomic&lt;State&gt; m_state;
</span><span class="cx"> 
</span><span class="cx">     Mutex m_conditionMutex;
</span><span class="cx">     std::condition_variable_any m_condition;
</span><del>-    pthread_t m_thread;
</del><span class="cx"> 
</span><ins>+    std::thread m_thread;
+
</ins><span class="cx">     Object&amp; m_object;
</span><span class="cx">     Function m_function;
</span><span class="cx"> };
</span><span class="lines">@@ -77,22 +77,27 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename Object, typename Function&gt;
</span><del>-void AsyncTask&lt;Object, Function&gt;::join()
</del><ins>+AsyncTask&lt;Object, Function&gt;::~AsyncTask()
</ins><span class="cx"> {
</span><del>-    if (m_state == Exited)
-        return;
</del><ins>+    // Prevent our thread from entering the running or sleeping state.
+    State oldState = m_state.exchange(ExitRequested);
</ins><span class="cx"> 
</span><del>-    { std::lock_guard&lt;Mutex&gt; lock(m_conditionMutex); }
-    m_condition.notify_one();
</del><ins>+    // Wake our thread if it was already in the sleeping state.
+    if (oldState == Sleeping) {
+        std::lock_guard&lt;Mutex&gt; lock(m_conditionMutex);
+        m_condition.notify_all();
+    }
</ins><span class="cx"> 
</span><del>-    while (m_state != Exited)
-        std::this_thread::yield();
</del><ins>+    // Wait for our thread to exit because it uses our data members (and it may
+    // use m_object's data members).
+    if (m_thread.joinable())
+        m_thread.join();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename Object, typename Function&gt;
</span><span class="cx"> inline void AsyncTask&lt;Object, Function&gt;::run()
</span><span class="cx"> {
</span><del>-    if (m_state == Signaled)
</del><ins>+    if (m_state == RunRequested)
</ins><span class="cx">         return;
</span><span class="cx">     runSlowCase();
</span><span class="cx"> }
</span><span class="lines">@@ -100,33 +105,40 @@
</span><span class="cx"> template&lt;typename Object, typename Function&gt;
</span><span class="cx"> NO_INLINE void AsyncTask&lt;Object, Function&gt;::runSlowCase()
</span><span class="cx"> {
</span><del>-    State oldState = m_state.exchange(Signaled);
-    if (oldState == Signaled || oldState == Running)
</del><ins>+    State oldState = m_state.exchange(RunRequested);
+    if (oldState == RunRequested || oldState == Running)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     if (oldState == Sleeping) {
</span><del>-        { std::lock_guard&lt;Mutex&gt; lock(m_conditionMutex); }
-        m_condition.notify_one();
</del><ins>+        std::lock_guard&lt;Mutex&gt; lock(m_conditionMutex);
+        m_condition.notify_all();
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     BASSERT(oldState == Exited);
</span><del>-    pthread_create(&amp;m_thread, nullptr, &amp;pthreadEntryPoint, this);
-    pthread_detach(m_thread);
</del><ins>+    if (m_thread.joinable())
+        m_thread.detach();
+    m_thread = std::thread(&amp;AsyncTask::threadEntryPoint, this);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename Object, typename Function&gt;
</span><del>-void* AsyncTask&lt;Object, Function&gt;::pthreadEntryPoint(void* asyncTask)
</del><ins>+void AsyncTask&lt;Object, Function&gt;::threadEntryPoint(AsyncTask* asyncTask)
</ins><span class="cx"> {
</span><del>-    static_cast&lt;AsyncTask*&gt;(asyncTask)-&gt;entryPoint();
-    return nullptr;
</del><ins>+    asyncTask-&gt;threadRunLoop();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename Object, typename Function&gt;
</span><del>-void AsyncTask&lt;Object, Function&gt;::entryPoint()
</del><ins>+void AsyncTask&lt;Object, Function&gt;::threadRunLoop()
</ins><span class="cx"> {
</span><ins>+    // This loop ratchets downward from most active to least active state, and
+    // finally exits. While we ratchet downward, any other thread may reset our
+    // state to RunRequested or ExitRequested.
+    
+    // We require any state change while we are sleeping to signal to our
+    // condition variable and wake us up.
+
</ins><span class="cx">     while (1) {
</span><del>-        State expectedState = Signaled;
</del><ins>+        State expectedState = RunRequested;
</ins><span class="cx">         if (m_state.compare_exchange_weak(expectedState, Running))
</span><span class="cx">             (m_object.*m_function)();
</span><span class="cx"> 
</span><span class="lines">@@ -139,6 +151,10 @@
</span><span class="cx">         expectedState = Sleeping;
</span><span class="cx">         if (m_state.compare_exchange_weak(expectedState, Exited))
</span><span class="cx">             return;
</span><ins>+        
+        expectedState = ExitRequested;
+        if (m_state.compare_exchange_weak(expectedState, Exited))
+            return;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>