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

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

Issue 2845753002: Remove data race in WebDataRequest::CancelRequest. (Closed)
Patch Set: rebase Created 3 years, 7 months 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
« no previous file with comments | « components/webdata/common/web_data_request_manager.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 3615379a7584f081735fa26a7b51884a2d98bae4..ec272c06a940cbe121c19a48c1dc7c5b9ffbb1a3 100644
--- a/components/webdata/common/web_data_request_manager.cc
+++ b/components/webdata/common/web_data_request_manager.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/memory/ptr_util.h"
#include "base/profiler/scoped_tracker.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -19,50 +20,47 @@
////////////////////////////////////////////////////////////////////////////////
WebDataRequest::~WebDataRequest() {
- if (IsActive()) {
- manager_->CancelRequest(handle_);
- }
+ WebDataRequestManager* manager = GetManager();
+ if (manager)
+ manager->CancelRequest(handle_);
}
WebDataServiceBase::Handle WebDataRequest::GetHandle() const {
return handle_;
}
-bool WebDataRequest::IsActive() const {
- return manager_ != nullptr;
+bool WebDataRequest::IsActive() {
+ return GetManager() != nullptr;
}
WebDataRequest::WebDataRequest(WebDataRequestManager* manager,
- WebDataServiceConsumer* consumer)
+ WebDataServiceConsumer* consumer,
+ WebDataServiceBase::Handle handle)
: task_runner_(base::ThreadTaskRunnerHandle::Get()),
- manager_(manager),
+ atomic_manager_(reinterpret_cast<base::subtle::AtomicWord>(manager)),
consumer_(consumer),
- handle_(0) {
+ handle_(handle) {
+ DCHECK(task_runner_);
DCHECK(IsActive());
+ static_assert(sizeof(atomic_manager_) == sizeof(manager), "size mismatch");
}
-void WebDataRequest::AssertThreadSafe() const {
- // Manipulations of the request state should only happen when the request is
- // active and the manager's lock is held (i.e., during request cancellation
- // or completion).
- DCHECK(IsActive());
- manager_->AssertLockedByCurrentThread();
+WebDataRequestManager* WebDataRequest::GetManager() {
+ return reinterpret_cast<WebDataRequestManager*>(
+ base::subtle::Acquire_Load(&atomic_manager_));
}
-WebDataServiceConsumer* WebDataRequest::GetConsumer() const {
- AssertThreadSafe();
+WebDataServiceConsumer* WebDataRequest::GetConsumer() {
return consumer_;
}
-scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner()
- const {
+scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner() {
return task_runner_;
}
void WebDataRequest::MarkAsInactive() {
- AssertThreadSafe();
- consumer_ = nullptr;
- manager_ = nullptr;
+ // Set atomic_manager_ to the equivalent of nullptr;
+ base::subtle::Release_Store(&atomic_manager_, 0);
}
////////////////////////////////////////////////////////////////////////////////
@@ -77,13 +75,13 @@ WebDataRequestManager::WebDataRequestManager()
std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest(
WebDataServiceConsumer* consumer) {
- std::unique_ptr<WebDataRequest> request(new WebDataRequest(this, consumer));
-
- // Grab the lock to get the next request handle and register the request.
base::AutoLock l(pending_lock_);
- request->handle_ = next_request_handle_++;
- pending_requests_[request->handle_] = request.get();
-
+ std::unique_ptr<WebDataRequest> request = base::WrapUnique(
+ new WebDataRequest(this, consumer, next_request_handle_));
+ bool inserted =
+ pending_requests_.emplace(next_request_handle_, request.get()).second;
+ DCHECK(inserted);
+ ++next_request_handle_;
return request;
}
@@ -105,12 +103,8 @@ void WebDataRequestManager::RequestCompleted(
request->GetTaskRunner();
task_runner->PostTask(
FROM_HERE,
- base::Bind(&WebDataRequestManager::RequestCompletedOnThread, this,
- base::Passed(&request), base::Passed(&result)));
-}
-
-void WebDataRequestManager::AssertLockedByCurrentThread() const {
- pending_lock_.AssertAcquired();
+ base::BindOnce(&WebDataRequestManager::RequestCompletedOnThread, this,
+ base::Passed(&request), base::Passed(&result)));
}
WebDataRequestManager::~WebDataRequestManager() {
@@ -123,28 +117,15 @@ WebDataRequestManager::~WebDataRequestManager() {
void WebDataRequestManager::RequestCompletedOnThread(
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;
-
- // Used to export the consumer from the locked region below so that the
- // consumer can be notified outside of the lock and after the request has
- // been marked as inactive.
- WebDataServiceConsumer* consumer;
-
// 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
+ // Check whether the request is active. It might have been cancelled in
// another thread before the lock was acquired.
if (!request->IsActive())
return;
- // Remember the consumer for notification below.
- consumer = request->GetConsumer();
-
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
// is fixed.
tracked_objects::ScopedTracker tracking_profile(
@@ -152,10 +133,10 @@ void WebDataRequestManager::RequestCompletedOnThread(
"422460 "
"WebDataRequestManager::RequestCompletedOnThread::UpdateMap"));
+ // Remove the request object from the pending_requests_ map. Note that this
+ // method has ownership of the object (it was passed by unique_ptr).
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);
// The request is no longer active.
@@ -166,6 +147,7 @@ void WebDataRequestManager::RequestCompletedOnThread(
//
// NOTE: The pending_lock_ is no longer held here. It's up to the consumer to
// be appropriately thread safe.
+ WebDataServiceConsumer* const consumer = request->GetConsumer();
if (consumer) {
// TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
// is fixed.
« no previous file with comments | « components/webdata/common/web_data_request_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698