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

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

Powered by Google App Engine
This is Rietveld 408576698