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..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)); |
| + } |
| } |