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

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: BookmarkStorage changes pulled out to issue 370323002. Created 6 years, 5 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
11 #include "base/atomic_ref_count.h"
11 #include "base/bind.h" 12 #include "base/bind.h"
12 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
13 #include "base/command_line.h" 14 #include "base/command_line.h"
14 #include "base/debug/alias.h" 15 #include "base/debug/alias.h"
15 #include "base/debug/leak_annotations.h" 16 #include "base/debug/leak_annotations.h"
16 #include "base/files/file_path.h" 17 #include "base/files/file_path.h"
17 #include "base/path_service.h" 18 #include "base/path_service.h"
18 #include "base/prefs/json_pref_store.h" 19 #include "base/prefs/json_pref_store.h"
19 #include "base/prefs/pref_registry_simple.h" 20 #include "base/prefs/pref_registry_simple.h"
20 #include "base/prefs/pref_service.h" 21 #include "base/prefs/pref_service.h"
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 // Reset associated state right after actual thread is stopped, 309 // Reset associated state right after actual thread is stopped,
309 // as io_thread_.global_ cleanup happens in CleanUp on the IO 310 // as io_thread_.global_ cleanup happens in CleanUp on the IO
310 // thread, i.e. as the thread exits its message loop. 311 // thread, i.e. as the thread exits its message loop.
311 // 312 //
312 // This is important also because in various places, the 313 // This is important also because in various places, the
313 // IOThread object being NULL is considered synonymous with the 314 // IOThread object being NULL is considered synonymous with the
314 // IO thread having stopped. 315 // IO thread having stopped.
315 io_thread_.reset(); 316 io_thread_.reset();
316 } 317 }
317 318
318 #if defined(USE_X11) || defined(OS_WIN)
319 static void Signal(base::WaitableEvent* event) {
320 event->Signal();
321 }
322 #endif
323
324 unsigned int BrowserProcessImpl::AddRefModule() { 319 unsigned int BrowserProcessImpl::AddRefModule() {
325 DCHECK(CalledOnValidThread()); 320 DCHECK(CalledOnValidThread());
326 321
327 // CHECK(!IsShuttingDown()); 322 // CHECK(!IsShuttingDown());
328 if (IsShuttingDown()) { 323 if (IsShuttingDown()) {
329 // Copy the stacktrace which released the final reference onto our stack so 324 // Copy the stacktrace which released the final reference onto our stack so
330 // it will be available in the crash report for inspection. 325 // it will be available in the crash report for inspection.
331 base::debug::StackTrace callstack = release_last_reference_callstack_; 326 base::debug::StackTrace callstack = release_last_reference_callstack_;
332 base::debug::Alias(&callstack); 327 base::debug::Alias(&callstack);
333 CHECK(false); 328 CHECK(false);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 #if defined(OS_MACOSX) 372 #if defined(OS_MACOSX)
378 base::MessageLoop::current()->PostTask( 373 base::MessageLoop::current()->PostTask(
379 FROM_HERE, 374 FROM_HERE,
380 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop)); 375 base::Bind(ChromeBrowserMainPartsMac::DidEndMainMessageLoop));
381 #endif 376 #endif
382 base::MessageLoop::current()->Quit(); 377 base::MessageLoop::current()->Quit();
383 } 378 }
384 return module_ref_count_; 379 return module_ref_count_;
385 } 380 }
386 381
382 namespace {
383
384 // Used at the end of session to block the UI thread for completion of sentinel
385 // tasks on the set of threads used to persist profile data and local state.
386 // This is done to ensure that the data has been persisted to disk before
387 // continuing.
388 class RundownTaskCounter :
389 public base::RefCountedThreadSafe<RundownTaskCounter> {
390 public:
391 RundownTaskCounter();
392
393 // Posts a rundown task to |task_runner|, can be invoked an arbitrary number
394 // of times before calling TimedWait.
395 void Post(base::SequencedTaskRunner* task_runner);
396
397 // Waits until the count is zero or |max_time| has passed.
398 // This can only be called once per instance.
399 bool TimedWait(const base::TimeDelta& max_time);
400
401 private:
402 friend class base::RefCountedThreadSafe<RundownTaskCounter>;
403 ~RundownTaskCounter() {}
404
405 // Decrements the counter and releases the waitable event on transition to
406 // zero.
407 void Decrement();
408
409 // The count starts at one to defer the possibility of one->zero transitions
410 // until TimedWait is called.
411 base::AtomicRefCount count_;
412 base::WaitableEvent waitable_event_;
413
414 DISALLOW_COPY_AND_ASSIGN(RundownTaskCounter);
415 };
416
417 RundownTaskCounter::RundownTaskCounter()
418 : count_(1), waitable_event_(true, false) {
419 }
420
421 void RundownTaskCounter::Post(base::SequencedTaskRunner* task_runner) {
422 // As the count starts off at one, it should never get to zero unless
423 // TimedWait has been called.
424 DCHECK(!base::AtomicRefCountIsZero(&count_));
425
426 base::AtomicRefCountInc(&count_);
427
428 task_runner->PostTask(FROM_HERE,
429 base::Bind(&RundownTaskCounter::Decrement, this));
430 }
431
432 void RundownTaskCounter::Decrement() {
433 if (!base::AtomicRefCountDec(&count_))
434 waitable_event_.Signal();
435 }
436
437 bool RundownTaskCounter::TimedWait(const base::TimeDelta& max_time) {
438 // Decrement the excess count from the constructor.
439 Decrement();
440
441 return waitable_event_.TimedWait(max_time);
442 }
443
444 } // namespace
445
387 void BrowserProcessImpl::EndSession() { 446 void BrowserProcessImpl::EndSession() {
388 // Mark all the profiles as clean. 447 // Mark all the profiles as clean.
389 ProfileManager* pm = profile_manager(); 448 ProfileManager* pm = profile_manager();
390 std::vector<Profile*> profiles(pm->GetLoadedProfiles()); 449 std::vector<Profile*> profiles(pm->GetLoadedProfiles());
391 for (size_t i = 0; i < profiles.size(); ++i) 450 scoped_refptr<RundownTaskCounter> rundown_counter(new RundownTaskCounter());
392 profiles[i]->SetExitType(Profile::EXIT_SESSION_ENDED); 451 for (size_t i = 0; i < profiles.size(); ++i) {
452 Profile* profile = profiles[i];
453 profile->SetExitType(Profile::EXIT_SESSION_ENDED);
454
455 rundown_counter->Post(profile->GetIOTaskRunner());
456 }
393 457
394 // Tell the metrics service it was cleanly shutdown. 458 // Tell the metrics service it was cleanly shutdown.
395 MetricsService* metrics = g_browser_process->metrics_service(); 459 MetricsService* metrics = g_browser_process->metrics_service();
396 if (metrics && local_state()) { 460 if (metrics && local_state()) {
397 metrics->RecordStartOfSessionEnd(); 461 metrics->RecordStartOfSessionEnd();
398 #if !defined(OS_CHROMEOS) 462 #if !defined(OS_CHROMEOS)
399 // MetricsService lazily writes to prefs, force it to write now. 463 // MetricsService lazily writes to prefs, force it to write now.
400 // On ChromeOS, chrome gets killed when hangs, so no need to 464 // On ChromeOS, chrome gets killed when hangs, so no need to
401 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately. 465 // commit metrics::prefs::kStabilitySessionEndCompleted change immediately.
402 local_state()->CommitPendingWrite(); 466 local_state()->CommitPendingWrite();
467
468 rundown_counter->Post(local_state_task_runner_);
403 #endif 469 #endif
404 } 470 }
405 471
406 // http://crbug.com/125207 472 // http://crbug.com/125207
407 base::ThreadRestrictions::ScopedAllowWait allow_wait; 473 base::ThreadRestrictions::ScopedAllowWait allow_wait;
408 474
409 // We must write that the profile and metrics service shutdown cleanly, 475 // We must write that the profile and metrics service shutdown cleanly,
410 // otherwise on startup we'll think we crashed. So we block until done and 476 // otherwise on startup we'll think we crashed. So we block until done and
411 // then proceed with normal shutdown. 477 // then proceed with normal shutdown.
412 #if defined(USE_X11) || defined(OS_WIN) 478 #if defined(USE_X11) || defined(OS_WIN)
413 // Create a waitable event to block on file writing being complete. 479 // Do a best-effort wait on the successful countdown of rundown tasks. Note
480 // that if we don't complete "quickly enough", Windows will terminate our
481 // process.
414 // 482 //
415 // On Windows, we previously posted a message to FILE and then ran a nested 483 // On Windows, we previously posted a message to FILE and then ran a nested
416 // message loop, waiting for that message to be processed until quitting. 484 // message loop, waiting for that message to be processed until quitting.
417 // However, doing so means that other messages will also be processed. In 485 // However, doing so means that other messages will also be processed. In
418 // particular, if the GPU process host notices that the GPU has been killed 486 // particular, if the GPU process host notices that the GPU has been killed
419 // during shutdown, it races exiting the nested loop with the process host 487 // during shutdown, it races exiting the nested loop with the process host
420 // blocking the message loop attempting to re-establish a connection to the 488 // blocking the message loop attempting to re-establish a connection to the
421 // GPU process synchronously. Because the system may not be allowing 489 // GPU process synchronously. Because the system may not be allowing
422 // processes to launch, this can result in a hang. See 490 // processes to launch, this can result in a hang. See
423 // http://crbug.com/318527. 491 // http://crbug.com/318527.
424 scoped_ptr<base::WaitableEvent> done_writing( 492 rundown_counter->TimedWait(
425 new base::WaitableEvent(false, false)); 493 base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds));
426 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
427 base::Bind(Signal, done_writing.get()));
428 // If all file writes haven't cleared in the timeout, leak the WaitableEvent
429 // so that there's no race to reference it in Signal().
430 if (!done_writing->TimedWait(
431 base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds))) {
432 ignore_result(done_writing.release());
433 }
434 #else 494 #else
435 NOTIMPLEMENTED(); 495 NOTIMPLEMENTED();
436 #endif 496 #endif
437 } 497 }
438 498
439 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() { 499 MetricsServicesManager* BrowserProcessImpl::GetMetricsServicesManager() {
440 DCHECK(CalledOnValidThread()); 500 DCHECK(CalledOnValidThread());
441 if (!metrics_services_manager_) 501 if (!metrics_services_manager_)
442 metrics_services_manager_.reset(new MetricsServicesManager(local_state())); 502 metrics_services_manager_.reset(new MetricsServicesManager(local_state()));
443 return metrics_services_manager_.get(); 503 return metrics_services_manager_.get();
(...skipping 664 matching lines...) Expand 10 before | Expand all | Expand 10 after
1108 } 1168 }
1109 1169
1110 void BrowserProcessImpl::OnAutoupdateTimer() { 1170 void BrowserProcessImpl::OnAutoupdateTimer() {
1111 if (CanAutorestartForUpdate()) { 1171 if (CanAutorestartForUpdate()) {
1112 DLOG(WARNING) << "Detected update. Restarting browser."; 1172 DLOG(WARNING) << "Detected update. Restarting browser.";
1113 RestartBackgroundInstance(); 1173 RestartBackgroundInstance();
1114 } 1174 }
1115 } 1175 }
1116 1176
1117 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) 1177 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698