Index: content/browser/webui/url_data_manager_backend.cc |
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc |
index 747c7e7a7e383bbdca805a967c59456d79514dfb..f600b409bbbb24c010dedae1412bfbd447282e33 100644 |
--- a/content/browser/webui/url_data_manager_backend.cc |
+++ b/content/browser/webui/url_data_manager_backend.cc |
@@ -23,6 +23,7 @@ |
#include "base/strings/string_number_conversions.h" |
#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
+#include "base/threading/worker_pool.h" |
#include "base/trace_event/trace_event.h" |
#include "content/browser/blob_storage/chrome_blob_storage_context.h" |
#include "content/browser/histogram_internals_request_job.h" |
@@ -106,6 +107,20 @@ std::string GetOriginHeaderValue(const net::URLRequest* request) { |
return result; |
} |
+// Copy data from source buffer into IO buffer destination. |
+// TODO(groby): Very similar to URLRequestSimpleJob, unify at some point. |
+void CopyData(const scoped_refptr<net::IOBuffer>& buf, |
+ int buf_size, |
+ const scoped_refptr<base::RefCountedMemory>& data, |
+ int64_t data_offset) { |
+ // TODO(pkasting): Remove ScopedTracker below once crbug.com/455423 is |
+ // fixed. |
+ tracked_objects::ScopedTracker tracking_profile( |
+ FROM_HERE_WITH_EXPLICIT_FUNCTION( |
+ "455423 URLRequestChromeJob::CompleteRead memcpy")); |
+ memcpy(buf->data(), data->front() + data_offset, buf_size); |
+} |
+ |
} // namespace |
// URLRequestChromeJob is a net::URLRequestJob that manages running |
@@ -211,10 +226,9 @@ class URLRequestChromeJob : public net::URLRequestJob { |
static void DelayStartForDevTools( |
const base::WeakPtr<URLRequestChromeJob>& job); |
- // Do the actual copy from data_ (the data we're serving) into |buf|. |
- // Separate from ReadRawData so we can handle async I/O. Returns the number of |
- // bytes read. |
- int CompleteRead(net::IOBuffer* buf, int buf_size); |
+ // Post a task to copy |data_| to |buf_| on a worker thread, to avoid browser |
+ // jank. (|data_| might be mem-mapped, so a memcpy can trigger file ops). |
+ int PostReadTask(scoped_refptr<net::IOBuffer> buf, int buf_size); |
// The actual data we're serving. NULL until it's been fetched. |
scoped_refptr<base::RefCountedMemory> data_; |
@@ -383,17 +397,22 @@ void URLRequestChromeJob::MimeTypeAvailable(const std::string& mime_type) { |
void URLRequestChromeJob::DataAvailable(base::RefCountedMemory* bytes) { |
TRACE_EVENT_ASYNC_END0("browser", "DataManager:Request", this); |
- if (bytes) { |
- data_ = bytes; |
- if (pending_buf_.get()) { |
- CHECK(pending_buf_->data()); |
- int result = CompleteRead(pending_buf_.get(), pending_buf_size_); |
- pending_buf_ = nullptr; |
- ReadRawDataComplete(result); |
- } |
- } else { |
- // The request failed. |
+ DCHECK(!data_); |
+ |
+ // A passed-in nullptr signals an error. |
+ if (!bytes) { |
ReadRawDataComplete(net::ERR_FAILED); |
+ return; |
+ } |
+ |
+ // All further requests will be satisfied from the passed-in data. |
+ data_ = bytes; |
+ |
+ if (pending_buf_) { |
+ int result = PostReadTask(pending_buf_, pending_buf_size_); |
+ pending_buf_ = nullptr; |
+ if (result != net::ERR_IO_PENDING) |
+ ReadRawDataComplete(result); |
} |
} |
@@ -402,32 +421,39 @@ base::WeakPtr<URLRequestChromeJob> URLRequestChromeJob::AsWeakPtr() { |
} |
int URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size) { |
+ DCHECK(!pending_buf_.get()); |
+ |
+ // If data isn't available yet, mark this as asynchronous. |
if (!data_.get()) { |
- DCHECK(!pending_buf_.get()); |
- CHECK(buf->data()); |
pending_buf_ = buf; |
pending_buf_size_ = buf_size; |
return net::ERR_IO_PENDING; |
} |
- // Otherwise, the data is available. |
- return CompleteRead(buf, buf_size); |
+ return PostReadTask(buf, buf_size); |
} |
-int URLRequestChromeJob::CompleteRead(net::IOBuffer* buf, int buf_size) { |
+int URLRequestChromeJob::PostReadTask(scoped_refptr<net::IOBuffer> buf, |
+ int buf_size) { |
+ DCHECK(buf); |
+ DCHECK(data_); |
+ CHECK(buf->data()); |
+ |
int remaining = data_->size() - data_offset_; |
if (buf_size > remaining) |
buf_size = remaining; |
- if (buf_size > 0) { |
- // TODO(pkasting): Remove ScopedTracker below once crbug.com/455423 is |
- // fixed. |
- tracked_objects::ScopedTracker tracking_profile( |
- FROM_HERE_WITH_EXPLICIT_FUNCTION( |
- "455423 URLRequestChromeJob::CompleteRead memcpy")); |
- memcpy(buf->data(), data_->front() + data_offset_, buf_size); |
- data_offset_ += buf_size; |
- } |
- return buf_size; |
+ |
+ if (buf_size == 0) |
+ return 0; |
+ |
+ base::WorkerPool::GetTaskRunner(false)->PostTaskAndReply( |
+ FROM_HERE, base::Bind(&CopyData, base::RetainedRef(buf), buf_size, data_, |
+ data_offset_), |
+ base::Bind(&URLRequestChromeJob::ReadRawDataComplete, AsWeakPtr(), |
+ buf_size)); |
+ data_offset_ += buf_size; |
+ |
+ return net::ERR_IO_PENDING; |
} |
void URLRequestChromeJob::DelayStartForDevTools( |