| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/nacl/browser/pnacl_host.h" | 5 #include "components/nacl/browser/pnacl_host.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 11 #include "base/debug/leak_annotations.h" |
| 11 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 12 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
| 13 #include "base/logging.h" | 14 #include "base/logging.h" |
| 14 #include "base/numerics/safe_math.h" | 15 #include "base/numerics/safe_math.h" |
| 15 #include "base/task_runner_util.h" | 16 #include "base/task_runner_util.h" |
| 16 #include "base/threading/sequenced_worker_pool.h" | 17 #include "base/threading/sequenced_worker_pool.h" |
| 17 #include "components/nacl/browser/nacl_browser.h" | 18 #include "components/nacl/browser/nacl_browser.h" |
| 18 #include "components/nacl/browser/pnacl_translation_cache.h" | 19 #include "components/nacl/browser/pnacl_translation_cache.h" |
| 19 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
| 20 #include "net/base/io_buffer.h" | 21 #include "net/base/io_buffer.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 33 } | 34 } |
| 34 | 35 |
| 35 void CloseScopedFile(std::unique_ptr<base::File> auto_file_closer) {} | 36 void CloseScopedFile(std::unique_ptr<base::File> auto_file_closer) {} |
| 36 | 37 |
| 37 } // namespace | 38 } // namespace |
| 38 | 39 |
| 39 namespace pnacl { | 40 namespace pnacl { |
| 40 | 41 |
| 41 class FileProxy { | 42 class FileProxy { |
| 42 public: | 43 public: |
| 43 FileProxy(std::unique_ptr<base::File> file, | 44 FileProxy(std::unique_ptr<base::File> file, PnaclHost* host); |
| 44 base::WeakPtr<pnacl::PnaclHost> host); | |
| 45 int Write(scoped_refptr<net::DrainableIOBuffer> buffer); | 45 int Write(scoped_refptr<net::DrainableIOBuffer> buffer); |
| 46 void WriteDone(const PnaclHost::TranslationID& id, int result); | 46 void WriteDone(const PnaclHost::TranslationID& id, int result); |
| 47 | 47 |
| 48 private: | 48 private: |
| 49 std::unique_ptr<base::File> file_; | 49 std::unique_ptr<base::File> file_; |
| 50 base::WeakPtr<pnacl::PnaclHost> host_; | 50 PnaclHost* host_; |
| 51 }; | 51 }; |
| 52 | 52 |
| 53 FileProxy::FileProxy(std::unique_ptr<base::File> file, | 53 FileProxy::FileProxy(std::unique_ptr<base::File> file, PnaclHost* host) |
| 54 base::WeakPtr<pnacl::PnaclHost> host) | |
| 55 : file_(std::move(file)), host_(host) {} | 54 : file_(std::move(file)), host_(host) {} |
| 56 | 55 |
| 57 int FileProxy::Write(scoped_refptr<net::DrainableIOBuffer> buffer) { | 56 int FileProxy::Write(scoped_refptr<net::DrainableIOBuffer> buffer) { |
| 58 int rv = file_->Write(0, buffer->data(), buffer->size()); | 57 int rv = file_->Write(0, buffer->data(), buffer->size()); |
| 59 if (rv == -1) | 58 if (rv == -1) |
| 60 PLOG(ERROR) << "FileProxy::Write error"; | 59 PLOG(ERROR) << "FileProxy::Write error"; |
| 61 return rv; | 60 return rv; |
| 62 } | 61 } |
| 63 | 62 |
| 64 void FileProxy::WriteDone(const PnaclHost::TranslationID& id, int result) { | 63 void FileProxy::WriteDone(const PnaclHost::TranslationID& id, int result) { |
| 65 if (host_) { | 64 host_->OnBufferCopiedToTempFile(id, std::move(file_), result); |
| 66 host_->OnBufferCopiedToTempFile(id, std::move(file_), result); | |
| 67 } else { | |
| 68 BrowserThread::PostBlockingPoolTask( | |
| 69 FROM_HERE, | |
| 70 base::Bind(CloseScopedFile, Passed(&file_))); | |
| 71 } | |
| 72 } | 65 } |
| 73 | 66 |
| 74 PnaclHost::PnaclHost() | 67 PnaclHost::PnaclHost() = default; |
| 75 : pending_backend_operations_(0), | |
| 76 cache_state_(CacheUninitialized), | |
| 77 weak_factory_(this) {} | |
| 78 | |
| 79 PnaclHost::~PnaclHost() { | |
| 80 // When PnaclHost is destroyed, it's too late to post anything to the cache | |
| 81 // thread (it will hang shutdown). So just leak the cache backend. | |
| 82 pnacl::PnaclTranslationCache* cache = disk_cache_.release(); | |
| 83 (void)cache; | |
| 84 } | |
| 85 | 68 |
| 86 PnaclHost* PnaclHost::GetInstance() { | 69 PnaclHost* PnaclHost::GetInstance() { |
| 87 return base::Singleton<PnaclHost>::get(); | 70 static PnaclHost* instance = nullptr; |
| 71 if (!instance) { |
| 72 instance = new PnaclHost; |
| 73 ANNOTATE_LEAKING_OBJECT_PTR(instance); |
| 74 } |
| 75 return instance; |
| 88 } | 76 } |
| 89 | 77 |
| 90 PnaclHost::PendingTranslation::PendingTranslation() | 78 PnaclHost::PendingTranslation::PendingTranslation() |
| 91 : process_handle(base::kNullProcessHandle), | 79 : process_handle(base::kNullProcessHandle), |
| 92 render_view_id(0), | 80 render_view_id(0), |
| 93 nexe_fd(NULL), | 81 nexe_fd(NULL), |
| 94 got_nexe_fd(false), | 82 got_nexe_fd(false), |
| 95 got_cache_reply(false), | 83 got_cache_reply(false), |
| 96 got_cache_hit(false), | 84 got_cache_hit(false), |
| 97 is_incognito(false), | 85 is_incognito(false), |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 } | 137 } |
| 150 | 138 |
| 151 void PnaclHost::Init() { | 139 void PnaclHost::Init() { |
| 152 // Extra check that we're on the real IO thread since this version of | 140 // Extra check that we're on the real IO thread since this version of |
| 153 // Init isn't used in unit tests. | 141 // Init isn't used in unit tests. |
| 154 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 142 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 155 DCHECK(thread_checker_.CalledOnValidThread()); | 143 DCHECK(thread_checker_.CalledOnValidThread()); |
| 156 base::FilePath cache_path(GetCachePath()); | 144 base::FilePath cache_path(GetCachePath()); |
| 157 if (cache_path.empty() || cache_state_ != CacheUninitialized) | 145 if (cache_path.empty() || cache_state_ != CacheUninitialized) |
| 158 return; | 146 return; |
| 159 disk_cache_.reset(new pnacl::PnaclTranslationCache()); | 147 disk_cache_.reset(new PnaclTranslationCache()); |
| 160 cache_state_ = CacheInitializing; | 148 cache_state_ = CacheInitializing; |
| 161 int rv = disk_cache_->InitOnDisk( | 149 int rv = disk_cache_->InitOnDisk( |
| 162 cache_path, | 150 cache_path, |
| 163 base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr())); | 151 base::Bind(&PnaclHost::OnCacheInitialized, base::Unretained(this))); |
| 164 if (rv != net::ERR_IO_PENDING) | 152 if (rv != net::ERR_IO_PENDING) |
| 165 OnCacheInitialized(rv); | 153 OnCacheInitialized(rv); |
| 166 } | 154 } |
| 167 | 155 |
| 168 // Initialize for testing, optionally using the in-memory backend, and manually | 156 // Initialize for testing, optionally using the in-memory backend, and manually |
| 169 // setting the temporary file directory instead of using the system directory. | 157 // setting the temporary file directory instead of using the system directory. |
| 170 void PnaclHost::InitForTest(base::FilePath temp_dir, bool in_memory) { | 158 void PnaclHost::InitForTest(base::FilePath temp_dir, bool in_memory) { |
| 171 DCHECK(thread_checker_.CalledOnValidThread()); | 159 DCHECK(thread_checker_.CalledOnValidThread()); |
| 172 disk_cache_.reset(new pnacl::PnaclTranslationCache()); | 160 disk_cache_.reset(new PnaclTranslationCache()); |
| 173 cache_state_ = CacheInitializing; | 161 cache_state_ = CacheInitializing; |
| 174 temp_dir_ = temp_dir; | 162 temp_dir_ = temp_dir; |
| 175 int rv; | 163 int rv; |
| 176 if (in_memory) { | 164 if (in_memory) { |
| 177 rv = disk_cache_->InitInMemory( | 165 rv = disk_cache_->InitInMemory( |
| 178 base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr())); | 166 base::Bind(&PnaclHost::OnCacheInitialized, base::Unretained(this))); |
| 179 } else { | 167 } else { |
| 180 rv = disk_cache_->InitOnDisk( | 168 rv = disk_cache_->InitOnDisk( |
| 181 temp_dir, | 169 temp_dir, |
| 182 base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr())); | 170 base::Bind(&PnaclHost::OnCacheInitialized, base::Unretained(this))); |
| 183 } | 171 } |
| 184 if (rv != net::ERR_IO_PENDING) | 172 if (rv != net::ERR_IO_PENDING) |
| 185 OnCacheInitialized(rv); | 173 OnCacheInitialized(rv); |
| 186 } | 174 } |
| 187 | 175 |
| 188 ///////////////////////////////////////// Temp files | 176 ///////////////////////////////////////// Temp files |
| 189 | 177 |
| 190 // Create a temporary file on the blocking pool | 178 // Create a temporary file on the blocking pool |
| 191 // static | 179 // static |
| 192 void PnaclHost::DoCreateTemporaryFile(base::FilePath temp_dir, | 180 void PnaclHost::DoCreateTemporaryFile(base::FilePath temp_dir, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 const NexeFdCallback& cb) { | 223 const NexeFdCallback& cb) { |
| 236 DCHECK(thread_checker_.CalledOnValidThread()); | 224 DCHECK(thread_checker_.CalledOnValidThread()); |
| 237 if (cache_state_ == CacheUninitialized) { | 225 if (cache_state_ == CacheUninitialized) { |
| 238 Init(); | 226 Init(); |
| 239 } | 227 } |
| 240 if (cache_state_ != CacheReady) { | 228 if (cache_state_ != CacheReady) { |
| 241 // If the backend hasn't yet initialized, try the request again later. | 229 // If the backend hasn't yet initialized, try the request again later. |
| 242 BrowserThread::PostDelayedTask(BrowserThread::IO, | 230 BrowserThread::PostDelayedTask(BrowserThread::IO, |
| 243 FROM_HERE, | 231 FROM_HERE, |
| 244 base::Bind(&PnaclHost::GetNexeFd, | 232 base::Bind(&PnaclHost::GetNexeFd, |
| 245 weak_factory_.GetWeakPtr(), | 233 base::Unretained(this), |
| 246 render_process_id, | 234 render_process_id, |
| 247 render_view_id, | 235 render_view_id, |
| 248 pp_instance, | 236 pp_instance, |
| 249 is_incognito, | 237 is_incognito, |
| 250 cache_info, | 238 cache_info, |
| 251 cb), | 239 cb), |
| 252 base::TimeDelta::FromMilliseconds( | 240 base::TimeDelta::FromMilliseconds( |
| 253 kTranslationCacheInitializationDelayMs)); | 241 kTranslationCacheInitializationDelayMs)); |
| 254 return; | 242 return; |
| 255 } | 243 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 277 pt.is_incognito = is_incognito; | 265 pt.is_incognito = is_incognito; |
| 278 pending_translations_[id] = pt; | 266 pending_translations_[id] = pt; |
| 279 SendCacheQueryAndTempFileRequest(cache_key, id); | 267 SendCacheQueryAndTempFileRequest(cache_key, id); |
| 280 } | 268 } |
| 281 | 269 |
| 282 // Dispatch the cache read request and the temp file creation request | 270 // Dispatch the cache read request and the temp file creation request |
| 283 // simultaneously; currently we need a temp file regardless of whether the | 271 // simultaneously; currently we need a temp file regardless of whether the |
| 284 // request hits. | 272 // request hits. |
| 285 void PnaclHost::SendCacheQueryAndTempFileRequest(const std::string& cache_key, | 273 void PnaclHost::SendCacheQueryAndTempFileRequest(const std::string& cache_key, |
| 286 const TranslationID& id) { | 274 const TranslationID& id) { |
| 275 DCHECK(thread_checker_.CalledOnValidThread()); |
| 287 pending_backend_operations_++; | 276 pending_backend_operations_++; |
| 288 disk_cache_->GetNexe( | 277 disk_cache_->GetNexe(cache_key, base::Bind(&PnaclHost::OnCacheQueryReturn, |
| 289 cache_key, | 278 base::Unretained(this), id)); |
| 290 base::Bind( | |
| 291 &PnaclHost::OnCacheQueryReturn, weak_factory_.GetWeakPtr(), id)); | |
| 292 | 279 |
| 293 CreateTemporaryFile( | 280 CreateTemporaryFile( |
| 294 base::Bind(&PnaclHost::OnTempFileReturn, weak_factory_.GetWeakPtr(), id)); | 281 base::Bind(&PnaclHost::OnTempFileReturn, base::Unretained(this), id)); |
| 295 } | 282 } |
| 296 | 283 |
| 297 // Callback from the translation cache query. |id| is bound from | 284 // Callback from the translation cache query. |id| is bound from |
| 298 // SendCacheQueryAndTempFileRequest, |net_error| is a net::Error code (which for | 285 // SendCacheQueryAndTempFileRequest, |net_error| is a net::Error code (which for |
| 299 // our purposes means a hit if it's net::OK (i.e. 0). |buffer| is allocated | 286 // our purposes means a hit if it's net::OK (i.e. 0). |buffer| is allocated |
| 300 // by PnaclTranslationCache and now belongs to PnaclHost. | 287 // by PnaclTranslationCache and now belongs to PnaclHost. |
| 301 // (Bound callbacks must re-lookup the TranslationID because the translation | 288 // (Bound callbacks must re-lookup the TranslationID because the translation |
| 302 // could be cancelled before they get called). | 289 // could be cancelled before they get called). |
| 303 void PnaclHost::OnCacheQueryReturn( | 290 void PnaclHost::OnCacheQueryReturn( |
| 304 const TranslationID& id, | 291 const TranslationID& id, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 PendingTranslation* pt = &entry->second; | 340 PendingTranslation* pt = &entry->second; |
| 354 pt->got_nexe_fd = true; | 341 pt->got_nexe_fd = true; |
| 355 pt->nexe_fd = new base::File(std::move(file)); | 342 pt->nexe_fd = new base::File(std::move(file)); |
| 356 CheckCacheQueryReady(entry); | 343 CheckCacheQueryReady(entry); |
| 357 } | 344 } |
| 358 | 345 |
| 359 // Check whether both the cache query and the temp file have returned, and check | 346 // Check whether both the cache query and the temp file have returned, and check |
| 360 // whether we actually got a hit or not. | 347 // whether we actually got a hit or not. |
| 361 void PnaclHost::CheckCacheQueryReady( | 348 void PnaclHost::CheckCacheQueryReady( |
| 362 const PendingTranslationMap::iterator& entry) { | 349 const PendingTranslationMap::iterator& entry) { |
| 350 DCHECK(thread_checker_.CalledOnValidThread()); |
| 363 PendingTranslation* pt = &entry->second; | 351 PendingTranslation* pt = &entry->second; |
| 364 if (!(pt->got_cache_reply && pt->got_nexe_fd)) | 352 if (!(pt->got_cache_reply && pt->got_nexe_fd)) |
| 365 return; | 353 return; |
| 366 if (!pt->got_cache_hit) { | 354 if (!pt->got_cache_hit) { |
| 367 // Check if there is already a pending translation for this file. If there | 355 // Check if there is already a pending translation for this file. If there |
| 368 // is, we will wait for it to come back, to avoid redundant translations. | 356 // is, we will wait for it to come back, to avoid redundant translations. |
| 369 for (PendingTranslationMap::iterator it = pending_translations_.begin(); | 357 for (PendingTranslationMap::iterator it = pending_translations_.begin(); |
| 370 it != pending_translations_.end(); | 358 it != pending_translations_.end(); |
| 371 ++it) { | 359 ++it) { |
| 372 // Another translation matches if it's a request for the same file, | 360 // Another translation matches if it's a request for the same file, |
| 373 if (it->second.cache_key == entry->second.cache_key && | 361 if (it->second.cache_key == entry->second.cache_key && |
| 374 // and it's not this translation, | 362 // and it's not this translation, |
| 375 it->first != entry->first && | 363 it->first != entry->first && |
| 376 // and it can be stored in the cache, | 364 // and it can be stored in the cache, |
| 377 TranslationMayBeCached(it) && | 365 TranslationMayBeCached(it) && |
| 378 // and it's already gotten past this check and returned the miss. | 366 // and it's already gotten past this check and returned the miss. |
| 379 it->second.got_cache_reply && | 367 it->second.got_cache_reply && |
| 380 it->second.got_nexe_fd) { | 368 it->second.got_nexe_fd) { |
| 381 return; | 369 return; |
| 382 } | 370 } |
| 383 } | 371 } |
| 384 ReturnMiss(entry); | 372 ReturnMiss(entry); |
| 385 return; | 373 return; |
| 386 } | 374 } |
| 387 | 375 |
| 388 std::unique_ptr<base::File> file(pt->nexe_fd); | 376 std::unique_ptr<base::File> file(pt->nexe_fd); |
| 389 pt->nexe_fd = NULL; | 377 pt->nexe_fd = NULL; |
| 390 pt->got_nexe_fd = false; | 378 pt->got_nexe_fd = false; |
| 391 FileProxy* proxy(new FileProxy(std::move(file), weak_factory_.GetWeakPtr())); | 379 FileProxy* proxy(new FileProxy(std::move(file), this)); |
| 392 | 380 |
| 393 if (!base::PostTaskAndReplyWithResult( | 381 if (!base::PostTaskAndReplyWithResult( |
| 394 BrowserThread::GetBlockingPool(), | 382 BrowserThread::GetBlockingPool(), |
| 395 FROM_HERE, | 383 FROM_HERE, |
| 396 base::Bind(&FileProxy::Write, base::Unretained(proxy), | 384 base::Bind(&FileProxy::Write, base::Unretained(proxy), |
| 397 pt->nexe_read_buffer), | 385 pt->nexe_read_buffer), |
| 398 base::Bind(&FileProxy::WriteDone, base::Owned(proxy), | 386 base::Bind(&FileProxy::WriteDone, base::Owned(proxy), |
| 399 entry->first))) { | 387 entry->first))) { |
| 400 pt->callback.Run(base::File(), false); | 388 pt->callback.Run(base::File(), false); |
| 401 } | 389 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 // translations. | 449 // translations. |
| 462 if (!entry->second.got_nexe_fd || !entry->second.got_cache_reply || | 450 if (!entry->second.got_nexe_fd || !entry->second.got_cache_reply || |
| 463 !success || !TranslationMayBeCached(entry)) { | 451 !success || !TranslationMayBeCached(entry)) { |
| 464 store_nexe = false; | 452 store_nexe = false; |
| 465 } else { | 453 } else { |
| 466 std::unique_ptr<base::File> file(entry->second.nexe_fd); | 454 std::unique_ptr<base::File> file(entry->second.nexe_fd); |
| 467 entry->second.nexe_fd = NULL; | 455 entry->second.nexe_fd = NULL; |
| 468 entry->second.got_nexe_fd = false; | 456 entry->second.got_nexe_fd = false; |
| 469 | 457 |
| 470 if (!base::PostTaskAndReplyWithResult( | 458 if (!base::PostTaskAndReplyWithResult( |
| 471 BrowserThread::GetBlockingPool(), | 459 BrowserThread::GetBlockingPool(), FROM_HERE, |
| 472 FROM_HERE, | 460 base::Bind(&PnaclHost::CopyFileToBuffer, Passed(&file)), |
| 473 base::Bind(&PnaclHost::CopyFileToBuffer, Passed(&file)), | 461 base::Bind(&PnaclHost::StoreTranslatedNexe, base::Unretained(this), |
| 474 base::Bind(&PnaclHost::StoreTranslatedNexe, | 462 id))) { |
| 475 weak_factory_.GetWeakPtr(), | |
| 476 id))) { | |
| 477 store_nexe = false; | 463 store_nexe = false; |
| 478 } | 464 } |
| 479 } | 465 } |
| 480 | 466 |
| 481 if (!store_nexe) { | 467 if (!store_nexe) { |
| 482 // If store_nexe is true, the fd will be closed by CopyFileToBuffer. | 468 // If store_nexe is true, the fd will be closed by CopyFileToBuffer. |
| 483 if (entry->second.got_nexe_fd) { | 469 if (entry->second.got_nexe_fd) { |
| 484 std::unique_ptr<base::File> file(entry->second.nexe_fd); | 470 std::unique_ptr<base::File> file(entry->second.nexe_fd); |
| 485 entry->second.nexe_fd = NULL; | 471 entry->second.nexe_fd = NULL; |
| 486 BrowserThread::PostBlockingPoolTask( | 472 BrowserThread::PostBlockingPoolTask( |
| (...skipping 19 matching lines...) Expand all Loading... |
| 506 LOG(ERROR) << "StoreTranslatedNexe: TranslationID " << id.first << "," | 492 LOG(ERROR) << "StoreTranslatedNexe: TranslationID " << id.first << "," |
| 507 << id.second << " not found."; | 493 << id.second << " not found."; |
| 508 return; | 494 return; |
| 509 } | 495 } |
| 510 | 496 |
| 511 if (buffer.get() == NULL) { | 497 if (buffer.get() == NULL) { |
| 512 LOG(ERROR) << "Error reading translated nexe"; | 498 LOG(ERROR) << "Error reading translated nexe"; |
| 513 return; | 499 return; |
| 514 } | 500 } |
| 515 pending_backend_operations_++; | 501 pending_backend_operations_++; |
| 516 disk_cache_->StoreNexe(it->second.cache_key, | 502 disk_cache_->StoreNexe(it->second.cache_key, buffer.get(), |
| 517 buffer.get(), | |
| 518 base::Bind(&PnaclHost::OnTranslatedNexeStored, | 503 base::Bind(&PnaclHost::OnTranslatedNexeStored, |
| 519 weak_factory_.GetWeakPtr(), | 504 base::Unretained(this), it->first)); |
| 520 it->first)); | |
| 521 } | 505 } |
| 522 | 506 |
| 523 // After we know the nexe has been stored, we can clean up, and unblock any | 507 // After we know the nexe has been stored, we can clean up, and unblock any |
| 524 // outstanding requests for the same file. | 508 // outstanding requests for the same file. |
| 525 // (Bound callbacks must re-lookup the TranslationID because the translation | 509 // (Bound callbacks must re-lookup the TranslationID because the translation |
| 526 // could be cancelled before they get called). | 510 // could be cancelled before they get called). |
| 527 void PnaclHost::OnTranslatedNexeStored(const TranslationID& id, int net_error) { | 511 void PnaclHost::OnTranslatedNexeStored(const TranslationID& id, int net_error) { |
| 528 PendingTranslationMap::iterator entry(pending_translations_.find(id)); | 512 PendingTranslationMap::iterator entry(pending_translations_.find(id)); |
| 529 pending_backend_operations_--; | 513 pending_backend_operations_--; |
| 530 if (entry == pending_translations_.end()) { | 514 if (entry == pending_translations_.end()) { |
| 531 // If the renderer closed while we were storing the nexe, we land here. | 515 // If the renderer closed while we were storing the nexe, we land here. |
| 532 // Make sure we try to de-init. | 516 // Make sure we try to de-init. |
| 533 DeInitIfSafe(); | 517 DeInitIfSafe(); |
| 534 return; | 518 return; |
| 535 } | 519 } |
| 536 std::string key(entry->second.cache_key); | 520 std::string key(entry->second.cache_key); |
| 537 pending_translations_.erase(entry); | 521 pending_translations_.erase(entry); |
| 538 RequeryMatchingTranslations(key); | 522 RequeryMatchingTranslations(key); |
| 539 } | 523 } |
| 540 | 524 |
| 541 // Check if any pending translations match |key|. If so, re-issue the cache | 525 // Check if any pending translations match |key|. If so, re-issue the cache |
| 542 // query. In the overlapped miss case, we expect a hit this time, but a miss | 526 // query. In the overlapped miss case, we expect a hit this time, but a miss |
| 543 // is also possible in case of an error. | 527 // is also possible in case of an error. |
| 544 void PnaclHost::RequeryMatchingTranslations(const std::string& key) { | 528 void PnaclHost::RequeryMatchingTranslations(const std::string& key) { |
| 529 DCHECK(thread_checker_.CalledOnValidThread()); |
| 545 // Check for outstanding misses to this same file | 530 // Check for outstanding misses to this same file |
| 546 for (PendingTranslationMap::iterator it = pending_translations_.begin(); | 531 for (PendingTranslationMap::iterator it = pending_translations_.begin(); |
| 547 it != pending_translations_.end(); | 532 it != pending_translations_.end(); |
| 548 ++it) { | 533 ++it) { |
| 549 if (it->second.cache_key == key) { | 534 if (it->second.cache_key == key) { |
| 550 // Re-send the cache read request. This time we expect a hit, but if | 535 // Re-send the cache read request. This time we expect a hit, but if |
| 551 // something goes wrong, it will just handle it like a miss. | 536 // something goes wrong, it will just handle it like a miss. |
| 552 it->second.got_cache_reply = false; | 537 it->second.got_cache_reply = false; |
| 553 pending_backend_operations_++; | 538 pending_backend_operations_++; |
| 554 disk_cache_->GetNexe(key, | 539 disk_cache_->GetNexe(key, base::Bind(&PnaclHost::OnCacheQueryReturn, |
| 555 base::Bind(&PnaclHost::OnCacheQueryReturn, | 540 base::Unretained(this), it->first)); |
| 556 weak_factory_.GetWeakPtr(), | |
| 557 it->first)); | |
| 558 } | 541 } |
| 559 } | 542 } |
| 560 } | 543 } |
| 561 | 544 |
| 562 //////////////////// GetNexeFd hit path | 545 //////////////////// GetNexeFd hit path |
| 563 | 546 |
| 564 void PnaclHost::OnBufferCopiedToTempFile(const TranslationID& id, | 547 void PnaclHost::OnBufferCopiedToTempFile(const TranslationID& id, |
| 565 std::unique_ptr<base::File> file, | 548 std::unique_ptr<base::File> file, |
| 566 int file_error) { | 549 int file_error) { |
| 567 DCHECK(thread_checker_.CalledOnValidThread()); | 550 DCHECK(thread_checker_.CalledOnValidThread()); |
| 568 PendingTranslationMap::iterator entry(pending_translations_.find(id)); | 551 PendingTranslationMap::iterator entry(pending_translations_.find(id)); |
| 569 if (entry == pending_translations_.end()) { | 552 if (entry == pending_translations_.end()) { |
| 570 BrowserThread::PostBlockingPoolTask( | 553 BrowserThread::PostBlockingPoolTask( |
| 571 FROM_HERE, | 554 FROM_HERE, |
| 572 base::Bind(CloseScopedFile, Passed(&file))); | 555 base::Bind(CloseScopedFile, Passed(&file))); |
| 573 return; | 556 return; |
| 574 } | 557 } |
| 575 if (file_error == -1) { | 558 if (file_error == -1) { |
| 576 // Write error on the temp file. Request a new file and start over. | 559 // Write error on the temp file. Request a new file and start over. |
| 577 BrowserThread::PostBlockingPoolTask( | 560 BrowserThread::PostBlockingPoolTask( |
| 578 FROM_HERE, | 561 FROM_HERE, |
| 579 base::Bind(CloseScopedFile, Passed(&file))); | 562 base::Bind(CloseScopedFile, Passed(&file))); |
| 580 CreateTemporaryFile(base::Bind(&PnaclHost::OnTempFileReturn, | 563 CreateTemporaryFile(base::Bind(&PnaclHost::OnTempFileReturn, |
| 581 weak_factory_.GetWeakPtr(), | 564 base::Unretained(this), entry->first)); |
| 582 entry->first)); | |
| 583 return; | 565 return; |
| 584 } | 566 } |
| 585 entry->second.callback.Run(*file.get(), true); | 567 entry->second.callback.Run(*file.get(), true); |
| 586 BrowserThread::PostBlockingPoolTask( | 568 BrowserThread::PostBlockingPoolTask( |
| 587 FROM_HERE, | 569 FROM_HERE, |
| 588 base::Bind(CloseScopedFile, Passed(&file))); | 570 base::Bind(CloseScopedFile, Passed(&file))); |
| 589 pending_translations_.erase(entry); | 571 pending_translations_.erase(entry); |
| 590 } | 572 } |
| 591 | 573 |
| 592 /////////////////// | 574 /////////////////// |
| (...skipping 14 matching lines...) Expand all Loading... |
| 607 base::Bind(CloseScopedFile, Passed(&file))); | 589 base::Bind(CloseScopedFile, Passed(&file))); |
| 608 std::string key(to_erase->second.cache_key); | 590 std::string key(to_erase->second.cache_key); |
| 609 bool may_be_cached = TranslationMayBeCached(to_erase); | 591 bool may_be_cached = TranslationMayBeCached(to_erase); |
| 610 pending_translations_.erase(to_erase); | 592 pending_translations_.erase(to_erase); |
| 611 // No translations will be waiting for entries that will not be stored. | 593 // No translations will be waiting for entries that will not be stored. |
| 612 if (may_be_cached) | 594 if (may_be_cached) |
| 613 RequeryMatchingTranslations(key); | 595 RequeryMatchingTranslations(key); |
| 614 } | 596 } |
| 615 } | 597 } |
| 616 BrowserThread::PostTask( | 598 BrowserThread::PostTask( |
| 617 BrowserThread::IO, | 599 BrowserThread::IO, FROM_HERE, |
| 618 FROM_HERE, | 600 base::Bind(&PnaclHost::DeInitIfSafe, base::Unretained(this))); |
| 619 base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr())); | |
| 620 } | 601 } |
| 621 | 602 |
| 622 ////////////////// Cache data removal | 603 ////////////////// Cache data removal |
| 623 void PnaclHost::ClearTranslationCacheEntriesBetween( | 604 void PnaclHost::ClearTranslationCacheEntriesBetween( |
| 624 base::Time initial_time, | 605 base::Time initial_time, |
| 625 base::Time end_time, | 606 base::Time end_time, |
| 626 const base::Closure& callback) { | 607 const base::Closure& callback) { |
| 627 DCHECK(thread_checker_.CalledOnValidThread()); | 608 DCHECK(thread_checker_.CalledOnValidThread()); |
| 628 if (cache_state_ == CacheUninitialized) { | 609 if (cache_state_ == CacheUninitialized) { |
| 629 Init(); | 610 Init(); |
| 630 } | 611 } |
| 631 if (cache_state_ == CacheInitializing) { | 612 if (cache_state_ == CacheInitializing) { |
| 632 // If the backend hasn't yet initialized, try the request again later. | 613 // If the backend hasn't yet initialized, try the request again later. |
| 633 BrowserThread::PostDelayedTask( | 614 BrowserThread::PostDelayedTask( |
| 634 BrowserThread::IO, | 615 BrowserThread::IO, FROM_HERE, |
| 635 FROM_HERE, | |
| 636 base::Bind(&PnaclHost::ClearTranslationCacheEntriesBetween, | 616 base::Bind(&PnaclHost::ClearTranslationCacheEntriesBetween, |
| 637 weak_factory_.GetWeakPtr(), | 617 base::Unretained(this), initial_time, end_time, callback), |
| 638 initial_time, | |
| 639 end_time, | |
| 640 callback), | |
| 641 base::TimeDelta::FromMilliseconds( | 618 base::TimeDelta::FromMilliseconds( |
| 642 kTranslationCacheInitializationDelayMs)); | 619 kTranslationCacheInitializationDelayMs)); |
| 643 return; | 620 return; |
| 644 } | 621 } |
| 645 pending_backend_operations_++; | 622 pending_backend_operations_++; |
| 646 int rv = disk_cache_->DoomEntriesBetween( | 623 int rv = disk_cache_->DoomEntriesBetween( |
| 647 initial_time, | 624 initial_time, end_time, base::Bind(&PnaclHost::OnEntriesDoomed, |
| 648 end_time, | 625 base::Unretained(this), callback)); |
| 649 base::Bind( | |
| 650 &PnaclHost::OnEntriesDoomed, weak_factory_.GetWeakPtr(), callback)); | |
| 651 if (rv != net::ERR_IO_PENDING) | 626 if (rv != net::ERR_IO_PENDING) |
| 652 OnEntriesDoomed(callback, rv); | 627 OnEntriesDoomed(callback, rv); |
| 653 } | 628 } |
| 654 | 629 |
| 655 void PnaclHost::OnEntriesDoomed(const base::Closure& callback, int net_error) { | 630 void PnaclHost::OnEntriesDoomed(const base::Closure& callback, int net_error) { |
| 656 DCHECK(thread_checker_.CalledOnValidThread()); | 631 DCHECK(thread_checker_.CalledOnValidThread()); |
| 657 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback); | 632 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback); |
| 658 pending_backend_operations_--; | 633 pending_backend_operations_--; |
| 659 // When clearing the cache, the UI is blocked on all the cache-clearing | 634 // When clearing the cache, the UI is blocked on all the cache-clearing |
| 660 // operations, and freeing the backend actually blocks the IO thread. So | 635 // operations, and freeing the backend actually blocks the IO thread. So |
| 661 // instead of calling DeInitIfSafe directly, post it for later. | 636 // instead of calling DeInitIfSafe directly, post it for later. |
| 662 BrowserThread::PostTask( | 637 BrowserThread::PostTask( |
| 663 BrowserThread::IO, | 638 BrowserThread::IO, FROM_HERE, |
| 664 FROM_HERE, | 639 base::Bind(&PnaclHost::DeInitIfSafe, base::Unretained(this))); |
| 665 base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr())); | |
| 666 } | 640 } |
| 667 | 641 |
| 668 // Destroying the cache backend causes it to post tasks to the cache thread to | 642 // Destroying the cache backend causes it to post tasks to the cache thread to |
| 669 // flush to disk. Because PnaclHost is a singleton, it does not get destroyed | 643 // flush to disk. PnaclHost is leaked on shutdown because registering it as a |
| 670 // until all the browser threads have gone away and it's too late to post | 644 // Singleton with AtExitManager would result in it not being destroyed until all |
| 671 // anything (attempting to do so hangs shutdown). So we make sure to destroy it | 645 // the browser threads have gone away and it's too late to post anything |
| 672 // when we no longer have any outstanding operations that need it. These include | 646 // (attempting to do so hangs shutdown) at that point anyways. So we make sure |
| 673 // pending translations, cache clear requests, and requests to read or write | 647 // to destroy it when we no longer have any outstanding operations that need it. |
| 674 // translated nexes. We check when renderers close, when cache clear requests | 648 // These include pending translations, cache clear requests, and requests to |
| 675 // finish, and when backend operations complete. | 649 // read or write translated nexes. We check when renderers close, when cache |
| 650 // clear requests finish, and when backend operations complete. |
| 676 | 651 |
| 677 // It is not safe to delete the backend while it is initializing, nor if it has | 652 // It is not safe to delete the backend while it is initializing, nor if it has |
| 678 // outstanding entry open requests; it is in theory safe to delete it with | 653 // outstanding entry open requests; it is in theory safe to delete it with |
| 679 // outstanding read/write requests, but because that distinction is hidden | 654 // outstanding read/write requests, but because that distinction is hidden |
| 680 // inside PnaclTranslationCache, we do not delete the backend if there are any | 655 // inside PnaclTranslationCache, we do not delete the backend if there are any |
| 681 // backend requests in flight. As a last resort in the destructor, we just leak | 656 // backend requests in flight. As a last resort in the destructor, we just leak |
| 682 // the backend to avoid hanging shutdown. | 657 // the backend to avoid hanging shutdown. |
| 683 void PnaclHost::DeInitIfSafe() { | 658 void PnaclHost::DeInitIfSafe() { |
| 684 DCHECK(pending_backend_operations_ >= 0); | 659 DCHECK(pending_backend_operations_ >= 0); |
| 685 if (pending_translations_.empty() && | 660 if (pending_translations_.empty() && |
| 686 pending_backend_operations_ <= 0 && | 661 pending_backend_operations_ <= 0 && |
| 687 cache_state_ == CacheReady) { | 662 cache_state_ == CacheReady) { |
| 688 cache_state_ = CacheUninitialized; | 663 cache_state_ = CacheUninitialized; |
| 689 disk_cache_.reset(); | 664 disk_cache_.reset(); |
| 690 } | 665 } |
| 691 } | 666 } |
| 692 | 667 |
| 693 } // namespace pnacl | 668 } // namespace pnacl |
| OLD | NEW |