Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/browser_process_impl.h" | 5 #include "chrome/browser/browser_process_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 #if defined(OS_MACOSX) | 372 #if defined(OS_MACOSX) |
| 373 base::MessageLoop::current()->PostTask( | 373 base::MessageLoop::current()->PostTask( |
| 374 FROM_HERE, | 374 FROM_HERE, |
| 375 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); | 375 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); |
| 376 #endif | 376 #endif |
| 377 base::MessageLoop::current()->Quit(); | 377 base::MessageLoop::current()->Quit(); |
| 378 } | 378 } |
| 379 return module_ref_count_; | 379 return module_ref_count_; |
| 380 } | 380 } |
| 381 | 381 |
| 382 namespace { | |
| 383 | |
| 384 class RundownTaskCounter { | |
|
gab
2014/06/23 19:53:48
This could simply be a RefCounted object (especial
Sigurður Ásgeirsson
2014/06/23 20:20:12
Conflating lifetime management with state is gener
gab
2014/06/23 21:09:53
Ah right, good point about the possibility of a th
erikwright (departed)
2014/06/24 16:10:53
The concern about multiple 1->0 transitions is not
| |
| 385 public: | |
| 386 // Creates a rundown task counter with |count|. | |
| 387 explicit RundownTaskCounter(size_t count); | |
| 388 ~RundownTaskCounter() {} | |
| 389 | |
| 390 // Decrements the counter and releases the wait on zero. | |
| 391 static void Decrement(RundownTaskCounter* counter); | |
| 392 | |
| 393 // Waits until the count is zero or |max_time| has passed. | |
| 394 bool TimedWait(const base::TimeDelta& max_time); | |
| 395 | |
| 396 private: | |
| 397 base::AtomicRefCount count_; | |
| 398 base::WaitableEvent waitable_event_; | |
| 399 | |
| 400 DISALLOW_COPY_AND_ASSIGN(RundownTaskCounter); | |
| 401 }; | |
| 402 | |
| 403 RundownTaskCounter::RundownTaskCounter(size_t count) | |
| 404 : count_(count), waitable_event_(true, false) { | |
| 405 DCHECK_LT(1U, count); | |
|
gab
2014/06/23 21:09:53
DCHECK_GT(count, 1U);
(We always put constants on
| |
| 406 } | |
| 407 | |
| 408 void RundownTaskCounter::Decrement(RundownTaskCounter* counter) { | |
| 409 DCHECK_NE(static_cast<RundownTaskCounter*>(NULL), counter); | |
|
gab
2014/06/23 21:09:53
DCHECK(counter);
| |
| 410 | |
| 411 if (!base::AtomicRefCountDec(&counter->count_)) { | |
| 412 counter->waitable_event_.Signal(); | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 bool RundownTaskCounter::TimedWait(const base::TimeDelta& max_time) { | |
| 417 return waitable_event_.TimedWait(max_time); | |
| 418 } | |
| 419 | |
| 420 } // namespace | |
| 421 | |
| 382 void BrowserProcessImpl::EndSession() { | 422 void BrowserProcessImpl::EndSession() { |
| 383 // Mark all the profiles as clean. | 423 // Mark all the profiles as clean. |
| 384 ProfileManager* pm = profile_manager(); | 424 ProfileManager* pm = profile_manager(); |
| 385 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); | 425 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); |
| 386 for (size_t i = 0; i < profiles.size(); ++i) | 426 |
| 387 profiles[i]->SetExitType(Profile::EXIT_SESSION_ENDED); | 427 // We create the rundown task counter with a count for each profile, |
| 428 // plus one for local state. | |
| 429 scoped_ptr<RundownTaskCounter> counter( | |
| 430 new RundownTaskCounter(profiles.size() + 1)); | |
| 431 | |
| 432 for (size_t i = 0; i < profiles.size(); ++i) { | |
| 433 Profile* profile = profiles[i]; | |
| 434 profile->SetExitType(Profile::EXIT_SESSION_ENDED); | |
| 435 | |
| 436 scoped_refptr<base::SequencedTaskRunner> io_task_runner = | |
| 437 profile->GetIOTaskRunner(); | |
| 438 io_task_runner->PostTask(FROM_HERE, | |
| 439 base::Bind(RundownTaskCounter::Decrement, | |
| 440 counter.get())); | |
| 441 } | |
| 388 | 442 |
| 389 // Tell the metrics service it was cleanly shutdown. | 443 // Tell the metrics service it was cleanly shutdown. |
| 390 MetricsService* metrics = g_browser_process->metrics_service(); | 444 MetricsService* metrics = g_browser_process->metrics_service(); |
| 391 if (metrics && local_state()) { | 445 if (metrics && local_state()) { |
| 392 metrics->RecordStartOfSessionEnd(); | 446 metrics->RecordStartOfSessionEnd(); |
| 393 #if !defined(OS_CHROMEOS) | 447 #if !defined(OS_CHROMEOS) |
| 394 // MetricsService lazily writes to prefs, force it to write now. | 448 // MetricsService lazily writes to prefs, force it to write now. |
| 395 // On ChromeOS, chrome gets killed when hangs, so no need to | 449 // On ChromeOS, chrome gets killed when hangs, so no need to |
| 396 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. | 450 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. |
| 397 local_state()->CommitPendingWrite(); | 451 local_state()->CommitPendingWrite(); |
| 452 | |
| 453 local_state_task_runner_->PostTask(FROM_HERE, | |
| 454 base::Bind(RundownTaskCounter::Decrement, | |
|
gab
2014/06/23 21:09:53
Now that RundownTaskCounter is refcounted, Decreme
Sigurður Ásgeirsson
2014/06/23 21:39:59
Done.
| |
| 455 counter.get())); | |
|
gab
2014/06/23 21:09:53
On ChromeOS this never gets posted (as per the ifd
Sigurður Ásgeirsson
2014/06/23 21:39:59
Thanks great catch. I've added some robustness aga
| |
| 456 | |
|
gab
2014/06/23 21:09:53
rm empty line
Sigurður Ásgeirsson
2014/06/23 21:39:59
Done.
| |
| 398 #endif | 457 #endif |
| 399 } | 458 } |
| 400 | 459 |
| 401 // http://crbug.com/125207 | 460 // http://crbug.com/125207 |
| 402 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 461 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 403 | 462 |
| 404 // We must write that the profile and metrics service shutdown cleanly, | 463 // We must write that the profile and metrics service shutdown cleanly, |
| 405 // otherwise on startup we'll think we crashed. So we block until done and | 464 // otherwise on startup we'll think we crashed. So we block until done and |
| 406 // then proceed with normal shutdown. | 465 // then proceed with normal shutdown. |
| 407 #if defined(USE_X11) || defined(OS_WIN) | 466 #if defined(USE_X11) || defined(OS_WIN) |
| 408 // Create a waitable event to block on file writing being complete. | 467 // Wait on the successful countdown of rundown tasks. |
| 409 // | 468 // |
| 410 // On Windows, we previously posted a message to FILE and then ran a nested | 469 // On Windows, we previously posted a message to FILE and then ran a nested |
| 411 // message loop, waiting for that message to be processed until quitting. | 470 // message loop, waiting for that message to be processed until quitting. |
| 412 // However, doing so means that other messages will also be processed. In | 471 // However, doing so means that other messages will also be processed. In |
| 413 // particular, if the GPU process host notices that the GPU has been killed | 472 // particular, if the GPU process host notices that the GPU has been killed |
| 414 // during shutdown, it races exiting the nested loop with the process host | 473 // during shutdown, it races exiting the nested loop with the process host |
| 415 // blocking the message loop attempting to re-establish a connection to the | 474 // blocking the message loop attempting to re-establish a connection to the |
| 416 // GPU process synchronously. Because the system may not be allowing | 475 // GPU process synchronously. Because the system may not be allowing |
| 417 // processes to launch, this can result in a hang. See | 476 // processes to launch, this can result in a hang. See |
| 418 // http://crbug.com/318527. | 477 // http://crbug.com/318527. |
| 419 scoped_ptr<base::WaitableEvent> done_writing( | 478 if (!counter.get()->TimedWait( |
| 420 new base::WaitableEvent(false, false)); | |
| 421 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
| 422 base::Bind(Signal, done_writing.get())); | |
| 423 // If all file writes haven't cleared in the timeout, leak the WaitableEvent | |
| 424 // so that there's no race to reference it in Signal(). | |
| 425 if (!done_writing->TimedWait( | |
| 426 base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds))) { | 479 base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds))) { |
| 427 ignore_result(done_writing.release()); | 480 // If the rundown tasks don't finish in time, we leak the counter, to |
| 481 // avoid use-after-free in the tasks. | |
| 482 ignore_result(counter.release()); | |
| 428 } | 483 } |
| 429 #else | 484 #else |
| 430 NOTIMPLEMENTED(); | 485 NOTIMPLEMENTED(); |
| 431 #endif | 486 #endif |
| 432 } | 487 } |
| 433 | 488 |
| 434 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { | 489 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { |
| 435 DCHECK(CalledOnValidThread()); | 490 DCHECK(CalledOnValidThread()); |
| 436 if (!metrics_services_manager_) | 491 if (!metrics_services_manager_) |
| 437 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); | 492 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); |
| (...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1101 } | 1156 } |
| 1102 | 1157 |
| 1103 void BrowserProcessImpl::OnAutoupdateTimer() { | 1158 void BrowserProcessImpl::OnAutoupdateTimer() { |
| 1104 if (CanAutorestartForUpdate()) { | 1159 if (CanAutorestartForUpdate()) { |
| 1105 DLOG(WARNING) << "Detected update. Restarting browser."; | 1160 DLOG(WARNING) << "Detected update. Restarting browser."; |
| 1106 RestartBackgroundInstance(); | 1161 RestartBackgroundInstance(); |
| 1107 } | 1162 } |
| 1108 } | 1163 } |
| 1109 | 1164 |
| 1110 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) | 1165 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) |
| OLD | NEW |