ThreadRestrictions: disallow blocking IO on the UI thread

This patch sets the "disallow IO" flag after the UI thread has
started, and then whitelists in the many places where we're
accidentally doing IO from the UI thread.  (I've filed bugs
on all of those cases.)

BUG=59847,60630,60641,60211,60634,60643,24163,60825

Review URL: http://codereview.chromium.org/4146004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63986 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/nss_util.cc b/base/nss_util.cc
index 5c7cafd5..95b0082 100644
--- a/base/nss_util.cc
+++ b/base/nss_util.cc
@@ -22,6 +22,7 @@
 #include "base/logging.h"
 #include "base/singleton.h"
 #include "base/stringprintf.h"
+#include "base/thread_restrictions.h"
 
 // USE_NSS means we use NSS for everything crypto-related.  If USE_NSS is not
 // defined, such as on Mac and Windows, we use NSS for SSL only -- we don't
@@ -310,6 +311,10 @@
 }
 
 void EnsureNSSInit() {
+  // Initializing SSL causes us to do blocking IO.
+  // Temporarily allow it until we fix
+  //   http://code.google.com/p/chromium/issues/detail?id=59847
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   Singleton<NSSInitSingleton>::get();
 }
 
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index e64c218..b18b924 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -21,6 +21,7 @@
 #include "base/path_service.h"
 #include "base/string_util.h"
 #include "base/thread.h"
+#include "base/thread_restrictions.h"
 #include "base/utf_string_conversions.h"
 #include "gfx/point.h"
 #include "chrome/app/chrome_dll_resource.h"
@@ -2336,6 +2337,11 @@
   // --homepage overrides any preferences.
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
   if (command_line.HasSwitch(switches::kHomePage)) {
+    // TODO(evanm): clean up usage of DIR_CURRENT.
+    //   http://code.google.com/p/chromium/issues/detail?id=60630
+    // For now, allow this code to call getcwd().
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+
     FilePath browser_directory;
     PathService::Get(base::DIR_CURRENT, &browser_directory);
     GURL home_page(URLFixerUpper::FixupRelativeFile(browser_directory,
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc
index 731e405d..c1ab3a9 100644
--- a/chrome/browser/browser_init.cc
+++ b/chrome/browser/browser_init.cc
@@ -15,6 +15,7 @@
 #include "base/path_service.h"
 #include "base/scoped_ptr.h"
 #include "base/string_number_conversions.h"
+#include "base/thread_restrictions.h"
 #include "base/utf_string_conversions.h"
 #include "chrome/browser/automation/automation_provider.h"
 #include "chrome/browser/automation/automation_provider_list.h"
@@ -851,7 +852,14 @@
           TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring())));
     } else {
       // This will create a file URL or a regular URL.
-      GURL url(URLFixerUpper::FixupRelativeFile(cur_dir_, param));
+      // This call can (in rare circumstances) block the UI thread.
+      // Allow it until this bug is fixed.
+      //  http://code.google.com/p/chromium/issues/detail?id=60641
+      GURL url;
+      {
+        base::ThreadRestrictions::ScopedAllowIO allow_io;
+        url = URLFixerUpper::FixupRelativeFile(cur_dir_, param);
+      }
       // Exclude dangerous schemes.
       if (url.is_valid()) {
         ChildProcessSecurityPolicy *policy =
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 9b0a628..57f001b7 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -28,6 +28,7 @@
 #include "base/string_split.h"
 #include "base/string_util.h"
 #include "base/sys_string_conversions.h"
+#include "base/thread_restrictions.h"
 #include "base/time.h"
 #include "base/utf_string_conversions.h"
 #include "base/values.h"
@@ -482,6 +483,14 @@
 void RunUIMessageLoop(BrowserProcess* browser_process) {
   TRACE_EVENT_BEGIN("BrowserMain:MESSAGE_LOOP", 0, "");
 
+#if defined(OS_LINUX)
+  // If the UI thread blocks, the whole UI is unresponsive.
+  // Do not allow disk IO from the UI thread.
+  // TODO(evanm): turn this on for all platforms.
+  //   http://code.google.com/p/chromium/issues/detail?id=60211
+  base::ThreadRestrictions::SetIOAllowed(false);
+#endif
+
 #if defined(TOOLKIT_VIEWS)
   views::AcceleratorHandler accelerator_handler;
   MessageLoopForUI::current()->Run(&accelerator_handler);
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index 98e0af7..8f1fb80 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -16,6 +16,7 @@
 #include "base/string_number_conversions.h"
 #include "base/string_util.h"
 #include "base/thread.h"
+#include "base/thread_restrictions.h"
 #include "base/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/about_flags.h"
@@ -100,6 +101,12 @@
 }
 
 void Shutdown() {
+  // During shutdown we will end up some blocking operations.  But the
+  // work needs to get done and we're going to wait for them no matter
+  // what thread they're on, so don't worry about it slowing down
+  // shutdown.
+  base::ThreadRestrictions::SetIOAllowed(true);
+
   // Unload plugins. This needs to happen on the IO thread.
   BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
diff --git a/chrome/browser/dom_ui/options/import_data_handler.cc b/chrome/browser/dom_ui/options/import_data_handler.cc
index d57e616..e4037e3 100644
--- a/chrome/browser/dom_ui/options/import_data_handler.cc
+++ b/chrome/browser/dom_ui/options/import_data_handler.cc
@@ -6,13 +6,14 @@
 
 #include "app/l10n_util.h"
 #include "base/basictypes.h"
+#include "base/callback.h"
 #include "base/scoped_ptr.h"
 #include "base/string16.h"
 #include "base/string_number_conversions.h"
 #include "base/string_util.h"
+#include "base/thread_restrictions.h"
 #include "base/utf_string_conversions.h"
 #include "base/values.h"
-#include "base/callback.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profile.h"
 #include "grit/chromium_strings.h"
@@ -52,6 +53,11 @@
 
 void ImportDataHandler::Initialize() {
   importer_list_.reset(new ImporterList);
+
+  // We should not be loading profiles from the UI thread!
+  // Temporarily allow this until we fix
+  //   http://code.google.com/p/chromium/issues/detail?id=60825
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   importer_list_->DetectSourceProfiles();
   int profiles_count = importer_list_->GetAvailableProfileCount();
 
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 8b523d5..4246ffa 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -12,6 +12,7 @@
 #include "base/singleton.h"
 #include "base/stringprintf.h"
 #include "base/task.h"
+#include "base/thread_restrictions.h"
 #include "base/utf_string_conversions.h"
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
@@ -112,7 +113,12 @@
   source_file_ = source_file;
 
   FilePath user_data_temp_dir;
-  CHECK(PathService::Get(chrome::DIR_USER_DATA_TEMP, &user_data_temp_dir));
+  {
+    // We shouldn't be doing disk IO on the UI thread.
+    //   http://code.google.com/p/chromium/issues/detail?id=60634
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    CHECK(PathService::Get(chrome::DIR_USER_DATA_TEMP, &user_data_temp_dir));
+  }
 
   scoped_refptr<SandboxedExtensionUnpacker> unpacker(
       new SandboxedExtensionUnpacker(
diff --git a/chrome/browser/spellcheck_host.cc b/chrome/browser/spellcheck_host.cc
index 545eaaa1..d9784c2 100644
--- a/chrome/browser/spellcheck_host.cc
+++ b/chrome/browser/spellcheck_host.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "base/string_split.h"
+#include "base/thread_restrictions.h"
 #include "base/utf_string_conversions.h"
 #include "chrome/browser/prefs/pref_member.h"
 #include "chrome/browser/profile.h"
@@ -28,7 +29,13 @@
 
 FilePath GetFirstChoiceFilePath(const std::string& language) {
   FilePath dict_dir;
-  PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir);
+  {
+    // This should not do blocking IO from the UI thread!
+    // Temporarily allow it for now.
+    //   http://code.google.com/p/chromium/issues/detail?id=60643
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir);
+  }
   return SpellCheckCommon::GetVersionedFileName(language, dict_dir);
 }
 
diff --git a/chrome/browser/visitedlink_master.cc b/chrome/browser/visitedlink_master.cc
index cf1445c..02b45d9 100644
--- a/chrome/browser/visitedlink_master.cc
+++ b/chrome/browser/visitedlink_master.cc
@@ -21,6 +21,7 @@
 #include "base/rand_util.h"
 #include "base/stack_container.h"
 #include "base/string_util.h"
+#include "base/thread_restrictions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_thread.h"
 #include "chrome/browser/history/history.h"
@@ -251,6 +252,10 @@
 }
 
 bool VisitedLinkMaster::Init() {
+  // We probably shouldn't be loading this from the UI thread,
+  // but it does need to happen early on in startup.
+  //   http://code.google.com/p/chromium/issues/detail?id=24163
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
   if (!InitFromFile())
     return InitFromScratch(suppress_rebuild_);
   return true;
@@ -889,6 +894,9 @@
       // Send an update notification to all child processes.
       listener_->NewTable(shared_memory_);
 
+      // We shouldn't be writing the table from the main thread!
+      //   http://code.google.com/p/chromium/issues/detail?id=24163
+      base::ThreadRestrictions::ScopedAllowIO allow_io;
       WriteFullTable();
     }
   }