| // Copyright 2018 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 "content/renderer/loader/code_cache_loader_impl.h" |
| #include "base/bind.h" |
| #include "base/task/post_task.h" |
| #include "third_party/blink/public/platform/platform.h" |
| |
| namespace content { |
| |
| CodeCacheLoaderImpl::CodeCacheLoaderImpl() : CodeCacheLoaderImpl(nullptr) {} |
| |
| CodeCacheLoaderImpl::CodeCacheLoaderImpl( |
| base::WaitableEvent* terminate_sync_load_event) |
| : terminate_sync_load_event_(terminate_sync_load_event), |
| weak_ptr_factory_(this) {} |
| |
| CodeCacheLoaderImpl::~CodeCacheLoaderImpl() = default; |
| |
| void CodeCacheLoaderImpl::FetchFromCodeCacheSynchronously( |
| const GURL& url, |
| base::Time* response_time_out, |
| std::vector<uint8_t>* data_out) { |
| base::WaitableEvent fetch_code_cache_event( |
| base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner = |
| base::CreateSingleThreadTaskRunnerWithTraits({}); |
| |
| // Also watch for terminate requests from the main thread when running on |
| // worker threads. |
| if (terminate_sync_load_event_) { |
| terminate_watcher_.StartWatching( |
| terminate_sync_load_event_, |
| base::BindOnce(&CodeCacheLoaderImpl::OnTerminate, |
| weak_ptr_factory_.GetWeakPtr(), |
| base::Unretained(&fetch_code_cache_event)), |
| task_runner); |
| } |
| |
| FetchCodeCacheCallback callback = |
| base::BindOnce(&CodeCacheLoaderImpl::ReceiveDataForSynchronousFetch, |
| weak_ptr_factory_.GetWeakPtr()); |
| |
| // It is Ok to pass |fetch_code_cache_event| with base::Unretained. Since |
| // this thread is stalled, the fetch_code_cache_event will be kept alive. |
| task_runner->PostTask( |
| FROM_HERE, base::BindOnce(&CodeCacheLoaderImpl::FetchFromCodeCacheImpl, |
| weak_ptr_factory_.GetWeakPtr(), |
| blink::mojom::CodeCacheType::kJavascript, url, |
| std::move(callback), |
| base::Unretained(&fetch_code_cache_event))); |
| |
| // Wait for the fetch from code cache to finish. |
| fetch_code_cache_event.Wait(); |
| |
| // Set the output data |
| *response_time_out = response_time_for_sync_load_; |
| *data_out = data_for_sync_load_; |
| } |
| |
| void CodeCacheLoaderImpl::FetchFromCodeCache( |
| blink::mojom::CodeCacheType cache_type, |
| const GURL& url, |
| FetchCodeCacheCallback callback) { |
| FetchFromCodeCacheImpl(cache_type, url, std::move(callback), nullptr); |
| } |
| |
| void CodeCacheLoaderImpl::FetchFromCodeCacheImpl( |
| blink::mojom::CodeCacheType cache_type, |
| const GURL& gurl, |
| FetchCodeCacheCallback callback, |
| base::WaitableEvent* fetch_event) { |
| // This may run on a different thread for synchronous events. It is Ok to pass |
| // fetch_event, because the thread is stalled and it will keep the fetch_event |
| // alive. |
| blink::Platform::Current()->FetchCachedCode( |
| cache_type, gurl, |
| base::BindOnce(&CodeCacheLoaderImpl::OnReceiveCachedCode, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback), |
| fetch_event)); |
| } |
| |
| void CodeCacheLoaderImpl::OnReceiveCachedCode( |
| FetchCodeCacheCallback callback, |
| base::WaitableEvent* fetch_event, |
| base::Time response_time, |
| const std::vector<uint8_t>& data) { |
| // The loader would be destroyed once the fetch has completed. On terminate |
| // the fetch event would be signalled and the fetch should complete and hence |
| // we should not see this callback anymore. |
| DCHECK(!terminated_); |
| std::move(callback).Run(response_time, data); |
| if (fetch_event) |
| fetch_event->Signal(); |
| } |
| |
| void CodeCacheLoaderImpl::ReceiveDataForSynchronousFetch( |
| const base::Time& response_time, |
| const std::vector<uint8_t>& data) { |
| response_time_for_sync_load_ = response_time; |
| data_for_sync_load_ = data; |
| } |
| |
| void CodeCacheLoaderImpl::OnTerminate(base::WaitableEvent* fetch_event, |
| base::WaitableEvent* terminate_event) { |
| DCHECK(!terminated_); |
| terminated_ = true; |
| DCHECK(fetch_event); |
| fetch_event->Signal(); |
| } |
| |
| } // namespace content |