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

Side by Side Diff: chrome/browser/browser_process_impl.cc

Issue 349263004: Fix Windows logoff race. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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
OLDNEW
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
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
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)
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/lifetime/application_lifetime.cc » ('j') | chrome/browser/lifetime/application_lifetime.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698