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