| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/webdata/common/web_data_request_manager.h" |
| |
| #include <utility> |
| |
| #include "base/functional/bind.h" |
| #include "base/location.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/task/thread_pool.h" |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // WebDataRequest implementation. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| WebDataRequest::~WebDataRequest() { |
| WebDataRequestManager* manager = GetManager(); |
| if (manager) { |
| manager->CancelRequest(handle_); |
| } |
| } |
| |
| WebDataServiceBase::Handle WebDataRequest::GetHandle() const { |
| return handle_; |
| } |
| |
| bool WebDataRequest::IsActive() { |
| return GetManager() != nullptr; |
| } |
| |
| WebDataRequest::WebDataRequest(WebDataRequestManager* manager, |
| WebDataServiceRequestCallback consumer, |
| WebDataServiceBase::Handle handle) |
| : task_runner_(base::SequencedTaskRunner::HasCurrentDefault() |
| ? base::SequencedTaskRunner::GetCurrentDefault() |
| : nullptr), |
| atomic_manager_(manager), |
| consumer_(std::move(consumer)), |
| handle_(handle) { |
| DCHECK(IsActive()); |
| static_assert(sizeof(atomic_manager_) == sizeof(manager), "size mismatch"); |
| } |
| |
| WebDataRequestManager* WebDataRequest::GetManager() { |
| return atomic_manager_.load(std::memory_order_acquire); |
| } |
| |
| WebDataServiceRequestCallback WebDataRequest::ExtractConsumer() && { |
| return std::move(consumer_); |
| } |
| |
| scoped_refptr<base::SequencedTaskRunner> WebDataRequest::GetTaskRunner() { |
| return task_runner_; |
| } |
| |
| void WebDataRequest::MarkAsInactive() { |
| atomic_manager_.store(nullptr, std::memory_order_release); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // WebDataRequestManager implementation. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| WebDataRequestManager::WebDataRequestManager() : next_request_handle_(1) {} |
| |
| std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest( |
| WebDataServiceRequestCallback consumer) { |
| base::AutoLock l(pending_lock_); |
| std::unique_ptr<WebDataRequest> request = base::WrapUnique( |
| new WebDataRequest(this, std::move(consumer), next_request_handle_)); |
| bool inserted = |
| pending_requests_.emplace(next_request_handle_, request.get()).second; |
| DCHECK(inserted); |
| ++next_request_handle_; |
| 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); |
| if (i == pending_requests_.end()) { |
| return; |
| } |
| i->second->MarkAsInactive(); |
| pending_requests_.erase(i); |
| } |
| |
| void WebDataRequestManager::RequestCompleted( |
| std::unique_ptr<WebDataRequest> request, |
| std::unique_ptr<WDTypedResult> result) { |
| // Careful: Don't swap this below the BindOnce() call below, since that |
| // effectively does a std::move() on |request|! |
| scoped_refptr<base::SequencedTaskRunner> task_runner = |
| request->GetTaskRunner(); |
| auto task = base::BindOnce(&WebDataRequestManager::RequestCompletedOnThread, |
| this, std::move(request), std::move(result)); |
| if (task_runner) { |
| task_runner->PostTask(FROM_HERE, std::move(task)); |
| } else { |
| base::ThreadPool::PostTask(FROM_HERE, std::move(task)); |
| } |
| } |
| |
| WebDataRequestManager::~WebDataRequestManager() { |
| base::AutoLock l(pending_lock_); |
| for (auto& pending_request : pending_requests_) { |
| pending_request.second->MarkAsInactive(); |
| } |
| pending_requests_.clear(); |
| } |
| |
| void WebDataRequestManager::RequestCompletedOnThread( |
| std::unique_ptr<WebDataRequest> request, |
| std::unique_ptr<WDTypedResult> result) { |
| // Check whether the request is active. It might have been cancelled in |
| // another thread before this completion handler was invoked. This means the |
| // request initiator is no longer interested in the result. |
| if (!request->IsActive()) { |
| return; |
| } |
| |
| WebDataServiceBase::Handle handle = request->GetHandle(); |
| WebDataServiceRequestCallback consumer = |
| std::move(*request).ExtractConsumer(); |
| |
| // Stop tracking the request. The request is already finished, so "stop |
| // tracking" is the same as post-facto cancellation. |
| CancelRequest(handle); |
| |
| // Notify the consumer if needed. |
| if (!consumer.is_null()) { |
| std::move(consumer).Run(handle, std::move(result)); |
| } |
| } |