| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // 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/bind.h" |
| #include "base/location.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/stl_util.h" |
| #include "base/task/post_task.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| #include "base/threading/thread_task_runner_handle.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, |
| WebDataServiceConsumer* consumer, |
| WebDataServiceBase::Handle handle) |
| : task_runner_(base::SequencedTaskRunnerHandle::IsSet() |
| ? base::SequencedTaskRunnerHandle::Get() |
| : nullptr), |
| atomic_manager_(reinterpret_cast<base::subtle::AtomicWord>(manager)), |
| consumer_(consumer), |
| handle_(handle) { |
| DCHECK(IsActive()); |
| static_assert(sizeof(atomic_manager_) == sizeof(manager), "size mismatch"); |
| } |
| |
| WebDataRequestManager* WebDataRequest::GetManager() { |
| return reinterpret_cast<WebDataRequestManager*>( |
| base::subtle::Acquire_Load(&atomic_manager_)); |
| } |
| |
| WebDataServiceConsumer* WebDataRequest::GetConsumer() { |
| return consumer_; |
| } |
| |
| scoped_refptr<base::SequencedTaskRunner> WebDataRequest::GetTaskRunner() { |
| return task_runner_; |
| } |
| |
| void WebDataRequest::MarkAsInactive() { |
| // Set atomic_manager_ to the equivalent of nullptr; |
| base::subtle::Release_Store(&atomic_manager_, 0); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // WebDataRequestManager implementation. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| WebDataRequestManager::WebDataRequestManager() |
| : next_request_handle_(1) { |
| } |
| |
| std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest( |
| WebDataServiceConsumer* consumer) { |
| base::AutoLock l(pending_lock_); |
| 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; |
| } |
| |
| 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::PostTask(FROM_HERE, std::move(task)); |
| } |
| |
| WebDataRequestManager::~WebDataRequestManager() { |
| base::AutoLock l(pending_lock_); |
| for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i) |
| i->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; |
| |
| // Stop tracking the request. The request is already finished, so "stop |
| // tracking" is the same as post-facto cancellation. |
| CancelRequest(request->GetHandle()); |
| |
| // Notify the consumer if needed. |
| WebDataServiceConsumer* const consumer = request->GetConsumer(); |
| if (consumer) { |
| consumer->OnWebDataServiceRequestDone(request->GetHandle(), |
| std::move(result)); |
| } |
| } |