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

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

Issue 2571923002: Fix threading issues in WebDataRequestManager. (Closed)
Patch Set: 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..eb958fd8eab782319b95d76c2d1a84d19022abae 100644
--- a/components/webdata/common/web_data_request_manager.cc
+++ b/components/webdata/common/web_data_request_manager.cc
@@ -20,9 +20,10 @@
WebDataRequest::WebDataRequest(WebDataServiceConsumer* consumer,
WebDataRequestManager* manager)
- : manager_(manager), cancelled_(false), consumer_(consumer) {
- handle_ = manager_->GetNextRequestHandle();
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ handle_(manager->GetNextRequestHandle()),
+ manager_(manager),
+ consumer_(consumer) {
manager_->RegisterRequest(this);
}
@@ -36,7 +37,22 @@ WebDataServiceBase::Handle WebDataRequest::GetHandle() const {
return handle_;
}
+bool WebDataRequest::IsCancelled() const {
Mathieu 2016/12/14 01:13:46 IsInactive? Could be completed at this point too i
Roger McFarlane (Chromium) 2016/12/14 14:02:49 Done. But used IsActive instead, to avoid the doub
+ return manager_ == nullptr;
+}
+
+inline void WebDataRequest::AssertThreadSafe() const {
+ // Of manager_ is null then the request has already been cancelled or
Mathieu 2016/12/14 01:13:46 If
Roger McFarlane (Chromium) 2016/12/14 14:02:49 Done.
+ // completed, and the asserting context represents and invalid state.
Mathieu 2016/12/14 01:13:46 *an
Roger McFarlane (Chromium) 2016/12/14 14:02:49 Done.
+ DCHECK(manager_);
+
+ // Manipulations of the request state should only happen when the manager's
+ // lock is held (i.e., during request cancellation or completion).
+ manager_->AssertLockedByCurrentThread();
+}
+
WebDataServiceConsumer* WebDataRequest::GetConsumer() const {
+ AssertThreadSafe();
return consumer_;
}
@@ -45,27 +61,19 @@ scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner()
return task_runner_;
}
-bool WebDataRequest::IsCancelled() const {
- base::AutoLock l(cancel_lock_);
Roger McFarlane (Chromium) 2016/12/13 22:33:55 this lock isn't useful, it's not protecting agains
- return cancelled_;
-}
-
-void WebDataRequest::Cancel() {
- base::AutoLock l(cancel_lock_);
Roger McFarlane (Chromium) 2016/12/13 22:33:55 this lock isn't useful. This code is called under
- cancelled_ = true;
- consumer_ = NULL;
- manager_ = NULL;
-}
-
-void WebDataRequest::OnComplete() {
- manager_= NULL;
+void WebDataRequest::MarkAsInactive() {
+ AssertThreadSafe();
+ consumer_ = nullptr;
+ manager_ = nullptr;
}
void WebDataRequest::SetResult(std::unique_ptr<WDTypedResult> r) {
+ AssertThreadSafe();
result_ = std::move(r);
Roger McFarlane (Chromium) 2016/12/13 22:33:55 this isn't thread safe, could leak r.
}
std::unique_ptr<WDTypedResult> WebDataRequest::GetResult() {
+ AssertThreadSafe();
return std::move(result_);
Roger McFarlane (Chromium) 2016/12/13 22:33:55 this isn't thread safe, you could end up with mult
}
@@ -82,7 +90,7 @@ 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();
}
@@ -98,55 +106,82 @@ int WebDataRequestManager::GetNextRequestHandle() {
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());
Roger McFarlane (Chromium) 2016/12/13 22:33:55 This DCHECK isn't valid. Given concurrent cancell
- i->second->Cancel();
+ if (i == pending_requests_.end())
+ return;
+ i->second->MarkAsInactive();
pending_requests_.erase(i);
}
void WebDataRequestManager::RequestCompleted(
- std::unique_ptr<WebDataRequest> request) {
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- request->GetTaskRunner();
- task_runner->PostTask(
+ std::unique_ptr<WebDataRequest> request,
+ std::unique_ptr<WDTypedResult> result) {
+ // Transfer ownership of the result to the request.
+ {
+ base::AutoLock l(pending_lock_);
+ request->SetResult(std::move(result));
Avi (use Gerrit) 2016/12/14 04:40:39 If we no longer have the WebDatabaseBackend call S
Roger McFarlane (Chromium) 2016/12/14 14:02:49 Ah, yes... should have made that private. But pass
+ }
+ request->GetTaskRunner()->PostTask(
FROM_HERE, base::Bind(&WebDataRequestManager::RequestCompletedOnThread,
this, base::Passed(&request)));
}
void WebDataRequestManager::RequestCompletedOnThread(
std::unique_ptr<WebDataRequest> request) {
+ // Early exit if the request is cancelled.
if (request->IsCancelled())
Roger McFarlane (Chromium) 2016/12/13 22:33:55 An optimization, to attempt to avoid contending fo
Mathieu 2016/12/14 01:13:46 This would be a worthwhile comment for a reader th
Roger McFarlane (Chromium) 2016/12/14 14:02:49 This is the double-checked locking pattern. I'll a
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
+ // when notifying the consumer that the request has completed.
+ WebDataServiceConsumer* consumer = nullptr;
+ std::unique_ptr<WDTypedResult> result;
+
+ // Manipulate the pending_requests_ collection while holding the lock.
{
base::AutoLock l(pending_lock_);
+
+ // Re-check if the request was cancelled. It might have been cancelled in
+ // another thread before the lock was acquired.
+ if (request->IsCancelled())
+ 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"));
+
auto i = pending_requests_.find(request->GetHandle());
DCHECK(i != pending_requests_.end());
Roger McFarlane (Chromium) 2016/12/13 22:33:55 This DCHECK isn't valid. Given concurrent cancell
Mathieu 2016/12/14 01:13:46 It's still in your change, should we remove it?
Roger McFarlane (Chromium) 2016/12/14 14:02:49 It should be valid now, since we re-check while ho
// 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();
+ result = request->GetResult();
- // 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