Chromium Code Reviews| 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)); |
| + } |
| } |