- Relanding 61718.

I disabled the GPU watchdog in three new cases:
- If the OSMesa software renderer is in use. This will disable it on bots.
- When running on valgrind, whether on a bot or locally.
- In debug builds

I added a GPU process initialization time to the GPU info.

I moved the GPU initialization code outside the watchdog protection because it
can take a long time and trigger the watchdog.

I increased the timeout. I set up a field trial with different timeouts to see
the rate of failure for each period.

Original CL description:

I added a watchdog thread that intermitently checks the main thread can respond
to tasks posted on its message queue.

I fixed some bugs that prevented GGL from failing when the GPU channel was
lost.

Added a command line swith to disable the watchdog thread for debugging
purposes.

TEST=try, local testing of all features
BUG=none


git-svn-id: svn://svn.chromium.org/chrome/trunk/src@65461 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/gpu/gpu_main.cc b/chrome/gpu/gpu_main.cc
index b6dfef5..cf5822d4 100644
--- a/chrome/gpu/gpu_main.cc
+++ b/chrome/gpu/gpu_main.cc
@@ -2,16 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stdlib.h>
+
 #include "app/app_switches.h"
+#include "app/gfx/gl/gl_context.h"
 #include "app/gfx/gl/gl_implementation.h"
+#include "base/environment.h"
 #include "base/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/env_vars.h"
 #include "chrome/common/main_function_params.h"
 #include "chrome/gpu/gpu_config.h"
 #include "chrome/gpu/gpu_process.h"
 #include "chrome/gpu/gpu_thread.h"
+#include "chrome/gpu/gpu_watchdog_thread.h"
 
 #if defined(USE_LINUX_BREAKPAD)
 #include "chrome/app/breakpad_linux.h"
@@ -26,9 +34,17 @@
 #include "app/x11_util_internal.h"
 #endif
 
-#if defined(USE_X11)
+
 namespace {
 
+// 1% per watchdog trial group.
+const int kFieldTrialSize = 1;
+
+// 5 - 20 seconds timeout.
+const int kMinGpuTimeout = 5;
+const int kMaxGpuTimeout = 20;
+
+#if defined(USE_X11)
 int GpuX11ErrorHandler(Display* d, XErrorEvent* error) {
   LOG(ERROR) << x11_util::GetErrorEventDescription(d, error);
   return 0;
@@ -38,12 +54,14 @@
   // Set up the error handlers so that only general errors aren't fatal.
   x11_util::SetX11ErrorHandlers(GpuX11ErrorHandler, NULL);
 }
+#endif
 
 }
-#endif
 
 // Main function for starting the Gpu process.
 int GpuMain(const MainFunctionParams& parameters) {
+  base::Time start_time = base::Time::Now();
+
 #if defined(USE_LINUX_BREAKPAD)
   // Needs to be called after we have chrome::DIR_USER_DATA.
   InitCrashReporter();
@@ -66,20 +84,75 @@
 
 #if defined(OS_WIN)
   win_util::ScopedCOMInitializer com_initializer;
-#elif defined(GPU_USE_GLX)
-  if (!command_line.HasSwitch(switches::kUseGL)) {
-    gfx::InitializeGLBindings(gfx::kGLImplementationDesktopGL);
-  }
 #endif
 
-  GpuProcess gpu_process;
-  gpu_process.set_main_thread(new GpuThread());
-
 #if defined(USE_X11)
   SetGpuX11ErrorHandlers();
 #endif
 
+  // Load the GL implementation and locate the bindings before starting as
+  // this can take a lot of time and the GPU watchdog might terminate the GPU
+  // process.
+  if (!gfx::GLContext::InitializeOneOff())
+    return EXIT_FAILURE;
+
+  GpuProcess gpu_process;
+  GpuThread* gpu_thread = new GpuThread;
+  gpu_process.set_main_thread(gpu_thread);
+
+  // Only enable this experimental feaure for a subset of users.
+  scoped_refptr<base::FieldTrial> watchdog_trial(
+      new base::FieldTrial("GpuWatchdogTrial", 100));
+  int watchdog_timeout = 0;
+  for (int i = kMinGpuTimeout; i <= kMaxGpuTimeout; ++i) {
+    int group = watchdog_trial->AppendGroup(StringPrintf("%dsecs", i),
+                                            kFieldTrialSize);
+    if (group == watchdog_trial->group()) {
+      watchdog_timeout = i;
+      break;
+    }
+  }
+
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+
+  // In addition to disabling the watchdog if the command line switch is
+  // present, disable it in two other cases. OSMesa is expected to run very
+  // slowly.  Also disable the watchdog on valgrind because the code is expected
+  // to run slowly in that case.
+  bool enable_watchdog =
+      watchdog_timeout != 0 &&
+      !command_line.HasSwitch(switches::kDisableGpuWatchdog) &&
+      gfx::GetGLImplementation() != gfx::kGLImplementationOSMesaGL &&
+      !RunningOnValgrind();
+
+  // Disable the watchdog in debug builds because they tend to only be run by
+  // developers who will not appreciate the watchdog killing the GPU process.
+#ifndef NDEBUG
+  enable_watchdog = false;
+#endif
+
+// TODO(apatrick): Disable for this commit. I want to enable this feature with
+// a simple single file change that can easily be reverted if need be without
+// losing all the other features of the patch.
+#if 1
+  enable_watchdog = false;
+#endif
+
+  scoped_refptr<GpuWatchdogThread> watchdog_thread;
+  if (enable_watchdog) {
+    watchdog_thread = new GpuWatchdogThread(MessageLoop::current(),
+                                            watchdog_timeout * 1000);
+    watchdog_thread->Start();
+  }
+
+  // Do this immediately before running the message loop so the correct
+  // initialization time is recorded in the GPU info.
+  gpu_thread->Init(start_time);
+
   main_message_loop.Run();
 
+  if (enable_watchdog)
+    watchdog_thread->Stop();
+
   return 0;
 }