| 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..ffbbec0bd54ed68f1f34ddaf5cab8ec839783e0c 100644
|
| --- a/chrome/browser/browser_process_impl.cc
|
| +++ b/chrome/browser/browser_process_impl.cc
|
| @@ -379,12 +379,70 @@ unsigned int BrowserProcessImpl::ReleaseModule() {
|
| return module_ref_count_;
|
| }
|
|
|
| +namespace {
|
| +
|
| +class RundownTaskCounter :
|
| + public base::RefCountedThreadSafe<RundownTaskCounter> {
|
| + public:
|
| + // Creates a rundown task counter with |count|.
|
| + explicit RundownTaskCounter(size_t count);
|
| +
|
| +
|
| + // 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:
|
| + friend class base::RefCountedThreadSafe<RundownTaskCounter>;
|
| + ~RundownTaskCounter() {}
|
| +
|
| + 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);
|
| +}
|
| +
|
| +void RundownTaskCounter::Decrement(RundownTaskCounter* counter) {
|
| + DCHECK_NE(static_cast<RundownTaskCounter*>(NULL), 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_refptr<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 +453,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,
|
| + counter.get()));
|
| +
|
| #endif
|
| }
|
|
|
| @@ -405,7 +468,9 @@ 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.
|
| + // Do a best-effort wait on the successful countdown of rundown tasks. Note
|
| + // that if we don't complete "quickly enough", Windows will terminate our
|
| + // process.
|
| //
|
| // 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,16 +481,8 @@ 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(
|
| - base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds))) {
|
| - ignore_result(done_writing.release());
|
| - }
|
| + counter.get()->TimedWait(
|
| + base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds));
|
| #else
|
| NOTIMPLEMENTED();
|
| #endif
|
|
|