Index: chrome/browser/nacl_host/pnacl_host.cc |
diff --git a/chrome/browser/nacl_host/pnacl_host.cc b/chrome/browser/nacl_host/pnacl_host.cc |
deleted file mode 100644 |
index 6a974cd9aaa40a5f0f07223f2dd3b9b33d4a58c2..0000000000000000000000000000000000000000 |
--- a/chrome/browser/nacl_host/pnacl_host.cc |
+++ /dev/null |
@@ -1,630 +0,0 @@ |
-// Copyright 2013 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 "chrome/browser/nacl_host/pnacl_host.h" |
- |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/file_util.h" |
-#include "base/files/file_path.h" |
-#include "base/logging.h" |
-#include "base/task_runner_util.h" |
-#include "base/threading/sequenced_worker_pool.h" |
-#include "components/nacl/browser/nacl_browser.h" |
-#include "components/nacl/browser/pnacl_translation_cache.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "net/base/io_buffer.h" |
-#include "net/base/net_errors.h" |
- |
-using content::BrowserThread; |
- |
-namespace { |
-static const base::FilePath::CharType kTranslationCacheDirectoryName[] = |
- FILE_PATH_LITERAL("PnaclTranslationCache"); |
-// Delay to wait for initialization of the cache backend |
-static const int kTranslationCacheInitializationDelayMs = 20; |
-} |
- |
-PnaclHost::PnaclHost() |
- : pending_backend_operations_(0), |
- cache_state_(CacheUninitialized), |
- weak_factory_(this) {} |
- |
-PnaclHost::~PnaclHost() { |
- // When PnaclHost is destroyed, it's too late to post anything to the cache |
- // thread (it will hang shutdown). So just leak the cache backend. |
- pnacl::PnaclTranslationCache* cache = disk_cache_.release(); |
- (void)cache; |
-} |
- |
-PnaclHost* PnaclHost::GetInstance() { return Singleton<PnaclHost>::get(); } |
- |
-PnaclHost::PendingTranslation::PendingTranslation() |
- : process_handle(base::kNullProcessHandle), |
- render_view_id(0), |
- nexe_fd(base::kInvalidPlatformFileValue), |
- got_nexe_fd(false), |
- got_cache_reply(false), |
- got_cache_hit(false), |
- is_incognito(false), |
- callback(NexeFdCallback()), |
- cache_info(nacl::PnaclCacheInfo()) {} |
-PnaclHost::PendingTranslation::~PendingTranslation() {} |
- |
-bool PnaclHost::TranslationMayBeCached( |
- const PendingTranslationMap::iterator& entry) { |
- return !entry->second.is_incognito && |
- !entry->second.cache_info.has_no_store_header; |
-} |
- |
-/////////////////////////////////////// Initialization |
- |
-static base::FilePath GetCachePath() { |
- NaClBrowserDelegate* browser_delegate = nacl::NaClBrowser::GetDelegate(); |
- // Determine where the translation cache resides in the file system. It |
- // exists in Chrome's cache directory and is not tied to any specific |
- // profile. If we fail, return an empty path. |
- // Start by finding the user data directory. |
- base::FilePath user_data_dir; |
- if (!browser_delegate || |
- !browser_delegate->GetUserDirectory(&user_data_dir)) { |
- return base::FilePath(); |
- } |
- // The cache directory may or may not be the user data directory. |
- base::FilePath cache_file_path; |
- browser_delegate->GetCacheDirectory(&cache_file_path); |
- |
- // Append the base file name to the cache directory. |
- return cache_file_path.Append(kTranslationCacheDirectoryName); |
-} |
- |
-void PnaclHost::OnCacheInitialized(int net_error) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- // If the cache was cleared before the load completed, ignore. |
- if (cache_state_ == CacheReady) |
- return; |
- if (net_error != net::OK) { |
- // This will cause the cache to attempt to re-init on the next call to |
- // GetNexeFd. |
- cache_state_ = CacheUninitialized; |
- } else { |
- cache_state_ = CacheReady; |
- } |
-} |
- |
-void PnaclHost::Init() { |
- // Extra check that we're on the real IO thread since this version of |
- // Init isn't used in unit tests. |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- base::FilePath cache_path(GetCachePath()); |
- if (cache_path.empty() || cache_state_ != CacheUninitialized) |
- return; |
- disk_cache_.reset(new pnacl::PnaclTranslationCache()); |
- cache_state_ = CacheInitializing; |
- int rv = disk_cache_->InitOnDisk( |
- cache_path, |
- base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr())); |
- if (rv != net::ERR_IO_PENDING) |
- OnCacheInitialized(rv); |
-} |
- |
-// Initialize using the in-memory backend, and manually set the temporary file |
-// directory instead of using the system directory. |
-void PnaclHost::InitForTest(base::FilePath temp_dir) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- disk_cache_.reset(new pnacl::PnaclTranslationCache()); |
- cache_state_ = CacheInitializing; |
- temp_dir_ = temp_dir; |
- int rv = disk_cache_->InitInMemory( |
- base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr())); |
- if (rv != net::ERR_IO_PENDING) |
- OnCacheInitialized(rv); |
-} |
- |
-///////////////////////////////////////// Temp files |
- |
-// Create a temporary file on the blocking pool |
-// static |
-void PnaclHost::DoCreateTemporaryFile(base::FilePath temp_dir, |
- TempFileCallback cb) { |
- DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
- |
- base::FilePath file_path; |
- base::PlatformFile file_handle(base::kInvalidPlatformFileValue); |
- bool rv = temp_dir.empty() |
- ? file_util::CreateTemporaryFile(&file_path) |
- : file_util::CreateTemporaryFileInDir(temp_dir, &file_path); |
- if (!rv) { |
- PLOG(ERROR) << "Temp file creation failed."; |
- } else { |
- base::PlatformFileError error; |
- file_handle = base::CreatePlatformFile( |
- file_path, |
- base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ | |
- base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY | |
- base::PLATFORM_FILE_DELETE_ON_CLOSE, |
- NULL, |
- &error); |
- |
- if (error != base::PLATFORM_FILE_OK) { |
- PLOG(ERROR) << "Temp file open failed: " << error; |
- file_handle = base::kInvalidPlatformFileValue; |
- } |
- } |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, base::Bind(cb, file_handle)); |
-} |
- |
-void PnaclHost::CreateTemporaryFile(TempFileCallback cb) { |
- if (!BrowserThread::PostBlockingPoolSequencedTask( |
- "PnaclHostCreateTempFile", |
- FROM_HERE, |
- base::Bind(&PnaclHost::DoCreateTemporaryFile, temp_dir_, cb))) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- cb.Run(base::kInvalidPlatformFileValue); |
- } |
-} |
- |
-///////////////////////////////////////// GetNexeFd implementation |
-////////////////////// Common steps |
- |
-void PnaclHost::GetNexeFd(int render_process_id, |
- int render_view_id, |
- int pp_instance, |
- bool is_incognito, |
- const nacl::PnaclCacheInfo& cache_info, |
- const NexeFdCallback& cb) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- if (cache_state_ == CacheUninitialized) { |
- Init(); |
- } |
- if (cache_state_ != CacheReady) { |
- // If the backend hasn't yet initialized, try the request again later. |
- BrowserThread::PostDelayedTask(BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&PnaclHost::GetNexeFd, |
- weak_factory_.GetWeakPtr(), |
- render_process_id, |
- render_view_id, |
- pp_instance, |
- is_incognito, |
- cache_info, |
- cb), |
- base::TimeDelta::FromMilliseconds( |
- kTranslationCacheInitializationDelayMs)); |
- return; |
- } |
- |
- TranslationID id(render_process_id, pp_instance); |
- PendingTranslationMap::iterator entry = pending_translations_.find(id); |
- if (entry != pending_translations_.end()) { |
- // Existing translation must have been abandonded. Clean it up. |
- LOG(ERROR) << "GetNexeFd for already-pending translation"; |
- pending_translations_.erase(entry); |
- } |
- |
- std::string cache_key(disk_cache_->GetKey(cache_info)); |
- if (cache_key.empty()) { |
- LOG(ERROR) << "GetNexeFd: Invalid cache info"; |
- cb.Run(base::kInvalidPlatformFileValue, false); |
- return; |
- } |
- |
- PendingTranslation pt; |
- pt.render_view_id = render_view_id; |
- pt.callback = cb; |
- pt.cache_info = cache_info; |
- pt.cache_key = cache_key; |
- pt.is_incognito = is_incognito; |
- pending_translations_[id] = pt; |
- SendCacheQueryAndTempFileRequest(cache_key, id); |
-} |
- |
-// Dispatch the cache read request and the temp file creation request |
-// simultaneously; currently we need a temp file regardless of whether the |
-// request hits. |
-void PnaclHost::SendCacheQueryAndTempFileRequest(const std::string& cache_key, |
- const TranslationID& id) { |
- pending_backend_operations_++; |
- disk_cache_->GetNexe( |
- cache_key, |
- base::Bind( |
- &PnaclHost::OnCacheQueryReturn, weak_factory_.GetWeakPtr(), id)); |
- |
- CreateTemporaryFile( |
- base::Bind(&PnaclHost::OnTempFileReturn, weak_factory_.GetWeakPtr(), id)); |
-} |
- |
-// Callback from the translation cache query. |id| is bound from |
-// SendCacheQueryAndTempFileRequest, |net_error| is a net::Error code (which for |
-// our purposes means a hit if it's net::OK (i.e. 0). |buffer| is allocated |
-// by PnaclTranslationCache and now belongs to PnaclHost. |
-// (Bound callbacks must re-lookup the TranslationID because the translation |
-// could be cancelled before they get called). |
-void PnaclHost::OnCacheQueryReturn( |
- const TranslationID& id, |
- int net_error, |
- scoped_refptr<net::DrainableIOBuffer> buffer) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- pending_backend_operations_--; |
- PendingTranslationMap::iterator entry(pending_translations_.find(id)); |
- if (entry == pending_translations_.end()) { |
- LOG(ERROR) << "OnCacheQueryReturn: id not found"; |
- DeInitIfSafe(); |
- return; |
- } |
- PendingTranslation* pt = &entry->second; |
- pt->got_cache_reply = true; |
- pt->got_cache_hit = (net_error == net::OK); |
- if (pt->got_cache_hit) |
- pt->nexe_read_buffer = buffer; |
- CheckCacheQueryReady(entry); |
-} |
- |
-// Callback from temp file creation. |id| is bound from |
-// SendCacheQueryAndTempFileRequest, and fd is the created file descriptor. |
-// If there was an error, fd is kInvalidPlatformFileValue. |
-// (Bound callbacks must re-lookup the TranslationID because the translation |
-// could be cancelled before they get called). |
-void PnaclHost::OnTempFileReturn(const TranslationID& id, |
- base::PlatformFile fd) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- PendingTranslationMap::iterator entry(pending_translations_.find(id)); |
- if (entry == pending_translations_.end()) { |
- // The renderer may have signaled an error or closed while the temp |
- // file was being created. |
- LOG(ERROR) << "OnTempFileReturn: id not found"; |
- BrowserThread::PostBlockingPoolTask( |
- FROM_HERE, base::Bind(base::IgnoreResult(base::ClosePlatformFile), fd)); |
- return; |
- } |
- if (fd == base::kInvalidPlatformFileValue) { |
- // This translation will fail, but we need to retry any translation |
- // waiting for its result. |
- LOG(ERROR) << "OnTempFileReturn: temp file creation failed"; |
- std::string key(entry->second.cache_key); |
- entry->second.callback.Run(fd, false); |
- bool may_be_cached = TranslationMayBeCached(entry); |
- pending_translations_.erase(entry); |
- // No translations will be waiting for entries that will not be stored. |
- if (may_be_cached) |
- RequeryMatchingTranslations(key); |
- return; |
- } |
- PendingTranslation* pt = &entry->second; |
- pt->got_nexe_fd = true; |
- pt->nexe_fd = fd; |
- CheckCacheQueryReady(entry); |
-} |
- |
-// Check whether both the cache query and the temp file have returned, and check |
-// whether we actually got a hit or not. |
-void PnaclHost::CheckCacheQueryReady( |
- const PendingTranslationMap::iterator& entry) { |
- PendingTranslation* pt = &entry->second; |
- if (!(pt->got_cache_reply && pt->got_nexe_fd)) |
- return; |
- if (!pt->got_cache_hit) { |
- // Check if there is already a pending translation for this file. If there |
- // is, we will wait for it to come back, to avoid redundant translations. |
- for (PendingTranslationMap::iterator it = pending_translations_.begin(); |
- it != pending_translations_.end(); |
- ++it) { |
- // Another translation matches if it's a request for the same file, |
- if (it->second.cache_key == entry->second.cache_key && |
- // and it's not this translation, |
- it->first != entry->first && |
- // and it can be stored in the cache, |
- TranslationMayBeCached(it) && |
- // and it's already gotten past this check and returned the miss. |
- it->second.got_cache_reply && |
- it->second.got_nexe_fd) { |
- return; |
- } |
- } |
- ReturnMiss(entry); |
- return; |
- } |
- |
- if (!base::PostTaskAndReplyWithResult( |
- BrowserThread::GetBlockingPool(), |
- FROM_HERE, |
- base::Bind( |
- &PnaclHost::CopyBufferToFile, pt->nexe_fd, pt->nexe_read_buffer), |
- base::Bind(&PnaclHost::OnBufferCopiedToTempFile, |
- weak_factory_.GetWeakPtr(), |
- entry->first))) { |
- pt->callback.Run(base::kInvalidPlatformFileValue, false); |
- } |
-} |
- |
-//////////////////// GetNexeFd miss path |
-// Return the temp fd to the renderer, reporting a miss. |
-void PnaclHost::ReturnMiss(const PendingTranslationMap::iterator& entry) { |
- // Return the fd |
- PendingTranslation* pt = &entry->second; |
- NexeFdCallback cb(pt->callback); |
- if (pt->nexe_fd == base::kInvalidPlatformFileValue) { |
- // Bad FD is unrecoverable, so clear out the entry |
- pending_translations_.erase(entry); |
- } |
- cb.Run(pt->nexe_fd, false); |
-} |
- |
-// On error, just return a null refptr. |
-// static |
-scoped_refptr<net::DrainableIOBuffer> PnaclHost::CopyFileToBuffer( |
- base::PlatformFile fd) { |
- base::PlatformFileInfo info; |
- scoped_refptr<net::DrainableIOBuffer> buffer; |
- bool error = false; |
- if (!base::GetPlatformFileInfo(fd, &info) || |
- info.size >= std::numeric_limits<int>::max()) { |
- PLOG(ERROR) << "GetPlatformFileInfo failed"; |
- error = true; |
- } else { |
- buffer = new net::DrainableIOBuffer( |
- new net::IOBuffer(static_cast<int>(info.size)), info.size); |
- if (base::ReadPlatformFile(fd, 0, buffer->data(), buffer->size()) != |
- info.size) { |
- PLOG(ERROR) << "CopyFileToBuffer file read failed"; |
- error = true; |
- } |
- } |
- if (error) { |
- buffer = NULL; |
- } |
- base::ClosePlatformFile(fd); |
- return buffer; |
-} |
- |
-// Called by the renderer in the miss path to report a finished translation |
-void PnaclHost::TranslationFinished(int render_process_id, |
- int pp_instance, |
- bool success) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- if (cache_state_ != CacheReady) |
- return; |
- TranslationID id(render_process_id, pp_instance); |
- PendingTranslationMap::iterator entry(pending_translations_.find(id)); |
- if (entry == pending_translations_.end()) { |
- LOG(ERROR) << "TranslationFinished: TranslationID " << render_process_id |
- << "," << pp_instance << " not found."; |
- return; |
- } |
- bool store_nexe = true; |
- // If this is a premature response (i.e. we haven't returned a temp file |
- // yet) or if it's an unsuccessful translation, or if we are incognito, |
- // don't store in the cache. |
- // TODO(dschuff): use a separate in-memory cache for incognito |
- // translations. |
- if (!entry->second.got_nexe_fd || !entry->second.got_cache_reply || |
- !success || !TranslationMayBeCached(entry)) { |
- store_nexe = false; |
- } else if (!base::PostTaskAndReplyWithResult( |
- BrowserThread::GetBlockingPool(), |
- FROM_HERE, |
- base::Bind(&PnaclHost::CopyFileToBuffer, |
- entry->second.nexe_fd), |
- base::Bind(&PnaclHost::StoreTranslatedNexe, |
- weak_factory_.GetWeakPtr(), |
- id))) { |
- store_nexe = false; |
- } |
- |
- if (!store_nexe) { |
- // If store_nexe is true, the fd will be closed by CopyFileToBuffer. |
- if (entry->second.got_nexe_fd) { |
- BrowserThread::PostBlockingPoolTask( |
- FROM_HERE, |
- base::Bind(base::IgnoreResult(base::ClosePlatformFile), |
- entry->second.nexe_fd)); |
- } |
- pending_translations_.erase(entry); |
- } |
-} |
- |
-// Store the translated nexe in the translation cache. Called back with the |
-// TranslationID from the host and the result of CopyFileToBuffer. |
-// (Bound callbacks must re-lookup the TranslationID because the translation |
-// could be cancelled before they get called). |
-void PnaclHost::StoreTranslatedNexe( |
- TranslationID id, |
- scoped_refptr<net::DrainableIOBuffer> buffer) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- if (cache_state_ != CacheReady) |
- return; |
- PendingTranslationMap::iterator it(pending_translations_.find(id)); |
- if (it == pending_translations_.end()) { |
- LOG(ERROR) << "StoreTranslatedNexe: TranslationID " << id.first << "," |
- << id.second << " not found."; |
- return; |
- } |
- |
- if (buffer.get() == NULL) { |
- LOG(ERROR) << "Error reading translated nexe"; |
- return; |
- } |
- pending_backend_operations_++; |
- disk_cache_->StoreNexe(it->second.cache_key, |
- buffer, |
- base::Bind(&PnaclHost::OnTranslatedNexeStored, |
- weak_factory_.GetWeakPtr(), |
- it->first)); |
-} |
- |
-// After we know the nexe has been stored, we can clean up, and unblock any |
-// outstanding requests for the same file. |
-// (Bound callbacks must re-lookup the TranslationID because the translation |
-// could be cancelled before they get called). |
-void PnaclHost::OnTranslatedNexeStored(const TranslationID& id, int net_error) { |
- PendingTranslationMap::iterator entry(pending_translations_.find(id)); |
- pending_backend_operations_--; |
- if (entry == pending_translations_.end()) { |
- // If the renderer closed while we were storing the nexe, we land here. |
- // Make sure we try to de-init. |
- DeInitIfSafe(); |
- return; |
- } |
- std::string key(entry->second.cache_key); |
- pending_translations_.erase(entry); |
- RequeryMatchingTranslations(key); |
-} |
- |
-// Check if any pending translations match |key|. If so, re-issue the cache |
-// query. In the overlapped miss case, we expect a hit this time, but a miss |
-// is also possible in case of an error. |
-void PnaclHost::RequeryMatchingTranslations(const std::string& key) { |
- // Check for outstanding misses to this same file |
- for (PendingTranslationMap::iterator it = pending_translations_.begin(); |
- it != pending_translations_.end(); |
- ++it) { |
- if (it->second.cache_key == key) { |
- // Re-send the cache read request. This time we expect a hit, but if |
- // something goes wrong, it will just handle it like a miss. |
- it->second.got_cache_reply = false; |
- pending_backend_operations_++; |
- disk_cache_->GetNexe(key, |
- base::Bind(&PnaclHost::OnCacheQueryReturn, |
- weak_factory_.GetWeakPtr(), |
- it->first)); |
- } |
- } |
-} |
- |
-//////////////////// GetNexeFd hit path |
- |
-// static |
-int PnaclHost::CopyBufferToFile(base::PlatformFile fd, |
- scoped_refptr<net::DrainableIOBuffer> buffer) { |
- int rv = base::WritePlatformFile(fd, 0, buffer->data(), buffer->size()); |
- if (rv == -1) |
- PLOG(ERROR) << "CopyBufferToFile write error"; |
- return rv; |
-} |
- |
-void PnaclHost::OnBufferCopiedToTempFile(const TranslationID& id, |
- int file_error) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- PendingTranslationMap::iterator entry(pending_translations_.find(id)); |
- if (entry == pending_translations_.end()) { |
- return; |
- } |
- if (file_error == -1) { |
- // Write error on the temp file. Request a new file and start over. |
- BrowserThread::PostBlockingPoolTask( |
- FROM_HERE, |
- base::Bind(base::IgnoreResult(base::ClosePlatformFile), |
- entry->second.nexe_fd)); |
- entry->second.got_nexe_fd = false; |
- CreateTemporaryFile(base::Bind(&PnaclHost::OnTempFileReturn, |
- weak_factory_.GetWeakPtr(), |
- entry->first)); |
- return; |
- } |
- base::PlatformFile fd = entry->second.nexe_fd; |
- entry->second.callback.Run(fd, true); |
- BrowserThread::PostBlockingPoolTask( |
- FROM_HERE, base::Bind(base::IgnoreResult(base::ClosePlatformFile), fd)); |
- pending_translations_.erase(entry); |
-} |
- |
-/////////////////// |
- |
-void PnaclHost::RendererClosing(int render_process_id) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- if (cache_state_ != CacheReady) |
- return; |
- for (PendingTranslationMap::iterator it = pending_translations_.begin(); |
- it != pending_translations_.end();) { |
- PendingTranslationMap::iterator to_erase(it++); |
- if (to_erase->first.first == render_process_id) { |
- // Clean up the open files. |
- BrowserThread::PostBlockingPoolTask( |
- FROM_HERE, |
- base::Bind(base::IgnoreResult(base::ClosePlatformFile), |
- to_erase->second.nexe_fd)); |
- std::string key(to_erase->second.cache_key); |
- bool may_be_cached = TranslationMayBeCached(to_erase); |
- pending_translations_.erase(to_erase); |
- // No translations will be waiting for entries that will not be stored. |
- if (may_be_cached) |
- RequeryMatchingTranslations(key); |
- } |
- } |
- BrowserThread::PostTask( |
- BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr())); |
-} |
- |
-////////////////// Cache data removal |
-void PnaclHost::ClearTranslationCacheEntriesBetween( |
- base::Time initial_time, |
- base::Time end_time, |
- const base::Closure& callback) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- if (cache_state_ == CacheUninitialized) { |
- Init(); |
- } |
- if (cache_state_ == CacheInitializing) { |
- // If the backend hasn't yet initialized, try the request again later. |
- BrowserThread::PostDelayedTask( |
- BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&PnaclHost::ClearTranslationCacheEntriesBetween, |
- weak_factory_.GetWeakPtr(), |
- initial_time, |
- end_time, |
- callback), |
- base::TimeDelta::FromMilliseconds( |
- kTranslationCacheInitializationDelayMs)); |
- return; |
- } |
- pending_backend_operations_++; |
- int rv = disk_cache_->DoomEntriesBetween( |
- initial_time, |
- end_time, |
- base::Bind( |
- &PnaclHost::OnEntriesDoomed, weak_factory_.GetWeakPtr(), callback)); |
- if (rv != net::ERR_IO_PENDING) |
- OnEntriesDoomed(callback, rv); |
-} |
- |
-void PnaclHost::OnEntriesDoomed(const base::Closure& callback, int net_error) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback); |
- pending_backend_operations_--; |
- // When clearing the cache, the UI is blocked on all the cache-clearing |
- // operations, and freeing the backend actually blocks the IO thread. So |
- // instead of calling DeInitIfSafe directly, post it for later. |
- BrowserThread::PostTask( |
- BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr())); |
-} |
- |
-// Destroying the cache backend causes it to post tasks to the cache thread to |
-// flush to disk. Because PnaclHost is a singleton, it does not get destroyed |
-// until all the browser threads have gone away and it's too late to post |
-// anything (attempting to do so hangs shutdown). So we make sure to destroy it |
-// when we no longer have any outstanding operations that need it. These include |
-// pending translations, cache clear requests, and requests to read or write |
-// translated nexes. We check when renderers close, when cache clear requests |
-// finish, and when backend operations complete. |
- |
-// It is not safe to delete the backend while it is initializing, nor if it has |
-// outstanding entry open requests; it is in theory safe to delete it with |
-// outstanding read/write requests, but because that distinction is hidden |
-// inside PnaclTranslationCache, we do not delete the backend if there are any |
-// backend requests in flight. As a last resort in the destructor, we just leak |
-// the backend to avoid hanging shutdown. |
-void PnaclHost::DeInitIfSafe() { |
- DCHECK(pending_backend_operations_ >= 0); |
- if (pending_translations_.empty() && pending_backend_operations_ <= 0) { |
- cache_state_ = CacheUninitialized; |
- disk_cache_.reset(); |
- } |
-} |