| Index: chrome/browser/browser_process_impl.cc
|
| diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
|
| index 39dc70edf71dbc9bbb7802e5129715c43cb1c344..8c3272e24499a2587bc2ad66e12756d829ae1007 100644
|
| --- a/chrome/browser/browser_process_impl.cc
|
| +++ b/chrome/browser/browser_process_impl.cc
|
| @@ -7,6 +7,7 @@
|
| #include <stddef.h>
|
|
|
| #include <algorithm>
|
| +#include <iterator>
|
| #include <map>
|
| #include <utility>
|
| #include <vector>
|
| @@ -398,6 +399,8 @@ void BrowserProcessImpl::PostDestroyThreads() {
|
|
|
| namespace {
|
|
|
| +using TaskRunnerVector = std::vector<scoped_refptr<base::SequencedTaskRunner>>;
|
| +
|
| // 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
|
| @@ -411,6 +414,10 @@ class RundownTaskCounter :
|
| // of times before calling TimedWait.
|
| void Post(base::SequencedTaskRunner* task_runner);
|
|
|
| + // Posts a rundown task to each runner in |runners|, where the rundown task
|
| + // for runner[n+1] is posted during rundown task execution for runner[n].
|
| + void PostSerially(TaskRunnerVector runners);
|
| +
|
| // Waits until the count is zero or |end_time| is reached.
|
| // This can only be called once per instance. Returns true if a count of zero
|
| // is reached or false if the |end_time| is reached. It is valid to pass an
|
| @@ -425,6 +432,9 @@ class RundownTaskCounter :
|
| // zero.
|
| void Decrement();
|
|
|
| + void RundownSerially(TaskRunnerVector::const_iterator it,
|
| + TaskRunnerVector runner);
|
| +
|
| // The count starts at one to defer the possibility of one->zero transitions
|
| // until TimedWait is called.
|
| base::AtomicRefCount count_;
|
| @@ -451,6 +461,16 @@ void RundownTaskCounter::Post(base::SequencedTaskRunner* task_runner) {
|
| base::Bind(&RundownTaskCounter::Decrement, this));
|
| }
|
|
|
| +void RundownTaskCounter::PostSerially(TaskRunnerVector runners) {
|
| + if (runners.empty())
|
| + return;
|
| + base::AtomicRefCountInc(&count_);
|
| + TaskRunnerVector::const_iterator it = runners.begin();
|
| + (*it)->PostNonNestableTask(
|
| + FROM_HERE, base::Bind(&RundownTaskCounter::RundownSerially, this, it + 1,
|
| + base::Passed(&runners)));
|
| +}
|
| +
|
| void RundownTaskCounter::Decrement() {
|
| if (!base::AtomicRefCountDec(&count_))
|
| waitable_event_.Signal();
|
| @@ -463,6 +483,17 @@ bool RundownTaskCounter::TimedWaitUntil(const base::TimeTicks& end_time) {
|
| return waitable_event_.TimedWaitUntil(end_time);
|
| }
|
|
|
| +void RundownTaskCounter::RundownSerially(TaskRunnerVector::const_iterator it,
|
| + TaskRunnerVector runners) {
|
| + if (it == runners.end()) {
|
| + Decrement();
|
| + return;
|
| + }
|
| + (*it)->PostNonNestableTask(
|
| + FROM_HERE, base::Bind(&RundownTaskCounter::RundownSerially, this, it + 1,
|
| + base::Passed(&runners)));
|
| +}
|
| +
|
| } // namespace
|
|
|
| void BrowserProcessImpl::EndSession() {
|
| @@ -473,8 +504,7 @@ void BrowserProcessImpl::EndSession() {
|
| const bool pref_service_enabled =
|
| base::FeatureList::IsEnabled(features::kPrefService);
|
| std::vector<scoped_refptr<base::SequencedTaskRunner>> profile_writer_runners;
|
| - for (size_t i = 0; i < profiles.size(); ++i) {
|
| - Profile* profile = profiles[i];
|
| + for (Profile* profile : profiles) {
|
| profile->SetExitType(Profile::EXIT_SESSION_ENDED);
|
| if (profile->GetPrefs()) {
|
| profile->GetPrefs()->CommitPendingWrite();
|
| @@ -527,15 +557,31 @@ void BrowserProcessImpl::EndSession() {
|
| // processes to launch, this can result in a hang. See
|
| // http://crbug.com/318527.
|
| const base::TimeTicks end_time = base::TimeTicks::Now() + kEndSessionTimeout;
|
| - const bool timed_out = !rundown_counter->TimedWaitUntil(end_time);
|
| - if (timed_out || !pref_service_enabled)
|
| + if (!rundown_counter->TimedWaitUntil(end_time))
|
| return;
|
|
|
| - scoped_refptr<RundownTaskCounter> profile_write_rundown_counter(
|
| + if (pref_service_enabled) {
|
| + scoped_refptr<RundownTaskCounter> profile_write_rundown_counter(
|
| + new RundownTaskCounter());
|
| + for (auto& profile_writer_runner : profile_writer_runners)
|
| + profile_write_rundown_counter->Post(profile_writer_runner.get());
|
| + if (!profile_write_rundown_counter->TimedWaitUntil(end_time))
|
| + return;
|
| + }
|
| +
|
| + // Time permitting, give other storage systems a chance to flush caches.
|
| + auto flush_function = [](scoped_refptr<RundownTaskCounter> rundown_counter,
|
| + content::StoragePartition* partition) {
|
| + rundown_counter->PostSerially(partition->Flush());
|
| + };
|
| + scoped_refptr<RundownTaskCounter> flush_storage_rundown_counter(
|
| new RundownTaskCounter());
|
| - for (auto& profile_writer_runner : profile_writer_runners)
|
| - profile_write_rundown_counter->Post(profile_writer_runner.get());
|
| - profile_write_rundown_counter->TimedWaitUntil(end_time);
|
| + for (Profile* profile : profiles) {
|
| + content::BrowserContext::ForEachStoragePartition(
|
| + profile,
|
| + base::BindRepeating(flush_function, flush_storage_rundown_counter));
|
| + }
|
| + flush_storage_rundown_counter->TimedWaitUntil(end_time);
|
| #else
|
| NOTIMPLEMENTED();
|
| #endif
|
|
|