<!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>[183273] 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/183273">183273</a></dd>
<dt>Author</dt> <dd>antti@apple.com</dd>
<dt>Date</dt> <dd>2015-04-24 11:57:25 -0700 (Fri, 24 Apr 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>CrashTracer: [USER] com.apple.WebKit.Networking at com.apple.WebKit: WebKit::NetworkResourceLoader::~NetworkResourceLoader + 14
https://bugs.webkit.org/show_bug.cgi?id=144147
Reviewed by Chris Dumez.
Storage::storeBodyAsBlob copies the std::function callback for handling mapped bodies in a thread.
This is thread safe only if the function copy is thread safe. It is currently not as we are capturing
RefPtr<NetworkResourceLoader> and NetworkResourceLoader doesn't use thread safe refcounting.
Fix by avoiding copying of the callback. Use same apporach for WriteOperation as we already use for
ReadOperation: count the active operations in progress and delete WriteOperation when everything is
finished. This way we don't need to copy the function out from WriteOperation.
* NetworkProcess/cache/NetworkCacheStorage.cpp:
(WebKit::NetworkCache::Storage::ReadOperation::ReadOperation):
(WebKit::NetworkCache::Storage::WriteOperation::WriteOperation):
Move definition here from the header.
(WebKit::NetworkCache::Storage::~Storage):
(WebKit::NetworkCache::Storage::storeBodyAsBlob):
Increment the operation count when storing a blob, call finishWriteOperation when done.
(WebKit::NetworkCache::Storage::dispatchReadOperation):
(WebKit::NetworkCache::Storage::finishReadOperation):
Count active operations instead of finished operations. This makes the code clearer.
(WebKit::NetworkCache::Storage::dispatchWriteOperation):
(WebKit::NetworkCache::Storage::finishWriteOperation):
Mirror the way ReadOperations work.
* NetworkProcess/cache/NetworkCacheStorage.h:
(WebKit::NetworkCache::Storage::ReadOperation::ReadOperation): Deleted.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStoragecpp">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (183272 => 183273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog 2015-04-24 18:55:26 UTC (rev 183272)
+++ trunk/Source/WebKit2/ChangeLog 2015-04-24 18:57:25 UTC (rev 183273)
</span><span class="lines">@@ -1,3 +1,42 @@
</span><ins>+2015-04-24 Antti Koivisto <antti@apple.com>
+
+ CrashTracer: [USER] com.apple.WebKit.Networking at com.apple.WebKit: WebKit::NetworkResourceLoader::~NetworkResourceLoader + 14
+ https://bugs.webkit.org/show_bug.cgi?id=144147
+
+ Reviewed by Chris Dumez.
+
+ Storage::storeBodyAsBlob copies the std::function callback for handling mapped bodies in a thread.
+ This is thread safe only if the function copy is thread safe. It is currently not as we are capturing
+ RefPtr<NetworkResourceLoader> and NetworkResourceLoader doesn't use thread safe refcounting.
+
+ Fix by avoiding copying of the callback. Use same apporach for WriteOperation as we already use for
+ ReadOperation: count the active operations in progress and delete WriteOperation when everything is
+ finished. This way we don't need to copy the function out from WriteOperation.
+
+ * NetworkProcess/cache/NetworkCacheStorage.cpp:
+ (WebKit::NetworkCache::Storage::ReadOperation::ReadOperation):
+ (WebKit::NetworkCache::Storage::WriteOperation::WriteOperation):
+
+ Move definition here from the header.
+
+ (WebKit::NetworkCache::Storage::~Storage):
+ (WebKit::NetworkCache::Storage::storeBodyAsBlob):
+
+ Increment the operation count when storing a blob, call finishWriteOperation when done.
+
+ (WebKit::NetworkCache::Storage::dispatchReadOperation):
+ (WebKit::NetworkCache::Storage::finishReadOperation):
+
+ Count active operations instead of finished operations. This makes the code clearer.
+
+ (WebKit::NetworkCache::Storage::dispatchWriteOperation):
+ (WebKit::NetworkCache::Storage::finishWriteOperation):
+
+ Mirror the way ReadOperations work.
+
+ * NetworkProcess/cache/NetworkCacheStorage.h:
+ (WebKit::NetworkCache::Storage::ReadOperation::ReadOperation): Deleted.
+
</ins><span class="cx"> 2015-04-24 Timothy Hatcher <timothy@apple.com>
</span><span class="cx">
</span><span class="cx"> REGRESSION: Web Inspector: Start Timeline Recording in Develop menu broken
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStoragecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp (183272 => 183273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp 2015-04-24 18:55:26 UTC (rev 183272)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp 2015-04-24 18:57:25 UTC (rev 183273)
</span><span class="lines">@@ -49,6 +49,32 @@
</span><span class="cx">
</span><span class="cx"> static double computeRecordWorth(FileTimes);
</span><span class="cx">
</span><ins>+struct Storage::ReadOperation {
+ ReadOperation(const Key& key, const RetrieveCompletionHandler& completionHandler)
+ : key(key)
+ , completionHandler(completionHandler)
+ { }
+
+ const Key key;
+ const RetrieveCompletionHandler completionHandler;
+
+ std::unique_ptr<Record> resultRecord;
+ SHA1::Digest expectedBodyHash;
+ BlobStorage::Blob resultBodyBlob;
+ std::atomic<unsigned> activeCount { 0 };
+};
+
+struct Storage::WriteOperation {
+ WriteOperation(const Record& record, const MappedBodyHandler& mappedBodyHandler)
+ : record(record)
+ , mappedBodyHandler(mappedBodyHandler)
+ { }
+
+ Record record;
+ MappedBodyHandler mappedBodyHandler;
+ std::atomic<unsigned> activeCount { 0 };
+};
+
</ins><span class="cx"> std::unique_ptr<Storage> Storage::open(const String& cachePath)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(RunLoop::isMain());
</span><span class="lines">@@ -87,6 +113,9 @@
</span><span class="cx"> synchronize();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+Storage::~Storage()
+{
+}
</ins><span class="cx">
</span><span class="cx"> String Storage::basePath() const
</span><span class="cx"> {
</span><span class="lines">@@ -351,25 +380,27 @@
</span><span class="cx"> return Data(encoder.buffer(), encoder.bufferSize());
</span><span class="cx"> }
</span><span class="cx">
</span><del>-Optional<BlobStorage::Blob> Storage::storeBodyAsBlob(const Record& record, const MappedBodyHandler& mappedBodyHandler)
</del><ins>+Optional<BlobStorage::Blob> Storage::storeBodyAsBlob(WriteOperation& writeOperation)
</ins><span class="cx"> {
</span><del>- auto bodyPath = bodyPathForKey(record.key);
</del><ins>+ auto bodyPath = bodyPathForKey(writeOperation.record.key);
</ins><span class="cx">
</span><span class="cx"> // Store the body.
</span><del>- auto blob = m_blobStorage.add(bodyPath, record.body);
</del><ins>+ auto blob = m_blobStorage.add(bodyPath, writeOperation.record.body);
</ins><span class="cx"> if (blob.data.isNull())
</span><span class="cx"> return { };
</span><span class="cx">
</span><del>- auto hash = record.key.hash();
- RunLoop::main().dispatch([this, blob, hash, mappedBodyHandler] {
</del><ins>+ ++writeOperation.activeCount;
+
+ RunLoop::main().dispatch([this, blob, &writeOperation] {
</ins><span class="cx"> if (m_bodyFilter)
</span><del>- m_bodyFilter->add(hash);
</del><ins>+ m_bodyFilter->add(writeOperation.record.key.hash());
</ins><span class="cx"> if (m_synchronizationInProgress)
</span><del>- m_bodyFilterHashesAddedDuringSynchronization.append(hash);
</del><ins>+ m_bodyFilterHashesAddedDuringSynchronization.append(writeOperation.record.key.hash());
</ins><span class="cx">
</span><del>- if (mappedBodyHandler)
- mappedBodyHandler(blob.data);
</del><ins>+ if (writeOperation.mappedBodyHandler)
+ writeOperation.mappedBodyHandler(blob.data);
</ins><span class="cx">
</span><ins>+ finishWriteOperation(writeOperation);
</ins><span class="cx"> });
</span><span class="cx"> return blob;
</span><span class="cx"> }
</span><span class="lines">@@ -424,6 +455,12 @@
</span><span class="cx">
</span><span class="cx"> auto recordPath = recordPathForKey(readOperation.key);
</span><span class="cx">
</span><ins>+ ++readOperation.activeCount;
+
+ bool shouldGetBodyBlob = !m_bodyFilter || m_bodyFilter->mayContain(readOperation.key.hash());
+ if (shouldGetBodyBlob)
+ ++readOperation.activeCount;
+
</ins><span class="cx"> RefPtr<IOChannel> channel = IOChannel::open(recordPath, IOChannel::Type::Read);
</span><span class="cx"> channel->read(0, std::numeric_limits<size_t>::max(), &ioQueue(), [this, &readOperation](const Data& fileData, int error) {
</span><span class="cx"> if (!error)
</span><span class="lines">@@ -431,11 +468,8 @@
</span><span class="cx"> finishReadOperation(readOperation);
</span><span class="cx"> });
</span><span class="cx">
</span><del>- bool shouldGetBodyBlob = !m_bodyFilter || m_bodyFilter->mayContain(readOperation.key.hash());
- if (!shouldGetBodyBlob) {
- finishReadOperation(readOperation);
</del><ins>+ if (!shouldGetBodyBlob)
</ins><span class="cx"> return;
</span><del>- }
</del><span class="cx">
</span><span class="cx"> // Read the body blob in parallel with the record read.
</span><span class="cx"> ioQueue().dispatch([this, &readOperation] {
</span><span class="lines">@@ -447,9 +481,9 @@
</span><span class="cx">
</span><span class="cx"> void Storage::finishReadOperation(ReadOperation& readOperation)
</span><span class="cx"> {
</span><ins>+ ASSERT(readOperation.activeCount);
</ins><span class="cx"> // Record and body blob reads must finish.
</span><del>- bool isComplete = ++readOperation.finishedCount == 2;
- if (!isComplete)
</del><ins>+ if (--readOperation.activeCount)
</ins><span class="cx"> return;
</span><span class="cx">
</span><span class="cx"> RunLoop::main().dispatch([this, &readOperation] {
</span><span class="lines">@@ -534,7 +568,7 @@
</span><span class="cx"> return bodyData.size() > maximumInlineBodySize;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void Storage::dispatchWriteOperation(const WriteOperation& writeOperation)
</del><ins>+void Storage::dispatchWriteOperation(WriteOperation& writeOperation)
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(RunLoop::isMain());
</span><span class="cx"> ASSERT(m_activeWriteOperations.contains(&writeOperation));
</span><span class="lines">@@ -548,8 +582,10 @@
</span><span class="cx">
</span><span class="cx"> WebCore::makeAllDirectories(partitionPath);
</span><span class="cx">
</span><ins>+ ++writeOperation.activeCount;
+
</ins><span class="cx"> bool shouldStoreAsBlob = shouldStoreBodyAsBlob(writeOperation.record.body);
</span><del>- auto bodyBlob = shouldStoreAsBlob ? storeBodyAsBlob(writeOperation.record, writeOperation.mappedBodyHandler) : Nullopt;
</del><ins>+ auto bodyBlob = shouldStoreAsBlob ? storeBodyAsBlob(writeOperation) : Nullopt;
</ins><span class="cx">
</span><span class="cx"> auto recordData = encodeRecord(writeOperation.record, bodyBlob);
</span><span class="cx">
</span><span class="lines">@@ -565,9 +601,15 @@
</span><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void Storage::finishWriteOperation(const WriteOperation& writeOperation)
</del><ins>+void Storage::finishWriteOperation(WriteOperation& writeOperation)
</ins><span class="cx"> {
</span><ins>+ ASSERT(RunLoop::isMain());
+ ASSERT(writeOperation.activeCount);
</ins><span class="cx"> ASSERT(m_activeWriteOperations.contains(&writeOperation));
</span><ins>+
+ if (--writeOperation.activeCount)
+ return;
+
</ins><span class="cx"> m_activeWriteOperations.remove(&writeOperation);
</span><span class="cx"> dispatchPendingWriteOperations();
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h (183272 => 183273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h 2015-04-24 18:55:26 UTC (rev 183272)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h 2015-04-24 18:57:25 UTC (rev 183273)
</span><span class="lines">@@ -87,6 +87,8 @@
</span><span class="cx"> String versionPath() const;
</span><span class="cx"> String recordsPath() const;
</span><span class="cx">
</span><ins>+ ~Storage();
+
</ins><span class="cx"> private:
</span><span class="cx"> Storage(const String& directoryPath);
</span><span class="cx">
</span><span class="lines">@@ -99,33 +101,17 @@
</span><span class="cx"> void shrinkIfNeeded();
</span><span class="cx"> void shrink();
</span><span class="cx">
</span><del>- struct ReadOperation {
- ReadOperation(const Key& key, const RetrieveCompletionHandler& completionHandler)
- : key(key)
- , completionHandler(completionHandler)
- { }
-
- const Key key;
- const RetrieveCompletionHandler completionHandler;
-
- std::unique_ptr<Record> resultRecord;
- SHA1::Digest expectedBodyHash;
- BlobStorage::Blob resultBodyBlob;
- std::atomic<unsigned> finishedCount { 0 };
- };
</del><ins>+ struct ReadOperation;
</ins><span class="cx"> void dispatchReadOperation(ReadOperation&);
</span><span class="cx"> void dispatchPendingReadOperations();
</span><span class="cx"> void finishReadOperation(ReadOperation&);
</span><span class="cx">
</span><del>- struct WriteOperation {
- Record record;
- MappedBodyHandler mappedBodyHandler;
- };
- void dispatchWriteOperation(const WriteOperation&);
</del><ins>+ struct WriteOperation;
+ void dispatchWriteOperation(WriteOperation&);
</ins><span class="cx"> void dispatchPendingWriteOperations();
</span><del>- void finishWriteOperation(const WriteOperation&);
</del><ins>+ void finishWriteOperation(WriteOperation&);
</ins><span class="cx">
</span><del>- Optional<BlobStorage::Blob> storeBodyAsBlob(const Record&, const MappedBodyHandler&);
</del><ins>+ Optional<BlobStorage::Blob> storeBodyAsBlob(WriteOperation&);
</ins><span class="cx"> Data encodeRecord(const Record&, Optional<BlobStorage::Blob>);
</span><span class="cx"> void readRecord(ReadOperation&, const Data&);
</span><span class="cx">
</span><span class="lines">@@ -160,8 +146,8 @@
</span><span class="cx"> Deque<std::unique_ptr<ReadOperation>> m_pendingReadOperationsByPriority[maximumRetrievePriority + 1];
</span><span class="cx"> HashSet<std::unique_ptr<ReadOperation>> m_activeReadOperations;
</span><span class="cx">
</span><del>- Deque<std::unique_ptr<const WriteOperation>> m_pendingWriteOperations;
- HashSet<std::unique_ptr<const WriteOperation>> m_activeWriteOperations;
</del><ins>+ Deque<std::unique_ptr<WriteOperation>> m_pendingWriteOperations;
+ HashSet<std::unique_ptr<WriteOperation>> m_activeWriteOperations;
</ins><span class="cx">
</span><span class="cx"> Ref<WorkQueue> m_ioQueue;
</span><span class="cx"> Ref<WorkQueue> m_backgroundIOQueue;
</span></span></pre>
</div>
</div>
</body>
</html>