summaryrefslogtreecommitdiffstats
path: root/chrome/gpu/gpu_thread.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/gpu/gpu_thread.cc')
-rw-r--r--chrome/gpu/gpu_thread.cc124
1 files changed, 105 insertions, 19 deletions
diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc
index c72de9e..f204ab1 100644
--- a/chrome/gpu/gpu_thread.cc
+++ b/chrome/gpu/gpu_thread.cc
@@ -8,41 +8,49 @@
#include <vector>
#include "app/gfx/gl/gl_context.h"
+#include "app/gfx/gl/gl_implementation.h"
#include "app/win/scoped_com_initializer.h"
#include "base/command_line.h"
#include "base/threading/worker_pool.h"
#include "build/build_config.h"
#include "chrome/common/child_process.h"
#include "chrome/common/child_process_logging.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/gpu/gpu_info_collector.h"
+#include "chrome/gpu/gpu_watchdog_thread.h"
#include "ipc/ipc_channel_handle.h"
-GpuThread::GpuThread() {
+#if defined(OS_MACOSX)
+#include "chrome/common/sandbox_mac.h"
+#endif
+
+const int kGpuTimeout = 10000;
+
+namespace {
+
+bool InitializeGpuSandbox() {
+#if defined(OS_MACOSX)
+ CommandLine* parsed_command_line = CommandLine::ForCurrentProcess();
+ SandboxInitWrapper sandbox_wrapper;
+ return sandbox_wrapper.InitializeSandbox(*parsed_command_line,
+ switches::kGpuProcess);
+#else
+ // TODO(port): Create GPU sandbox for linux and windows.
+ return true;
+#endif
}
+} // namespace
+
+GpuThread::GpuThread(const CommandLine& command_line)
+ : command_line_(command_line) {}
+
GpuThread::~GpuThread() {
}
void GpuThread::Init(const base::Time& process_start_time) {
- gpu_info_collector::CollectGraphicsInfo(&gpu_info_);
- child_process_logging::SetGpuInfo(gpu_info_);
-
-#if defined(OS_WIN)
- // Asynchronously collect the DirectX diagnostics because this can take a
- // couple of seconds.
- if (!base::WorkerPool::PostTask(
- FROM_HERE,
- NewRunnableFunction(&GpuThread::CollectDxDiagnostics, this),
- true)) {
- // Flag GPU info as complete if the DirectX diagnostics cannot be collected.
- gpu_info_.SetProgress(GPUInfo::kComplete);
- }
-#endif
-
- // Record initialization only after collecting the GPU info because that can
- // take a significant amount of time.
- gpu_info_.SetInitializationTime(base::Time::Now() - process_start_time);
+ process_start_time_ = process_start_time;
}
void GpuThread::RemoveChannel(int renderer_id) {
@@ -53,6 +61,7 @@ bool GpuThread::OnControlMessageReceived(const IPC::Message& msg) {
bool msg_is_ok = true;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(GpuThread, msg, msg_is_ok)
+ IPC_MESSAGE_HANDLER(GpuMsg_Initialize, OnInitialize)
IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel)
IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel)
IPC_MESSAGE_HANDLER(GpuMsg_Synchronize, OnSynchronize)
@@ -70,6 +79,83 @@ bool GpuThread::OnControlMessageReceived(const IPC::Message& msg) {
return handled;
}
+void GpuThread::OnInitialize() {
+ // Load the GL implementation and locate the bindings before starting the GPU
+ // watchdog because this can take a lot of time and the GPU watchdog might
+ // terminate the GPU process.
+ if (!gfx::GLContext::InitializeOneOff()) {
+ MessageLoop::current()->Quit();
+ return;
+ }
+ gpu_info_collector::CollectGraphicsInfo(&gpu_info_);
+ child_process_logging::SetGpuInfo(gpu_info_);
+
+#if defined(OS_WIN)
+ // Asynchronously collect the DirectX diagnostics because this can take a
+ // couple of seconds.
+ if (!base::WorkerPool::PostTask(
+ FROM_HERE,
+ NewRunnableFunction(&GpuThread::CollectDxDiagnostics, this),
+ true)) {
+ // Flag GPU info as complete if the DirectX diagnostics cannot be collected.
+ gpu_info_.SetProgress(GPUInfo::kComplete);
+ }
+#endif
+
+ // Record initialization only after collecting the GPU info because that can
+ // take a significant amount of time.
+ gpu_info_.SetInitializationTime(base::Time::Now() - process_start_time_);
+
+ // Note that kNoSandbox will also disable the GPU sandbox.
+ bool no_gpu_sandbox = command_line_.HasSwitch(switches::kNoGpuSandbox);
+ if (!no_gpu_sandbox) {
+ if (!InitializeGpuSandbox()) {
+ LOG(ERROR) << "Failed to initialize the GPU sandbox";
+ MessageLoop::current()->Quit();
+ return;
+ }
+ } else {
+ LOG(ERROR) << "Running without GPU sandbox";
+ }
+
+ // 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 =
+ !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
+
+ // Disable the watchdog for Windows. It tends to abort when the GPU process
+ // is not hung but still taking a long time to do something. Instead, the
+ // browser process displays a dialog when it notices that the child window
+ // is hung giving the user an opportunity to terminate it. This is the
+ // same mechanism used to abort hung plugins.
+#if defined(OS_WIN)
+ enable_watchdog = false;
+#endif
+
+ // Start the GPU watchdog only after anything that is expected to be time
+ // consuming has completed, otherwise the process is liable to be aborted.
+ if (enable_watchdog) {
+ watchdog_thread_ = new GpuWatchdogThread(kGpuTimeout);
+ watchdog_thread_->Start();
+ }
+}
+
+void GpuThread::StopWatchdog() {
+ if (watchdog_thread_.get()) {
+ watchdog_thread_->Stop();
+ }
+}
+
void GpuThread::OnEstablishChannel(int renderer_id) {
scoped_refptr<GpuChannel> channel;
IPC::ChannelHandle channel_handle;