| Index: chrome/browser/browser_process_impl.cc
|
| diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
|
| index e014c1803ea454929ce339613e4ed93614a111b5..a36ac9fa8ed0e36a3cdbc28cb6ed078173008095 100644
|
| --- a/chrome/browser/browser_process_impl.cc
|
| +++ b/chrome/browser/browser_process_impl.cc
|
| @@ -8,7 +8,6 @@
|
| #include <map>
|
| #include <vector>
|
|
|
| -#include "base/atomic_ref_count.h"
|
| #include "base/bind.h"
|
| #include "base/bind_helpers.h"
|
| #include "base/command_line.h"
|
| @@ -316,6 +315,12 @@
|
| io_thread_.reset();
|
| }
|
|
|
| +#if defined(USE_X11) || defined(OS_WIN)
|
| +static void Signal(base::WaitableEvent* event) {
|
| + event->Signal();
|
| +}
|
| +#endif
|
| +
|
| unsigned int BrowserProcessImpl::AddRefModule() {
|
| DCHECK(CalledOnValidThread());
|
|
|
| @@ -379,81 +384,12 @@
|
| return module_ref_count_;
|
| }
|
|
|
| -namespace {
|
| -
|
| -// Used at the end of session to block the UI thread for completion of sentinel
|
| -// tasks on the set of threads used to persist profile data and local state.
|
| -// This is done to ensure that the data has been persisted to disk before
|
| -// continuing.
|
| -class RundownTaskCounter :
|
| - public base::RefCountedThreadSafe<RundownTaskCounter> {
|
| - public:
|
| - RundownTaskCounter();
|
| -
|
| - // Posts a rundown task to |task_runner|, can be invoked an arbitrary number
|
| - // of times before calling TimedWait.
|
| - void Post(base::SequencedTaskRunner* task_runner);
|
| -
|
| - // Waits until the count is zero or |max_time| has passed.
|
| - // This can only be called once per instance.
|
| - bool TimedWait(const base::TimeDelta& max_time);
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<RundownTaskCounter>;
|
| - ~RundownTaskCounter() {}
|
| -
|
| - // Decrements the counter and releases the waitable event on transition to
|
| - // zero.
|
| - void Decrement();
|
| -
|
| - // The count starts at one to defer the possibility of one->zero transitions
|
| - // until TimedWait is called.
|
| - base::AtomicRefCount count_;
|
| - base::WaitableEvent waitable_event_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(RundownTaskCounter);
|
| -};
|
| -
|
| -RundownTaskCounter::RundownTaskCounter()
|
| - : count_(1), waitable_event_(true, false) {
|
| -}
|
| -
|
| -void RundownTaskCounter::Post(base::SequencedTaskRunner* task_runner) {
|
| - // As the count starts off at one, it should never get to zero unless
|
| - // TimedWait has been called.
|
| - DCHECK(!base::AtomicRefCountIsZero(&count_));
|
| -
|
| - base::AtomicRefCountInc(&count_);
|
| -
|
| - task_runner->PostTask(FROM_HERE,
|
| - base::Bind(&RundownTaskCounter::Decrement, this));
|
| -}
|
| -
|
| -void RundownTaskCounter::Decrement() {
|
| - if (!base::AtomicRefCountDec(&count_))
|
| - waitable_event_.Signal();
|
| -}
|
| -
|
| -bool RundownTaskCounter::TimedWait(const base::TimeDelta& max_time) {
|
| - // Decrement the excess count from the constructor.
|
| - Decrement();
|
| -
|
| - 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());
|
| - scoped_refptr<RundownTaskCounter> rundown_counter(new RundownTaskCounter());
|
| - for (size_t i = 0; i < profiles.size(); ++i) {
|
| - Profile* profile = profiles[i];
|
| - profile->SetExitType(Profile::EXIT_SESSION_ENDED);
|
| -
|
| - rundown_counter->Post(profile->GetIOTaskRunner());
|
| - }
|
| + for (size_t i = 0; i < profiles.size(); ++i)
|
| + profiles[i]->SetExitType(Profile::EXIT_SESSION_ENDED);
|
|
|
| // Tell the metrics service it was cleanly shutdown.
|
| MetricsService* metrics = g_browser_process->metrics_service();
|
| @@ -464,8 +400,6 @@
|
| // On ChromeOS, chrome gets killed when hangs, so no need to
|
| // commit metrics::prefs::kStabilitySessionEndCompleted change immediately.
|
| local_state()->CommitPendingWrite();
|
| -
|
| - rundown_counter->Post(local_state_task_runner_);
|
| #endif
|
| }
|
|
|
| @@ -476,9 +410,7 @@
|
| // 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)
|
| - // 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.
|
| + // Create a waitable event to block on file writing being complete.
|
| //
|
| // 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.
|
| @@ -489,8 +421,16 @@
|
| // GPU process synchronously. Because the system may not be allowing
|
| // processes to launch, this can result in a hang. See
|
| // http://crbug.com/318527.
|
| - rundown_counter->TimedWait(
|
| - base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds));
|
| + 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());
|
| + }
|
| #else
|
| NOTIMPLEMENTED();
|
| #endif
|
|
|