diff options
Diffstat (limited to 'chrome/gpu/gpu_thread.cc')
-rw-r--r-- | chrome/gpu/gpu_thread.cc | 124 |
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; |