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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/browser_process_impl.cc
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 7f492c575c22e6ae13b52c0ff07ba29c145f9eb6..a611417e8c55b42ba53b4f37af54f8aaed100867 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -379,12 +379,66 @@ unsigned int BrowserProcessImpl::ReleaseModule() {
return module_ref_count_;
}
+namespace {
+
+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
+ public:
+ // Creates a rundown task counter with |count|.
+ explicit RundownTaskCounter(size_t count);
+ ~RundownTaskCounter() {}
+
+ // Decrements the counter and releases the wait on zero.
+ static void Decrement(RundownTaskCounter* counter);
+
+ // Waits until the count is zero or |max_time| has passed.
+ bool TimedWait(const base::TimeDelta& max_time);
+
+ private:
+ base::AtomicRefCount count_;
+ base::WaitableEvent waitable_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(RundownTaskCounter);
+};
+
+RundownTaskCounter::RundownTaskCounter(size_t count)
+ : count_(count), waitable_event_(true, false) {
+ DCHECK_LT(1U, count);
gab 2014/06/23 21:09:53 DCHECK_GT(count, 1U); (We always put constants on
+}
+
+void RundownTaskCounter::Decrement(RundownTaskCounter* counter) {
+ DCHECK_NE(static_cast<RundownTaskCounter*>(NULL), counter);
gab 2014/06/23 21:09:53 DCHECK(counter);
+
+ if (!base::AtomicRefCountDec(&counter->count_)) {
+ counter->waitable_event_.Signal();
+ }
+}
+
+bool RundownTaskCounter::TimedWait(const base::TimeDelta& max_time) {
+ return waitable_event_.TimedWait(max_time);
+}
+
+} // namespace
+
void BrowserProcessImpl::EndSession() {
// Mark all the profiles as clean.
ProfileManager* pm = profile_manager();
std::vector<Profile*> profiles(pm->GetLoadedProfiles());
- for (size_t i = 0; i < profiles.size(); ++i)
- profiles[i]->SetExitType(Profile::EXIT_SESSION_ENDED);
+
+ // We create the rundown task counter with a count for each profile,
+ // plus one for local state.
+ scoped_ptr<RundownTaskCounter> counter(
+ new RundownTaskCounter(profiles.size() + 1));
+
+ for (size_t i = 0; i < profiles.size(); ++i) {
+ Profile* profile = profiles[i];
+ profile->SetExitType(Profile::EXIT_SESSION_ENDED);
+
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner =
+ profile->GetIOTaskRunner();
+ io_task_runner->PostTask(FROM_HERE,
+ base::Bind(RundownTaskCounter::Decrement,
+ counter.get()));
+ }
// Tell the metrics service it was cleanly shutdown.
MetricsService* metrics = g_browser_process->metrics_service();
@@ -395,6 +449,11 @@ void BrowserProcessImpl::EndSession() {
// On ChromeOS, chrome gets killed when hangs, so no need to
// commit metrics::prefs::kStabilitySessionEndCompleted change immediately.
local_state()->CommitPendingWrite();
+
+ local_state_task_runner_->PostTask(FROM_HERE,
+ 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.
+ 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
+
gab 2014/06/23 21:09:53 rm empty line
Sigurður Ásgeirsson 2014/06/23 21:39:59 Done.
#endif
}
@@ -405,7 +464,7 @@ void BrowserProcessImpl::EndSession() {
// otherwise on startup we'll think we crashed. So we block until done and
// then proceed with normal shutdown.
#if defined(USE_X11) || defined(OS_WIN)
- // Create a waitable event to block on file writing being complete.
+ // Wait on the successful countdown of rundown tasks.
//
// On Windows, we previously posted a message to FILE and then ran a nested
// message loop, waiting for that message to be processed until quitting.
@@ -416,15 +475,11 @@ void BrowserProcessImpl::EndSession() {
// GPU process synchronously. Because the system may not be allowing
// processes to launch, this can result in a hang. See
// http://crbug.com/318527.
- scoped_ptr<base::WaitableEvent> done_writing(
- new base::WaitableEvent(false, false));
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(Signal, done_writing.get()));
- // If all file writes haven't cleared in the timeout, leak the WaitableEvent
- // so that there's no race to reference it in Signal().
- if (!done_writing->TimedWait(
+ if (!counter.get()->TimedWait(
base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds))) {
- ignore_result(done_writing.release());
+ // If the rundown tasks don't finish in time, we leak the counter, to
+ // avoid use-after-free in the tasks.
+ ignore_result(counter.release());
}
#else
NOTIMPLEMENTED();
« 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