1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file.
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/nacl/browser/pnacl_host.h"
6ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/bind.h"
8ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/bind_helpers.h"
9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/files/file_path.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/logging.h"
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/task_runner_util.h"
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/threading/sequenced_worker_pool.h"
140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "components/nacl/browser/nacl_browser.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/nacl/browser/pnacl_translation_cache.h"
16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "content/public/browser/browser_thread.h"
17ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "net/base/io_buffer.h"
18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "net/base/net_errors.h"
19ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
20ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochusing content::BrowserThread;
21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace {
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic const base::FilePath::CharType kTranslationCacheDirectoryName[] =
25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    FILE_PATH_LITERAL("PnaclTranslationCache");
26ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Delay to wait for initialization of the cache backend
27ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochstatic const int kTranslationCacheInitializationDelayMs = 20;
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void CloseBaseFile(base::File auto_file_closer) {
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void CloseScopedFile(scoped_ptr<base::File> auto_file_closer) {
33ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
34ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace pnacl {
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class FileProxy {
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public:
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  FileProxy(scoped_ptr<base::File> file, base::WeakPtr<pnacl::PnaclHost> host);
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  int Write(scoped_refptr<net::DrainableIOBuffer> buffer);
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void WriteDone(const PnaclHost::TranslationID& id, int result);
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) private:
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<base::File> file_;
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::WeakPtr<pnacl::PnaclHost> host_;
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)FileProxy::FileProxy(scoped_ptr<base::File> file,
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     base::WeakPtr<pnacl::PnaclHost> host)
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : file_(file.Pass()),
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      host_(host) {
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)int FileProxy::Write(scoped_refptr<net::DrainableIOBuffer> buffer) {
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  int rv = file_->Write(0, buffer->data(), buffer->size());
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (rv == -1)
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    PLOG(ERROR) << "FileProxy::Write error";
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return rv;
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void FileProxy::WriteDone(const PnaclHost::TranslationID& id, int result) {
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (host_) {
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    host_->OnBufferCopiedToTempFile(id, file_.Pass(), result);
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  } else {
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    BrowserThread::PostBlockingPoolTask(
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        FROM_HERE,
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        base::Bind(CloseScopedFile, Passed(&file_)));
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
73ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochPnaclHost::PnaclHost()
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    : pending_backend_operations_(0),
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      cache_state_(CacheUninitialized),
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      weak_factory_(this) {}
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)PnaclHost::~PnaclHost() {
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // When PnaclHost is destroyed, it's too late to post anything to the cache
801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // thread (it will hang shutdown). So just leak the cache backend.
811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  pnacl::PnaclTranslationCache* cache = disk_cache_.release();
821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  (void)cache;
831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
84ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)PnaclHost* PnaclHost::GetInstance() {
8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return Singleton<PnaclHost>::get();
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
88ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
89ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochPnaclHost::PendingTranslation::PendingTranslation()
90ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    : process_handle(base::kNullProcessHandle),
91ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      render_view_id(0),
9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      nexe_fd(NULL),
93ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      got_nexe_fd(false),
94ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      got_cache_reply(false),
95ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      got_cache_hit(false),
96ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      is_incognito(false),
97ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      callback(NexeFdCallback()),
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      cache_info(nacl::PnaclCacheInfo()) {
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)PnaclHost::PendingTranslation::~PendingTranslation() {
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (nexe_fd)
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    delete nexe_fd;
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
105ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool PnaclHost::TranslationMayBeCached(
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const PendingTranslationMap::iterator& entry) {
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return !entry->second.is_incognito &&
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)         !entry->second.cache_info.has_no_store_header;
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/////////////////////////////////////// Initialization
113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic base::FilePath GetCachePath() {
1150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  NaClBrowserDelegate* browser_delegate = nacl::NaClBrowser::GetDelegate();
116ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Determine where the translation cache resides in the file system.  It
117ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // exists in Chrome's cache directory and is not tied to any specific
118ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // profile. If we fail, return an empty path.
119ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Start by finding the user data directory.
120ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::FilePath user_data_dir;
121ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!browser_delegate ||
122ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      !browser_delegate->GetUserDirectory(&user_data_dir)) {
123ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return base::FilePath();
124ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
125ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // The cache directory may or may not be the user data directory.
126ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::FilePath cache_file_path;
127ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  browser_delegate->GetCacheDirectory(&cache_file_path);
128ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Append the base file name to the cache directory.
130ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return cache_file_path.Append(kTranslationCacheDirectoryName);
131ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
133ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::OnCacheInitialized(int net_error) {
134ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
135ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // If the cache was cleared before the load completed, ignore.
136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (cache_state_ == CacheReady)
137ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
138ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (net_error != net::OK) {
139ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // This will cause the cache to attempt to re-init on the next call to
140ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // GetNexeFd.
141ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    cache_state_ = CacheUninitialized;
142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else {
143ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    cache_state_ = CacheReady;
144ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
145ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
147ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid PnaclHost::Init() {
148ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Extra check that we're on the real IO thread since this version of
149ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Init isn't used in unit tests.
150ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::FilePath cache_path(GetCachePath());
153ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (cache_path.empty() || cache_state_ != CacheUninitialized)
154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  disk_cache_.reset(new pnacl::PnaclTranslationCache());
156ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  cache_state_ = CacheInitializing;
1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  int rv = disk_cache_->InitOnDisk(
158ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      cache_path,
159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (rv != net::ERR_IO_PENDING)
1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    OnCacheInitialized(rv);
162ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
163ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Initialize for testing, optionally using the in-memory backend, and manually
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// setting the temporary file directory instead of using the system directory.
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PnaclHost::InitForTest(base::FilePath temp_dir, bool in_memory) {
167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
168ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  disk_cache_.reset(new pnacl::PnaclTranslationCache());
169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  cache_state_ = CacheInitializing;
170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  temp_dir_ = temp_dir;
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int rv;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (in_memory) {
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    rv = disk_cache_->InitInMemory(
174ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    rv = disk_cache_->InitOnDisk(
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      temp_dir,
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (rv != net::ERR_IO_PENDING)
1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    OnCacheInitialized(rv);
182ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
183ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
184ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch///////////////////////////////////////// Temp files
185ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
186ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Create a temporary file on the blocking pool
187ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// static
188424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void PnaclHost::DoCreateTemporaryFile(base::FilePath temp_dir,
189424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                      TempFileCallback cb) {
190ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
191ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
192ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::FilePath file_path;
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::File file;
194ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool rv = temp_dir.empty()
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                ? base::CreateTemporaryFile(&file_path)
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                : base::CreateTemporaryFileInDir(temp_dir, &file_path);
197ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!rv) {
1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    PLOG(ERROR) << "Temp file creation failed.";
199424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  } else {
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    file.Initialize(
201424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        file_path,
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_READ |
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            base::File::FLAG_WRITE | base::File::FLAG_TEMPORARY |
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            base::File::FLAG_DELETE_ON_CLOSE);
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!file.IsValid())
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      PLOG(ERROR) << "Temp file open failed: " << file.error_details();
208ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
209424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  BrowserThread::PostTask(
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      BrowserThread::IO, FROM_HERE, base::Bind(cb, Passed(file.Pass())));
211ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
212ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
213ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::CreateTemporaryFile(TempFileCallback cb) {
214424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!BrowserThread::PostBlockingPoolSequencedTask(
215424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)           "PnaclHostCreateTempFile",
216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)           FROM_HERE,
217424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)           base::Bind(&PnaclHost::DoCreateTemporaryFile, temp_dir_, cb))) {
218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK(thread_checker_.CalledOnValidThread());
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    cb.Run(base::File());
220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
221ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
222ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
223ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch///////////////////////////////////////// GetNexeFd implementation
224ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch////////////////////// Common steps
225ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
226ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid PnaclHost::GetNexeFd(int render_process_id,
227ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                          int render_view_id,
228ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                          int pp_instance,
229ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                          bool is_incognito,
230ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                          const nacl::PnaclCacheInfo& cache_info,
231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                          const NexeFdCallback& cb) {
232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
233ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (cache_state_ == CacheUninitialized) {
234ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    Init();
235ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (cache_state_ != CacheReady) {
237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If the backend hasn't yet initialized, try the request again later.
238ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    BrowserThread::PostDelayedTask(BrowserThread::IO,
239ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                   FROM_HERE,
240ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                   base::Bind(&PnaclHost::GetNexeFd,
241ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              weak_factory_.GetWeakPtr(),
242ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              render_process_id,
243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              render_view_id,
244ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              pp_instance,
245ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              is_incognito,
246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              cache_info,
247ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              cb),
248ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                   base::TimeDelta::FromMilliseconds(
249ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                       kTranslationCacheInitializationDelayMs));
250ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
251ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
252ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
253ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  TranslationID id(render_process_id, pp_instance);
254ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslationMap::iterator entry = pending_translations_.find(id);
255ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (entry != pending_translations_.end()) {
256ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // Existing translation must have been abandonded. Clean it up.
2573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "GetNexeFd for already-pending translation";
258ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    pending_translations_.erase(entry);
259ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
260ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
261ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::string cache_key(disk_cache_->GetKey(cache_info));
262ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (cache_key.empty()) {
2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "GetNexeFd: Invalid cache info";
26446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    cb.Run(base::File(), false);
265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
266ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
267ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
268ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  PendingTranslation pt;
269ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pt.render_view_id = render_view_id;
270ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pt.callback = cb;
271ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pt.cache_info = cache_info;
272ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  pt.cache_key = cache_key;
273ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  pt.is_incognito = is_incognito;
274ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  pending_translations_[id] = pt;
275ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  SendCacheQueryAndTempFileRequest(cache_key, id);
276ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
277ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
278ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Dispatch the cache read request and the temp file creation request
279ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// simultaneously; currently we need a temp file regardless of whether the
280ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// request hits.
281ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::SendCacheQueryAndTempFileRequest(const std::string& cache_key,
282ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                                 const TranslationID& id) {
2831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  pending_backend_operations_++;
284ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  disk_cache_->GetNexe(
285ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      cache_key,
286ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(
287ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          &PnaclHost::OnCacheQueryReturn, weak_factory_.GetWeakPtr(), id));
288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CreateTemporaryFile(
290ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&PnaclHost::OnTempFileReturn, weak_factory_.GetWeakPtr(), id));
291ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
292ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
293ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Callback from the translation cache query. |id| is bound from
294ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// SendCacheQueryAndTempFileRequest, |net_error| is a net::Error code (which for
295ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// our purposes means a hit if it's net::OK (i.e. 0). |buffer| is allocated
296ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// by PnaclTranslationCache and now belongs to PnaclHost.
297ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// (Bound callbacks must re-lookup the TranslationID because the translation
298ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// could be cancelled before they get called).
299ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::OnCacheQueryReturn(
300ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const TranslationID& id,
301ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    int net_error,
302ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    scoped_refptr<net::DrainableIOBuffer> buffer) {
303ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  pending_backend_operations_--;
305ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslationMap::iterator entry(pending_translations_.find(id));
306ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (entry == pending_translations_.end()) {
3073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "OnCacheQueryReturn: id not found";
3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DeInitIfSafe();
309ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
310ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
311ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslation* pt = &entry->second;
312ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  pt->got_cache_reply = true;
313ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  pt->got_cache_hit = (net_error == net::OK);
314ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (pt->got_cache_hit)
315ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    pt->nexe_read_buffer = buffer;
316ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  CheckCacheQueryReady(entry);
317ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
318ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
319ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Callback from temp file creation. |id| is bound from
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// SendCacheQueryAndTempFileRequest, and |file| is the created file.
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// If there was an error, file is invalid.
322ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// (Bound callbacks must re-lookup the TranslationID because the translation
323ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// could be cancelled before they get called).
324ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::OnTempFileReturn(const TranslationID& id,
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 base::File file) {
326ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
327ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslationMap::iterator entry(pending_translations_.find(id));
328ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (entry == pending_translations_.end()) {
329ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // The renderer may have signaled an error or closed while the temp
330ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // file was being created.
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "OnTempFileReturn: id not found";
332ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    BrowserThread::PostBlockingPoolTask(
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE, base::Bind(CloseBaseFile, Passed(file.Pass())));
334ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
335ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!file.IsValid()) {
337ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // This translation will fail, but we need to retry any translation
338ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // waiting for its result.
3393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "OnTempFileReturn: temp file creation failed";
340ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    std::string key(entry->second.cache_key);
34146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    entry->second.callback.Run(base::File(), false);
34258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    bool may_be_cached = TranslationMayBeCached(entry);
343ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    pending_translations_.erase(entry);
34458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // No translations will be waiting for entries that will not be stored.
34558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (may_be_cached)
346ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      RequeryMatchingTranslations(key);
347ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
348ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
349ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslation* pt = &entry->second;
350ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  pt->got_nexe_fd = true;
35146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  pt->nexe_fd = new base::File(file.Pass());
352ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  CheckCacheQueryReady(entry);
353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
355ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Check whether both the cache query and the temp file have returned, and check
356ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// whether we actually got a hit or not.
357ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::CheckCacheQueryReady(
358ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const PendingTranslationMap::iterator& entry) {
359ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslation* pt = &entry->second;
360ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!(pt->got_cache_reply && pt->got_nexe_fd))
361ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
362ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!pt->got_cache_hit) {
363ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // Check if there is already a pending translation for this file. If there
364ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // is, we will wait for it to come back, to avoid redundant translations.
365ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    for (PendingTranslationMap::iterator it = pending_translations_.begin();
366ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch         it != pending_translations_.end();
367ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch         ++it) {
368ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      // Another translation matches if it's a request for the same file,
369ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      if (it->second.cache_key == entry->second.cache_key &&
370ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          // and it's not this translation,
371ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          it->first != entry->first &&
37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          // and it can be stored in the cache,
37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          TranslationMayBeCached(it) &&
37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          // and it's already gotten past this check and returned the miss.
375ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          it->second.got_cache_reply &&
376ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          it->second.got_nexe_fd) {
377ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        return;
378ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      }
379ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
380ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    ReturnMiss(entry);
381ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
382ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
383ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
38446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<base::File> file(pt->nexe_fd);
38546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  pt->nexe_fd = NULL;
38646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  pt->got_nexe_fd = false;
38746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  FileProxy* proxy(new FileProxy(file.Pass(), weak_factory_.GetWeakPtr()));
38846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
389ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!base::PostTaskAndReplyWithResult(
390424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)           BrowserThread::GetBlockingPool(),
391424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)           FROM_HERE,
39246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)           base::Bind(&FileProxy::Write, base::Unretained(proxy),
39346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      pt->nexe_read_buffer),
39446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)           base::Bind(&FileProxy::WriteDone, base::Owned(proxy),
395424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                      entry->first))) {
39646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    pt->callback.Run(base::File(), false);
397ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
398ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
399ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
400ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch//////////////////// GetNexeFd miss path
401ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Return the temp fd to the renderer, reporting a miss.
402ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::ReturnMiss(const PendingTranslationMap::iterator& entry) {
403ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Return the fd
404ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslation* pt = &entry->second;
405ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NexeFdCallback cb(pt->callback);
40646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  cb.Run(*pt->nexe_fd, false);
40746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!pt->nexe_fd->IsValid()) {
40846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // Bad FD is unrecoverable, so clear out the entry.
409ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    pending_translations_.erase(entry);
410ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
411ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
412ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
413ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// On error, just return a null refptr.
414ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// static
415ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochscoped_refptr<net::DrainableIOBuffer> PnaclHost::CopyFileToBuffer(
41646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_ptr<base::File> file) {
41746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::File::Info info;
418ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_refptr<net::DrainableIOBuffer> buffer;
419ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool error = false;
42046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!file->GetInfo(&info) ||
421ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      info.size >= std::numeric_limits<int>::max()) {
42246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    PLOG(ERROR) << "File::GetInfo failed";
423ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    error = true;
424ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  } else {
425ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    buffer = new net::DrainableIOBuffer(
426ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        new net::IOBuffer(static_cast<int>(info.size)), info.size);
42746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (file->Read(0, buffer->data(), buffer->size()) != info.size) {
4283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      PLOG(ERROR) << "CopyFileToBuffer file read failed";
429ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      error = true;
430ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
431ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
432ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (error) {
433ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    buffer = NULL;
434ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
435ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  return buffer;
436ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
437ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
438ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Called by the renderer in the miss path to report a finished translation
439bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid PnaclHost::TranslationFinished(int render_process_id,
440bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                                    int pp_instance,
441bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                                    bool success) {
442ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
443ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (cache_state_ != CacheReady)
444ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
445ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  TranslationID id(render_process_id, pp_instance);
446ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslationMap::iterator entry(pending_translations_.find(id));
447ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (entry == pending_translations_.end()) {
448ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    LOG(ERROR) << "TranslationFinished: TranslationID " << render_process_id
449ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch               << "," << pp_instance << " not found.";
450ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
451ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
452ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool store_nexe = true;
453ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // If this is a premature response (i.e. we haven't returned a temp file
454ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // yet) or if it's an unsuccessful translation, or if we are incognito,
455ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // don't store in the cache.
456ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // TODO(dschuff): use a separate in-memory cache for incognito
457ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // translations.
458ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!entry->second.got_nexe_fd || !entry->second.got_cache_reply ||
45958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      !success || !TranslationMayBeCached(entry)) {
460ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    store_nexe = false;
46146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  } else {
46246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_ptr<base::File> file(entry->second.nexe_fd);
46346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    entry->second.nexe_fd = NULL;
46446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    entry->second.got_nexe_fd = false;
46546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
46646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!base::PostTaskAndReplyWithResult(
46746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             BrowserThread::GetBlockingPool(),
46846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             FROM_HERE,
46946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             base::Bind(&PnaclHost::CopyFileToBuffer, Passed(&file)),
47046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)             base::Bind(&PnaclHost::StoreTranslatedNexe,
47146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        weak_factory_.GetWeakPtr(),
47246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        id))) {
47346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      store_nexe = false;
47446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
475ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
476ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
477ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!store_nexe) {
478ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If store_nexe is true, the fd will be closed by CopyFileToBuffer.
479ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (entry->second.got_nexe_fd) {
48046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<base::File> file(entry->second.nexe_fd);
48146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      entry->second.nexe_fd = NULL;
482ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      BrowserThread::PostBlockingPoolTask(
483ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          FROM_HERE,
48446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          base::Bind(CloseScopedFile, Passed(&file)));
485ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
486ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    pending_translations_.erase(entry);
487ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
488ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
489ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
490ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Store the translated nexe in the translation cache. Called back with the
491ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// TranslationID from the host and the result of CopyFileToBuffer.
492ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// (Bound callbacks must re-lookup the TranslationID because the translation
493ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// could be cancelled before they get called).
494ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::StoreTranslatedNexe(
495ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    TranslationID id,
496ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    scoped_refptr<net::DrainableIOBuffer> buffer) {
497ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
498ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (cache_state_ != CacheReady)
499ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
500ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslationMap::iterator it(pending_translations_.find(id));
501ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (it == pending_translations_.end()) {
502ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    LOG(ERROR) << "StoreTranslatedNexe: TranslationID " << id.first << ","
503ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch               << id.second << " not found.";
504ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
505ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
506ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
507ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (buffer.get() == NULL) {
508ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    LOG(ERROR) << "Error reading translated nexe";
509ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
510ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
5111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  pending_backend_operations_++;
512ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  disk_cache_->StoreNexe(it->second.cache_key,
5131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         buffer.get(),
514ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                         base::Bind(&PnaclHost::OnTranslatedNexeStored,
515ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                    weak_factory_.GetWeakPtr(),
516ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                    it->first));
517ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
518ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
519ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// After we know the nexe has been stored, we can clean up, and unblock any
520ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// outstanding requests for the same file.
521ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// (Bound callbacks must re-lookup the TranslationID because the translation
522ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// could be cancelled before they get called).
523ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::OnTranslatedNexeStored(const TranslationID& id, int net_error) {
524ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslationMap::iterator entry(pending_translations_.find(id));
5251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  pending_backend_operations_--;
526ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (entry == pending_translations_.end()) {
5271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // If the renderer closed while we were storing the nexe, we land here.
5281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Make sure we try to de-init.
5291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DeInitIfSafe();
530ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
531ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
532ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::string key(entry->second.cache_key);
533ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  pending_translations_.erase(entry);
534ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  RequeryMatchingTranslations(key);
535ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
536ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
537ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Check if any pending translations match |key|. If so, re-issue the cache
538ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// query. In the overlapped miss case, we expect a hit this time, but a miss
539ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// is also possible in case of an error.
540ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::RequeryMatchingTranslations(const std::string& key) {
541ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Check for outstanding misses to this same file
542ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (PendingTranslationMap::iterator it = pending_translations_.begin();
543ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch       it != pending_translations_.end();
544ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch       ++it) {
545ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (it->second.cache_key == key) {
546ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      // Re-send the cache read request. This time we expect a hit, but if
547ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      // something goes wrong, it will just handle it like a miss.
548ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      it->second.got_cache_reply = false;
5491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      pending_backend_operations_++;
550ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      disk_cache_->GetNexe(key,
551ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                           base::Bind(&PnaclHost::OnCacheQueryReturn,
552ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                      weak_factory_.GetWeakPtr(),
553ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                      it->first));
554ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
555ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
556ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
557ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
558ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch//////////////////// GetNexeFd hit path
559ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
560ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::OnBufferCopiedToTempFile(const TranslationID& id,
56146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                         scoped_ptr<base::File> file,
562ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                         int file_error) {
563ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
564ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PendingTranslationMap::iterator entry(pending_translations_.find(id));
565ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (entry == pending_translations_.end()) {
56646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    BrowserThread::PostBlockingPoolTask(
56746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        FROM_HERE,
56846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        base::Bind(CloseScopedFile, Passed(&file)));
569ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
570ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
571ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (file_error == -1) {
572ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // Write error on the temp file. Request a new file and start over.
573ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    BrowserThread::PostBlockingPoolTask(
574ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        FROM_HERE,
57546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        base::Bind(CloseScopedFile, Passed(&file)));
576ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    CreateTemporaryFile(base::Bind(&PnaclHost::OnTempFileReturn,
577ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                   weak_factory_.GetWeakPtr(),
578ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                   entry->first));
579ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
580ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
58146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  entry->second.callback.Run(*file.get(), true);
582ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  BrowserThread::PostBlockingPoolTask(
58346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      FROM_HERE,
58446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(CloseScopedFile, Passed(&file)));
585ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  pending_translations_.erase(entry);
586ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
587ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
588ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch///////////////////
589ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
590ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::RendererClosing(int render_process_id) {
591ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
592ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (cache_state_ != CacheReady)
593ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
594ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  for (PendingTranslationMap::iterator it = pending_translations_.begin();
595ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       it != pending_translations_.end();) {
596ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    PendingTranslationMap::iterator to_erase(it++);
597ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (to_erase->first.first == render_process_id) {
598ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      // Clean up the open files.
59946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<base::File> file(to_erase->second.nexe_fd);
60046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      to_erase->second.nexe_fd = NULL;
601ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      BrowserThread::PostBlockingPoolTask(
602ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          FROM_HERE,
60346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          base::Bind(CloseScopedFile, Passed(&file)));
604ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      std::string key(to_erase->second.cache_key);
60558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      bool may_be_cached = TranslationMayBeCached(to_erase);
606ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      pending_translations_.erase(to_erase);
60758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // No translations will be waiting for entries that will not be stored.
60858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (may_be_cached)
609ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        RequeryMatchingTranslations(key);
610ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
611ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
6121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserThread::PostTask(
6131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserThread::IO,
6141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
6151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr()));
616ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
617ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
618ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch////////////////// Cache data removal
619ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::ClearTranslationCacheEntriesBetween(
620ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    base::Time initial_time,
621ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    base::Time end_time,
622ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const base::Closure& callback) {
623ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
624ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (cache_state_ == CacheUninitialized) {
625ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    Init();
626ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
627ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (cache_state_ == CacheInitializing) {
628ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // If the backend hasn't yet initialized, try the request again later.
629ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    BrowserThread::PostDelayedTask(
630ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        BrowserThread::IO,
631ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        FROM_HERE,
632ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        base::Bind(&PnaclHost::ClearTranslationCacheEntriesBetween,
633ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                   weak_factory_.GetWeakPtr(),
634ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                   initial_time,
635ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                   end_time,
636ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                   callback),
637ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        base::TimeDelta::FromMilliseconds(
638ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            kTranslationCacheInitializationDelayMs));
639ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
640ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
6411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  pending_backend_operations_++;
642ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int rv = disk_cache_->DoomEntriesBetween(
643ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      initial_time,
644ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      end_time,
6451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(
6461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          &PnaclHost::OnEntriesDoomed, weak_factory_.GetWeakPtr(), callback));
647ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (rv != net::ERR_IO_PENDING)
648ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    OnEntriesDoomed(callback, rv);
649ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
650ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
651ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PnaclHost::OnEntriesDoomed(const base::Closure& callback, int net_error) {
6521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
653ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback);
6541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  pending_backend_operations_--;
6551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // When clearing the cache, the UI is blocked on all the cache-clearing
6561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // operations, and freeing the backend actually blocks the IO thread. So
6571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // instead of calling DeInitIfSafe directly, post it for later.
6581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserThread::PostTask(
6591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      BrowserThread::IO,
6601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
6611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr()));
6621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
6631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
6641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Destroying the cache backend causes it to post tasks to the cache thread to
6651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// flush to disk. Because PnaclHost is a singleton, it does not get destroyed
6661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// until all the browser threads have gone away and it's too late to post
6671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// anything (attempting to do so hangs shutdown).  So we make sure to destroy it
6681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// when we no longer have any outstanding operations that need it. These include
6691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// pending translations, cache clear requests, and requests to read or write
6701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// translated nexes.  We check when renderers close, when cache clear requests
6711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// finish, and when backend operations complete.
6721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
6731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// It is not safe to delete the backend while it is initializing, nor if it has
6741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// outstanding entry open requests; it is in theory safe to delete it with
6751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// outstanding read/write requests, but because that distinction is hidden
6761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// inside PnaclTranslationCache, we do not delete the backend if there are any
6771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// backend requests in flight.  As a last resort in the destructor, we just leak
6781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// the backend to avoid hanging shutdown.
6791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void PnaclHost::DeInitIfSafe() {
6801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(pending_backend_operations_ >= 0);
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pending_translations_.empty() &&
6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pending_backend_operations_ <= 0 &&
6835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      cache_state_ == CacheReady) {
6841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    cache_state_ = CacheUninitialized;
6851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    disk_cache_.reset();
6861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
687ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
688f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
689f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace pnacl
690