Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4083)

Unified Diff: components/webdata/common/web_data_request_manager.cc

Issue 2571923002: Fix threading issues in WebDataRequestManager. (Closed)
Patch Set: Simplify handling of result and add request factory func Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/webdata/common/web_data_request_manager.cc
diff --git a/components/webdata/common/web_data_request_manager.cc b/components/webdata/common/web_data_request_manager.cc
index d8a271d4a8b26f9bb1c3135127e37d17ea3c3adb..59901e208ce54db2c9f60f3eb363e36ea33f9a48 100644
--- a/components/webdata/common/web_data_request_manager.cc
+++ b/components/webdata/common/web_data_request_manager.cc
@@ -18,12 +18,13 @@
//
////////////////////////////////////////////////////////////////////////////////
-WebDataRequest::WebDataRequest(WebDataServiceConsumer* consumer,
- WebDataRequestManager* manager)
- : manager_(manager), cancelled_(false), consumer_(consumer) {
- handle_ = manager_->GetNextRequestHandle();
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
- manager_->RegisterRequest(this);
+WebDataRequest::WebDataRequest(WebDataRequestManager* manager,
Peter Kasting 2016/12/15 01:05:34 Nit: While here, maybe fix function definition ord
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
+ WebDataServiceConsumer* consumer)
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ manager_(manager),
+ consumer_(consumer),
+ handle_(0) {
+ DCHECK(manager_ != nullptr);
Peter Kasting 2016/12/15 01:05:34 Nit: DCHECK(IsActive())?
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
}
WebDataRequest::~WebDataRequest() {
@@ -36,7 +37,20 @@ WebDataServiceBase::Handle WebDataRequest::GetHandle() const {
return handle_;
}
+bool WebDataRequest::IsActive() const {
+ return manager_ != nullptr;
+}
+
+inline void WebDataRequest::AssertThreadSafe() const {
Peter Kasting 2016/12/15 01:05:34 Nit: Remove "inline" (doesn't match class declarat
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
+ // Manipulations of the request state should only happen when the request is
+ // active (i.e., the manager is non-null) and the manager's lock is held
Peter Kasting 2016/12/15 01:05:34 Nit: Remove "(i.e., the manager is non-null)" and
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
+ // (i.e., during request cancellation or completion).
+ DCHECK(manager_ != nullptr);
+ manager_->AssertLockedByCurrentThread();
+}
+
WebDataServiceConsumer* WebDataRequest::GetConsumer() const {
+ AssertThreadSafe();
return consumer_;
}
@@ -45,28 +59,10 @@ scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner()
return task_runner_;
}
-bool WebDataRequest::IsCancelled() const {
- base::AutoLock l(cancel_lock_);
- return cancelled_;
-}
-
-void WebDataRequest::Cancel() {
- base::AutoLock l(cancel_lock_);
- cancelled_ = true;
- consumer_ = NULL;
- manager_ = NULL;
-}
-
-void WebDataRequest::OnComplete() {
- manager_= NULL;
-}
-
-void WebDataRequest::SetResult(std::unique_ptr<WDTypedResult> r) {
- result_ = std::move(r);
-}
-
-std::unique_ptr<WDTypedResult> WebDataRequest::GetResult() {
- return std::move(result_);
+void WebDataRequest::MarkAsInactive() {
+ AssertThreadSafe();
+ consumer_ = nullptr;
+ manager_ = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
@@ -82,71 +78,98 @@ WebDataRequestManager::WebDataRequestManager()
WebDataRequestManager::~WebDataRequestManager() {
base::AutoLock l(pending_lock_);
for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i)
- i->second->Cancel();
+ i->second->MarkAsInactive();
pending_requests_.clear();
}
-void WebDataRequestManager::RegisterRequest(WebDataRequest* request) {
- base::AutoLock l(pending_lock_);
- pending_requests_[request->GetHandle()] = request;
-}
+std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest(
+ WebDataServiceConsumer* consumer) {
+ std::unique_ptr<WebDataRequest> request(new WebDataRequest(this, consumer));
-int WebDataRequestManager::GetNextRequestHandle() {
+ // Grab the lock to get the next request handle and register the request.
base::AutoLock l(pending_lock_);
- return ++next_request_handle_;
+ request->handle_ = ++next_request_handle_;
Peter Kasting 2016/12/15 01:05:34 Nit: I think this should be next_request_handle_++
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
+ pending_requests_[request->handle_] = request.get();
+
+ return request;
}
void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) {
base::AutoLock l(pending_lock_);
+ // If the request was already cancelled, or has already completed, it won't
+ // be in the pending_requests_ collection any more.
auto i = pending_requests_.find(h);
- DCHECK(i != pending_requests_.end());
- i->second->Cancel();
+ if (i == pending_requests_.end())
+ return;
+ i->second->MarkAsInactive();
pending_requests_.erase(i);
}
void WebDataRequestManager::RequestCompleted(
- std::unique_ptr<WebDataRequest> request) {
+ std::unique_ptr<WebDataRequest> request,
+ std::unique_ptr<WDTypedResult> result) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
request->GetTaskRunner();
task_runner->PostTask(
- FROM_HERE, base::Bind(&WebDataRequestManager::RequestCompletedOnThread,
- this, base::Passed(&request)));
+ FROM_HERE,
+ base::Bind(&WebDataRequestManager::RequestCompletedOnThread, this,
+ base::Passed(&request), base::Passed(&result)));
}
void WebDataRequestManager::RequestCompletedOnThread(
- std::unique_ptr<WebDataRequest> request) {
- if (request->IsCancelled())
+ std::unique_ptr<WebDataRequest> request,
+ std::unique_ptr<WDTypedResult> result) {
+ // If the request is already inactive, early exit to avoid contending for the
+ // lock (aka, the double checked locking pattern).
+ if (!request->IsActive())
return;
- // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile1(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422460 WebDataRequestManager::RequestCompletedOnThread::UpdateMap"));
+ // Placeholders for the request consumer, handle and result... to be used
Peter Kasting 2016/12/15 01:05:34 Nit: Comment seems inaccurate? I don't see the ot
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Oops, out of date comment. I'd prefer to leave a
+ // when notifying the consumer that the request has completed.
+ WebDataServiceConsumer* consumer = nullptr;
+
+ // Manipulate the pending_requests_ collection while holding the lock.
{
base::AutoLock l(pending_lock_);
+
+ // Re-check whether the request is active. It might have been cancelled in
+ // another thread before the lock was acquired.
+ if (!request->IsActive())
+ return;
+
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
Peter Kasting 2016/12/15 01:05:34 Nit: Rename this variable and the one below to no
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "422460 "
+ "WebDataRequestManager::RequestCompletedOnThread::UpdateMap"));
+
auto i = pending_requests_.find(request->GetHandle());
DCHECK(i != pending_requests_.end());
// Take ownership of the request object and remove it from the map.
pending_requests_.erase(i);
- }
- // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile2(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "422460 "
- "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer"));
+ // Remember the consumer and result for notification below.
+ consumer = request->GetConsumer();
- // Notify the consumer if needed.
- if (!request->IsCancelled()) {
- WebDataServiceConsumer* consumer = request->GetConsumer();
- request->OnComplete();
- if (consumer) {
- consumer->OnWebDataServiceRequestDone(request->GetHandle(),
- request->GetResult());
- }
+ // The request is no longer active.
+ request->MarkAsInactive();
}
+ // Notify the consumer if needed.
+ //
+ // NOTE: The pending_lock_ is no longer held here. It's up to the consumer to
+ // be appropriately thread safe.
+ if (consumer) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "422460 "
+ "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer"));
+
+ consumer->OnWebDataServiceRequestDone(request->GetHandle(),
+ std::move(result));
+ }
}

Powered by Google App Engine
This is Rietveld 408576698