Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: chrome/browser/nacl_host/pnacl_host.cc

Issue 28933003: Delete PNaCl translation cache backend object when no longer needed (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: cleanup Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/nacl_host/pnacl_host.h ('k') | chrome/browser/nacl_host/pnacl_host_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "chrome/browser/nacl_host/pnacl_host.h" 5 #include "chrome/browser/nacl_host/pnacl_host.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/task_runner_util.h" 12 #include "base/task_runner_util.h"
13 #include "base/threading/sequenced_worker_pool.h" 13 #include "base/threading/sequenced_worker_pool.h"
14 #include "chrome/browser/nacl_host/nacl_browser.h" 14 #include "chrome/browser/nacl_host/nacl_browser.h"
15 #include "chrome/browser/nacl_host/pnacl_translation_cache.h" 15 #include "chrome/browser/nacl_host/pnacl_translation_cache.h"
16 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/io_buffer.h" 17 #include "net/base/io_buffer.h"
18 #include "net/base/net_errors.h" 18 #include "net/base/net_errors.h"
19 19
20 using content::BrowserThread; 20 using content::BrowserThread;
21 21
22 namespace { 22 namespace {
23 static const base::FilePath::CharType kTranslationCacheDirectoryName[] = 23 static const base::FilePath::CharType kTranslationCacheDirectoryName[] =
24 FILE_PATH_LITERAL("PnaclTranslationCache"); 24 FILE_PATH_LITERAL("PnaclTranslationCache");
25 // Delay to wait for initialization of the cache backend 25 // Delay to wait for initialization of the cache backend
26 static const int kTranslationCacheInitializationDelayMs = 20; 26 static const int kTranslationCacheInitializationDelayMs = 20;
27 } 27 }
28 28
29 PnaclHost::PnaclHost() 29 PnaclHost::PnaclHost()
30 : cache_state_(CacheUninitialized), weak_factory_(this) {} 30 : pending_backend_operations_(0),
31 cache_state_(CacheUninitialized),
32 weak_factory_(this) {}
31 33
32 PnaclHost::~PnaclHost() {} 34 PnaclHost::~PnaclHost() {
35 // When PnaclHost is destroyed, it's too late to post anything to the cache
36 // thread (it will hang shutdown). So just leak the cache backend.
37 pnacl::PnaclTranslationCache* cache = disk_cache_.release();
jvoung (off chromium) 2013/10/24 21:14:58 Can this just be a one-liner (void)...release()?
Derek Schuff 2013/10/25 19:38:06 Nope, gcc still warns about unused result if you d
38 (void)cache;
39 }
33 40
34 PnaclHost* PnaclHost::GetInstance() { return Singleton<PnaclHost>::get(); } 41 PnaclHost* PnaclHost::GetInstance() { return Singleton<PnaclHost>::get(); }
35 42
36 PnaclHost::PendingTranslation::PendingTranslation() 43 PnaclHost::PendingTranslation::PendingTranslation()
37 : process_handle(base::kNullProcessHandle), 44 : process_handle(base::kNullProcessHandle),
38 render_view_id(0), 45 render_view_id(0),
39 nexe_fd(base::kInvalidPlatformFileValue), 46 nexe_fd(base::kInvalidPlatformFileValue),
40 got_nexe_fd(false), 47 got_nexe_fd(false),
41 got_cache_reply(false), 48 got_cache_reply(false),
42 got_cache_hit(false), 49 got_cache_hit(false),
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 void PnaclHost::Init() { 96 void PnaclHost::Init() {
90 // Extra check that we're on the real IO thread since this version of 97 // Extra check that we're on the real IO thread since this version of
91 // Init isn't used in unit tests. 98 // Init isn't used in unit tests.
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
93 DCHECK(thread_checker_.CalledOnValidThread()); 100 DCHECK(thread_checker_.CalledOnValidThread());
94 base::FilePath cache_path(GetCachePath()); 101 base::FilePath cache_path(GetCachePath());
95 if (cache_path.empty() || cache_state_ != CacheUninitialized) 102 if (cache_path.empty() || cache_state_ != CacheUninitialized)
96 return; 103 return;
97 disk_cache_.reset(new pnacl::PnaclTranslationCache()); 104 disk_cache_.reset(new pnacl::PnaclTranslationCache());
98 cache_state_ = CacheInitializing; 105 cache_state_ = CacheInitializing;
99 disk_cache_->InitOnDisk( 106 int rv = disk_cache_->InitOnDisk(
100 cache_path, 107 cache_path,
101 base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr())); 108 base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
109 if (rv != net::ERR_IO_PENDING)
110 OnCacheInitialized(rv);
102 } 111 }
103 112
104 // Initialize using the in-memory backend, and manually set the temporary file 113 // Initialize using the in-memory backend, and manually set the temporary file
105 // directory instead of using the system directory. 114 // directory instead of using the system directory.
106 void PnaclHost::InitForTest(base::FilePath temp_dir) { 115 void PnaclHost::InitForTest(base::FilePath temp_dir) {
107 DCHECK(thread_checker_.CalledOnValidThread()); 116 DCHECK(thread_checker_.CalledOnValidThread());
108 disk_cache_.reset(new pnacl::PnaclTranslationCache()); 117 disk_cache_.reset(new pnacl::PnaclTranslationCache());
109 cache_state_ = CacheInitializing; 118 cache_state_ = CacheInitializing;
110 temp_dir_ = temp_dir; 119 temp_dir_ = temp_dir;
111 disk_cache_->InitInMemory( 120 int rv = disk_cache_->InitInMemory(
112 base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr())); 121 base::Bind(&PnaclHost::OnCacheInitialized, weak_factory_.GetWeakPtr()));
122 if (rv != net::ERR_IO_PENDING)
123 OnCacheInitialized(rv);
113 } 124 }
114 125
115 ///////////////////////////////////////// Temp files 126 ///////////////////////////////////////// Temp files
116 127
117 // Create a temporary file on the blocking pool 128 // Create a temporary file on the blocking pool
118 // static 129 // static
119 void PnaclHost::DoCreateTemporaryFile(base::FilePath temp_dir, 130 void PnaclHost::DoCreateTemporaryFile(base::FilePath temp_dir,
120 TempFileCallback cb) { 131 TempFileCallback cb) {
121 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 132 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
122 133
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 pt.is_incognito = is_incognito; 220 pt.is_incognito = is_incognito;
210 pending_translations_[id] = pt; 221 pending_translations_[id] = pt;
211 SendCacheQueryAndTempFileRequest(cache_key, id); 222 SendCacheQueryAndTempFileRequest(cache_key, id);
212 } 223 }
213 224
214 // Dispatch the cache read request and the temp file creation request 225 // Dispatch the cache read request and the temp file creation request
215 // simultaneously; currently we need a temp file regardless of whether the 226 // simultaneously; currently we need a temp file regardless of whether the
216 // request hits. 227 // request hits.
217 void PnaclHost::SendCacheQueryAndTempFileRequest(const std::string& cache_key, 228 void PnaclHost::SendCacheQueryAndTempFileRequest(const std::string& cache_key,
218 const TranslationID& id) { 229 const TranslationID& id) {
230 pending_backend_operations_++;
219 disk_cache_->GetNexe( 231 disk_cache_->GetNexe(
220 cache_key, 232 cache_key,
221 base::Bind( 233 base::Bind(
222 &PnaclHost::OnCacheQueryReturn, weak_factory_.GetWeakPtr(), id)); 234 &PnaclHost::OnCacheQueryReturn, weak_factory_.GetWeakPtr(), id));
223 235
224 CreateTemporaryFile( 236 CreateTemporaryFile(
225 base::Bind(&PnaclHost::OnTempFileReturn, weak_factory_.GetWeakPtr(), id)); 237 base::Bind(&PnaclHost::OnTempFileReturn, weak_factory_.GetWeakPtr(), id));
226 } 238 }
227 239
228 // Callback from the translation cache query. |id| is bound from 240 // Callback from the translation cache query. |id| is bound from
229 // SendCacheQueryAndTempFileRequest, |net_error| is a net::Error code (which for 241 // SendCacheQueryAndTempFileRequest, |net_error| is a net::Error code (which for
230 // our purposes means a hit if it's net::OK (i.e. 0). |buffer| is allocated 242 // our purposes means a hit if it's net::OK (i.e. 0). |buffer| is allocated
231 // by PnaclTranslationCache and now belongs to PnaclHost. 243 // by PnaclTranslationCache and now belongs to PnaclHost.
232 // (Bound callbacks must re-lookup the TranslationID because the translation 244 // (Bound callbacks must re-lookup the TranslationID because the translation
233 // could be cancelled before they get called). 245 // could be cancelled before they get called).
234 void PnaclHost::OnCacheQueryReturn( 246 void PnaclHost::OnCacheQueryReturn(
235 const TranslationID& id, 247 const TranslationID& id,
236 int net_error, 248 int net_error,
237 scoped_refptr<net::DrainableIOBuffer> buffer) { 249 scoped_refptr<net::DrainableIOBuffer> buffer) {
238 DCHECK(thread_checker_.CalledOnValidThread()); 250 DCHECK(thread_checker_.CalledOnValidThread());
251 pending_backend_operations_--;
239 PendingTranslationMap::iterator entry(pending_translations_.find(id)); 252 PendingTranslationMap::iterator entry(pending_translations_.find(id));
240 if (entry == pending_translations_.end()) { 253 if (entry == pending_translations_.end()) {
241 LOG(ERROR) << "OnCacheQueryReturn: id not found"; 254 LOG(ERROR) << "OnCacheQueryReturn: id not found";
255 DeInitIfSafe();
242 return; 256 return;
243 } 257 }
244 PendingTranslation* pt = &entry->second; 258 PendingTranslation* pt = &entry->second;
245 pt->got_cache_reply = true; 259 pt->got_cache_reply = true;
246 pt->got_cache_hit = (net_error == net::OK); 260 pt->got_cache_hit = (net_error == net::OK);
247 if (pt->got_cache_hit) 261 if (pt->got_cache_hit)
248 pt->nexe_read_buffer = buffer; 262 pt->nexe_read_buffer = buffer;
249 CheckCacheQueryReady(entry); 263 CheckCacheQueryReady(entry);
250 } 264 }
251 265
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 if (it == pending_translations_.end()) { 440 if (it == pending_translations_.end()) {
427 LOG(ERROR) << "StoreTranslatedNexe: TranslationID " << id.first << "," 441 LOG(ERROR) << "StoreTranslatedNexe: TranslationID " << id.first << ","
428 << id.second << " not found."; 442 << id.second << " not found.";
429 return; 443 return;
430 } 444 }
431 445
432 if (buffer.get() == NULL) { 446 if (buffer.get() == NULL) {
433 LOG(ERROR) << "Error reading translated nexe"; 447 LOG(ERROR) << "Error reading translated nexe";
434 return; 448 return;
435 } 449 }
436 450 pending_backend_operations_++;
437 disk_cache_->StoreNexe(it->second.cache_key, 451 disk_cache_->StoreNexe(it->second.cache_key,
438 buffer, 452 buffer,
439 base::Bind(&PnaclHost::OnTranslatedNexeStored, 453 base::Bind(&PnaclHost::OnTranslatedNexeStored,
440 weak_factory_.GetWeakPtr(), 454 weak_factory_.GetWeakPtr(),
441 it->first)); 455 it->first));
442 } 456 }
443 457
444 // After we know the nexe has been stored, we can clean up, and unblock any 458 // After we know the nexe has been stored, we can clean up, and unblock any
445 // outstanding requests for the same file. 459 // outstanding requests for the same file.
446 // (Bound callbacks must re-lookup the TranslationID because the translation 460 // (Bound callbacks must re-lookup the TranslationID because the translation
447 // could be cancelled before they get called). 461 // could be cancelled before they get called).
448 void PnaclHost::OnTranslatedNexeStored(const TranslationID& id, int net_error) { 462 void PnaclHost::OnTranslatedNexeStored(const TranslationID& id, int net_error) {
449 PendingTranslationMap::iterator entry(pending_translations_.find(id)); 463 PendingTranslationMap::iterator entry(pending_translations_.find(id));
464 pending_backend_operations_--;
450 if (entry == pending_translations_.end()) { 465 if (entry == pending_translations_.end()) {
466 // If the renderer closed while we were storing the nexe, we land here.
467 // Make sure we try to de-init.
468 DeInitIfSafe();
451 return; 469 return;
452 } 470 }
453 std::string key(entry->second.cache_key); 471 std::string key(entry->second.cache_key);
454 pending_translations_.erase(entry); 472 pending_translations_.erase(entry);
455 RequeryMatchingTranslations(key); 473 RequeryMatchingTranslations(key);
456 } 474 }
457 475
458 // Check if any pending translations match |key|. If so, re-issue the cache 476 // Check if any pending translations match |key|. If so, re-issue the cache
459 // query. In the overlapped miss case, we expect a hit this time, but a miss 477 // query. In the overlapped miss case, we expect a hit this time, but a miss
460 // is also possible in case of an error. 478 // is also possible in case of an error.
461 void PnaclHost::RequeryMatchingTranslations(const std::string& key) { 479 void PnaclHost::RequeryMatchingTranslations(const std::string& key) {
462 // Check for outstanding misses to this same file 480 // Check for outstanding misses to this same file
463 for (PendingTranslationMap::iterator it = pending_translations_.begin(); 481 for (PendingTranslationMap::iterator it = pending_translations_.begin();
464 it != pending_translations_.end(); 482 it != pending_translations_.end();
465 ++it) { 483 ++it) {
466 if (it->second.cache_key == key) { 484 if (it->second.cache_key == key) {
467 // Re-send the cache read request. This time we expect a hit, but if 485 // Re-send the cache read request. This time we expect a hit, but if
468 // something goes wrong, it will just handle it like a miss. 486 // something goes wrong, it will just handle it like a miss.
469 it->second.got_cache_reply = false; 487 it->second.got_cache_reply = false;
488 pending_backend_operations_++;
470 disk_cache_->GetNexe(key, 489 disk_cache_->GetNexe(key,
471 base::Bind(&PnaclHost::OnCacheQueryReturn, 490 base::Bind(&PnaclHost::OnCacheQueryReturn,
472 weak_factory_.GetWeakPtr(), 491 weak_factory_.GetWeakPtr(),
473 it->first)); 492 it->first));
474 } 493 }
475 } 494 }
476 } 495 }
477 496
478 //////////////////// GetNexeFd hit path 497 //////////////////// GetNexeFd hit path
479 498
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 base::Bind(base::IgnoreResult(base::ClosePlatformFile), 547 base::Bind(base::IgnoreResult(base::ClosePlatformFile),
529 to_erase->second.nexe_fd)); 548 to_erase->second.nexe_fd));
530 std::string key(to_erase->second.cache_key); 549 std::string key(to_erase->second.cache_key);
531 bool may_be_cached = TranslationMayBeCached(to_erase); 550 bool may_be_cached = TranslationMayBeCached(to_erase);
532 pending_translations_.erase(to_erase); 551 pending_translations_.erase(to_erase);
533 // No translations will be waiting for entries that will not be stored. 552 // No translations will be waiting for entries that will not be stored.
534 if (may_be_cached) 553 if (may_be_cached)
535 RequeryMatchingTranslations(key); 554 RequeryMatchingTranslations(key);
536 } 555 }
537 } 556 }
538 if (pending_translations_.empty()) { 557 BrowserThread::PostTask(
539 cache_state_ = CacheUninitialized; 558 BrowserThread::IO,
540 // Freeing the backend causes it to flush to disk, so do it when the 559 FROM_HERE,
541 // last renderer closes rather than on destruction. 560 base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr()));
542 disk_cache_.reset();
543 }
544 } 561 }
545 562
546 ////////////////// Cache data removal 563 ////////////////// Cache data removal
547 void PnaclHost::ClearTranslationCacheEntriesBetween( 564 void PnaclHost::ClearTranslationCacheEntriesBetween(
548 base::Time initial_time, 565 base::Time initial_time,
549 base::Time end_time, 566 base::Time end_time,
550 const base::Closure& callback) { 567 const base::Closure& callback) {
551 DCHECK(thread_checker_.CalledOnValidThread()); 568 DCHECK(thread_checker_.CalledOnValidThread());
552 if (cache_state_ == CacheUninitialized) { 569 if (cache_state_ == CacheUninitialized) {
553 Init(); 570 Init();
554 } 571 }
555 if (cache_state_ == CacheInitializing) { 572 if (cache_state_ == CacheInitializing) {
556 // If the backend hasn't yet initialized, try the request again later. 573 // If the backend hasn't yet initialized, try the request again later.
557 BrowserThread::PostDelayedTask( 574 BrowserThread::PostDelayedTask(
558 BrowserThread::IO, 575 BrowserThread::IO,
559 FROM_HERE, 576 FROM_HERE,
560 base::Bind(&PnaclHost::ClearTranslationCacheEntriesBetween, 577 base::Bind(&PnaclHost::ClearTranslationCacheEntriesBetween,
561 weak_factory_.GetWeakPtr(), 578 weak_factory_.GetWeakPtr(),
562 initial_time, 579 initial_time,
563 end_time, 580 end_time,
564 callback), 581 callback),
565 base::TimeDelta::FromMilliseconds( 582 base::TimeDelta::FromMilliseconds(
566 kTranslationCacheInitializationDelayMs)); 583 kTranslationCacheInitializationDelayMs));
567 return; 584 return;
568 } 585 }
586 pending_backend_operations_++;
569 int rv = disk_cache_->DoomEntriesBetween( 587 int rv = disk_cache_->DoomEntriesBetween(
570 initial_time, 588 initial_time,
571 end_time, 589 end_time,
572 base::Bind(&PnaclHost::OnEntriesDoomed, callback)); 590 base::Bind(
591 &PnaclHost::OnEntriesDoomed, weak_factory_.GetWeakPtr(), callback));
573 if (rv != net::ERR_IO_PENDING) 592 if (rv != net::ERR_IO_PENDING)
574 OnEntriesDoomed(callback, rv); 593 OnEntriesDoomed(callback, rv);
575 } 594 }
576 595
577 // static
578 void PnaclHost::OnEntriesDoomed(const base::Closure& callback, int net_error) { 596 void PnaclHost::OnEntriesDoomed(const base::Closure& callback, int net_error) {
597 DCHECK(thread_checker_.CalledOnValidThread());
579 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback); 598 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback);
599 pending_backend_operations_--;
600 // When clearing the cache, the UI is blocked on all the cache-clearing
601 // operations, and freeing the backend actually blocks the IO thread. So
602 // instead of calling DeInitIfSafe directly, post it for later.
603 BrowserThread::PostTask(
604 BrowserThread::IO,
605 FROM_HERE,
606 base::Bind(&PnaclHost::DeInitIfSafe, weak_factory_.GetWeakPtr()));
580 } 607 }
608
609 // Destroying the cache backend causes it to post tasks to the cache thread to
610 // flush to disk. Because PnaclHost is a singleton, it does not get destroyed
611 // until all the browser threads have gone away and it's too late to post
612 // anything (attempting to do so hangs shutdown). So we make sure to destroy it
613 // when we no longer have any outstanding operations that need it. These include
614 // pending translations, cache clear requests, and requests to read or write
615 // translated nexes. We check when renderers close, when cache clear requests
616 // finish, and when backend operations complete.
617
618 // It is not safe to delete the backend while it is initializing, nor if it has
619 // outstanding entry open requests; it is in theory safe to delete it with
620 // outstanding read/write requests, but because that distinction is hidden
621 // inside PnaclTranslationCache, we do not delete the backend if there are any
622 // backend requests in flight. As a last resort in the destructor, we just leak
623 // the backend to avoid hanging shutdown.
624 void PnaclHost::DeInitIfSafe() {
625 if (pending_translations_.empty() && pending_backend_operations_ <= 0) {
jvoung (off chromium) 2013/10/24 21:14:58 Should just be pending_backend_operations_ == 0? S
Derek Schuff 2013/10/25 19:38:06 Yeah, it's bad and definitely not expected, the qu
jvoung (off chromium) 2013/10/25 19:51:43 Maybe you could DCHECK() that it's never < 0 for t
Derek Schuff 2013/10/25 19:57:09 good idea, done.
626 cache_state_ = CacheUninitialized;
627 disk_cache_.reset();
628 }
629 }
OLDNEW
« no previous file with comments | « chrome/browser/nacl_host/pnacl_host.h ('k') | chrome/browser/nacl_host/pnacl_host_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698