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 |