Index: content/browser/browser_main_loop.cc |
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc |
index e343427bf6f4e3e5e7263fdd52e97e7fffb849b4..6f9fd2a55f3bd151c7c266737b685593b61db7b7 100644 |
--- a/content/browser/browser_main_loop.cc |
+++ b/content/browser/browser_main_loop.cc |
@@ -1259,86 +1259,88 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() { |
service_manager_context_.reset(); |
mojo_ipc_support_.reset(); |
- // Must be size_t so we can subtract from it. |
- for (size_t thread_id = BrowserThread::ID_COUNT - 1; |
- thread_id >= (BrowserThread::UI + 1); |
- --thread_id) { |
- // Find the thread object we want to stop. Looping over all valid |
- // BrowserThread IDs and DCHECKing on a missing case in the switch |
- // statement helps avoid a mismatch between this code and the |
- // BrowserThread::ID enumeration. |
- // |
- // The destruction order is the reverse order of occurrence in the |
- // BrowserThread::ID list. The rationale for the order is as |
- // follows (need to be filled in a bit): |
- // |
- // |
- // - The IO thread is the only user of the CACHE thread. |
- // |
- // - The PROCESS_LAUNCHER thread must be stopped after IO in case |
- // the IO thread posted a task to terminate a process on the |
- // process launcher thread. |
- // |
- // - (Not sure why DB stops last.) |
- switch (thread_id) { |
- case BrowserThread::DB: { |
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:DBThread"); |
- ResetThread_DB(std::move(db_thread_)); |
- break; |
- } |
- case BrowserThread::FILE: { |
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:FileThread"); |
- // Clean up state that lives on or uses the FILE thread before it goes |
- // away. |
- save_file_manager_->Shutdown(); |
- ResetThread_FILE(std::move(file_thread_)); |
- break; |
- } |
- case BrowserThread::FILE_USER_BLOCKING: { |
- TRACE_EVENT0("shutdown", |
- "BrowserMainLoop::Subsystem:FileUserBlockingThread"); |
- ResetThread_FILE_USER_BLOCKING(std::move(file_user_blocking_thread_)); |
- break; |
- } |
- case BrowserThread::PROCESS_LAUNCHER: { |
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:LauncherThread"); |
- ResetThread_PROCESS_LAUNCHER(std::move(process_launcher_thread_)); |
- break; |
- } |
- case BrowserThread::CACHE: { |
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:CacheThread"); |
- ResetThread_CACHE(std::move(cache_thread_)); |
- break; |
- } |
- case BrowserThread::IO: { |
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread"); |
- ResetThread_IO(std::move(io_thread_)); |
- break; |
+ { |
+ base::ThreadRestrictions::ScopedAllowWait allow_wait_for_join; |
+ |
+ // Must be size_t so we can subtract from it. |
+ for (size_t thread_id = BrowserThread::ID_COUNT - 1; |
+ thread_id >= (BrowserThread::UI + 1); --thread_id) { |
+ // Find the thread object we want to stop. Looping over all valid |
+ // BrowserThread IDs and DCHECKing on a missing case in the switch |
+ // statement helps avoid a mismatch between this code and the |
+ // BrowserThread::ID enumeration. |
+ // |
+ // The destruction order is the reverse order of occurrence in the |
+ // BrowserThread::ID list. The rationale for the order is as follows (need |
+ // to be filled in a bit): |
+ // |
+ // - The IO thread is the only user of the CACHE thread. |
+ // |
+ // - The PROCESS_LAUNCHER thread must be stopped after IO in case |
+ // the IO thread posted a task to terminate a process on the |
+ // process launcher thread. |
+ // |
+ // - (Not sure why DB stops last.) |
+ switch (thread_id) { |
+ case BrowserThread::DB: { |
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:DBThread"); |
+ ResetThread_DB(std::move(db_thread_)); |
+ break; |
+ } |
+ case BrowserThread::FILE: { |
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:FileThread"); |
+ // Clean up state that lives on or uses the FILE thread before it goes |
+ // away. |
+ save_file_manager_->Shutdown(); |
+ ResetThread_FILE(std::move(file_thread_)); |
+ break; |
+ } |
+ case BrowserThread::FILE_USER_BLOCKING: { |
+ TRACE_EVENT0("shutdown", |
+ "BrowserMainLoop::Subsystem:FileUserBlockingThread"); |
+ ResetThread_FILE_USER_BLOCKING(std::move(file_user_blocking_thread_)); |
+ break; |
+ } |
+ case BrowserThread::PROCESS_LAUNCHER: { |
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:LauncherThread"); |
+ ResetThread_PROCESS_LAUNCHER(std::move(process_launcher_thread_)); |
+ break; |
+ } |
+ case BrowserThread::CACHE: { |
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:CacheThread"); |
+ ResetThread_CACHE(std::move(cache_thread_)); |
+ break; |
+ } |
+ case BrowserThread::IO: { |
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread"); |
+ ResetThread_IO(std::move(io_thread_)); |
+ break; |
+ } |
+ case BrowserThread::UI: |
+ case BrowserThread::ID_COUNT: |
+ NOTREACHED(); |
+ break; |
} |
- case BrowserThread::UI: |
- case BrowserThread::ID_COUNT: |
- NOTREACHED(); |
- break; |
} |
- } |
- { |
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IndexedDBThread"); |
- ResetThread_IndexedDb(std::move(indexed_db_thread_)); |
- } |
+ { |
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IndexedDBThread"); |
+ ResetThread_IndexedDb(std::move(indexed_db_thread_)); |
+ } |
- // Close the blocking I/O pool after the other threads. Other threads such |
- // as the I/O thread may need to schedule work like closing files or flushing |
- // data during shutdown, so the blocking pool needs to be available. There |
- // may also be slow operations pending that will blcok shutdown, so closing |
- // it here (which will block until required operations are complete) gives |
- // more head start for those operations to finish. |
- { |
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:ThreadPool"); |
- BrowserThreadImpl::ShutdownThreadPool(); |
- } |
- { |
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:TaskScheduler"); |
- base::TaskScheduler::GetInstance()->Shutdown(); |
+ // Close the blocking I/O pool after the other threads. Other threads such |
+ // as the I/O thread may need to schedule work like closing files or |
+ // flushing data during shutdown, so the blocking pool needs to be |
+ // available. There may also be slow operations pending that will blcok |
+ // shutdown, so closing it here (which will block until required operations |
+ // are complete) gives more head start for those operations to finish. |
+ { |
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:ThreadPool"); |
+ BrowserThreadImpl::ShutdownThreadPool(); |
+ } |
+ { |
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:TaskScheduler"); |
+ base::TaskScheduler::GetInstance()->Shutdown(); |
+ } |
} |
// Must happen after the IO thread is shutdown since this may be accessed from |