1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/gpu/gpu_child_thread.h" 6 7 #include "base/bind.h" 8 #include "base/lazy_instance.h" 9 #include "base/threading/worker_pool.h" 10 #include "build/build_config.h" 11 #include "content/child/child_process.h" 12 #include "content/child/thread_safe_sender.h" 13 #include "content/common/gpu/gpu_messages.h" 14 #include "content/gpu/gpu_watchdog_thread.h" 15 #include "content/public/common/content_client.h" 16 #include "content/public/common/content_switches.h" 17 #include "gpu/config/gpu_info_collector.h" 18 #include "ipc/ipc_channel_handle.h" 19 #include "ipc/ipc_sync_message_filter.h" 20 #include "ui/gl/gl_implementation.h" 21 22 namespace content { 23 namespace { 24 25 static base::LazyInstance<scoped_refptr<ThreadSafeSender> > 26 g_thread_safe_sender = LAZY_INSTANCE_INITIALIZER; 27 28 bool GpuProcessLogMessageHandler(int severity, 29 const char* file, int line, 30 size_t message_start, 31 const std::string& str) { 32 std::string header = str.substr(0, message_start); 33 std::string message = str.substr(message_start); 34 35 g_thread_safe_sender.Get()->Send(new GpuHostMsg_OnLogMessage( 36 severity, header, message)); 37 38 return false; 39 } 40 41 } // namespace 42 43 GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread, 44 bool dead_on_arrival, 45 const gpu::GPUInfo& gpu_info, 46 const DeferredMessages& deferred_messages) 47 : dead_on_arrival_(dead_on_arrival), 48 gpu_info_(gpu_info), 49 deferred_messages_(deferred_messages), 50 in_browser_process_(false) { 51 watchdog_thread_ = watchdog_thread; 52 #if defined(OS_WIN) 53 target_services_ = NULL; 54 #endif 55 g_thread_safe_sender.Get() = thread_safe_sender(); 56 } 57 58 GpuChildThread::GpuChildThread(const std::string& channel_id) 59 : ChildThread(channel_id), 60 dead_on_arrival_(false), 61 in_browser_process_(true) { 62 #if defined(OS_WIN) 63 target_services_ = NULL; 64 #endif 65 DCHECK( 66 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) || 67 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)); 68 // For single process and in-process GPU mode, we need to load and 69 // initialize the GL implementation and locate the GL entry points here. 70 if (!gfx::GLSurface::InitializeOneOff()) { 71 VLOG(1) << "gfx::GLSurface::InitializeOneOff()"; 72 } 73 g_thread_safe_sender.Get() = thread_safe_sender(); 74 } 75 76 GpuChildThread::~GpuChildThread() { 77 } 78 79 void GpuChildThread::Shutdown() { 80 ChildThread::Shutdown(); 81 logging::SetLogMessageHandler(NULL); 82 } 83 84 void GpuChildThread::Init(const base::Time& process_start_time) { 85 process_start_time_ = process_start_time; 86 } 87 88 bool GpuChildThread::Send(IPC::Message* msg) { 89 // The GPU process must never send a synchronous IPC message to the browser 90 // process. This could result in deadlock. 91 DCHECK(!msg->is_sync()); 92 93 return ChildThread::Send(msg); 94 } 95 96 bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) { 97 bool msg_is_ok = true; 98 bool handled = true; 99 IPC_BEGIN_MESSAGE_MAP_EX(GpuChildThread, msg, msg_is_ok) 100 IPC_MESSAGE_HANDLER(GpuMsg_Initialize, OnInitialize) 101 IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo) 102 IPC_MESSAGE_HANDLER(GpuMsg_GetVideoMemoryUsageStats, 103 OnGetVideoMemoryUsageStats) 104 IPC_MESSAGE_HANDLER(GpuMsg_Clean, OnClean) 105 IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash) 106 IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang) 107 IPC_MESSAGE_HANDLER(GpuMsg_DisableWatchdog, OnDisableWatchdog) 108 IPC_MESSAGE_UNHANDLED(handled = false) 109 IPC_END_MESSAGE_MAP_EX() 110 111 if (handled) 112 return true; 113 114 return gpu_channel_manager_.get() && 115 gpu_channel_manager_->OnMessageReceived(msg); 116 } 117 118 void GpuChildThread::OnInitialize() { 119 Send(new GpuHostMsg_Initialized(!dead_on_arrival_, gpu_info_)); 120 while (!deferred_messages_.empty()) { 121 Send(deferred_messages_.front()); 122 deferred_messages_.pop(); 123 } 124 125 if (dead_on_arrival_) { 126 VLOG(1) << "Exiting GPU process due to errors during initialization"; 127 base::MessageLoop::current()->Quit(); 128 return; 129 } 130 131 #if defined(OS_ANDROID) 132 base::PlatformThread::SetThreadPriority( 133 base::PlatformThread::CurrentHandle(), 134 base::kThreadPriority_Display); 135 #endif 136 137 // We don't need to pipe log messages if we are running the GPU thread in 138 // the browser process. 139 if (!in_browser_process_) 140 logging::SetLogMessageHandler(GpuProcessLogMessageHandler); 141 142 // Record initialization only after collecting the GPU info because that can 143 // take a significant amount of time. 144 gpu_info_.initialization_time = base::Time::Now() - process_start_time_; 145 146 // Defer creation of the render thread. This is to prevent it from handling 147 // IPC messages before the sandbox has been enabled and all other necessary 148 // initialization has succeeded. 149 gpu_channel_manager_.reset( 150 new GpuChannelManager(this, 151 watchdog_thread_.get(), 152 ChildProcess::current()->io_message_loop_proxy(), 153 ChildProcess::current()->GetShutDownEvent())); 154 155 // Ensure the browser process receives the GPU info before a reply to any 156 // subsequent IPC it might send. 157 if (!in_browser_process_) 158 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_)); 159 } 160 161 void GpuChildThread::StopWatchdog() { 162 if (watchdog_thread_.get()) { 163 watchdog_thread_->Stop(); 164 } 165 } 166 167 void GpuChildThread::OnCollectGraphicsInfo() { 168 #if defined(OS_WIN) 169 // GPU full info collection should only happen on un-sandboxed GPU process 170 // or single process/in-process gpu mode on Windows. 171 CommandLine* command_line = CommandLine::ForCurrentProcess(); 172 DCHECK(command_line->HasSwitch(switches::kDisableGpuSandbox) || 173 in_browser_process_); 174 #endif // OS_WIN 175 176 if (!gpu::CollectContextGraphicsInfo(&gpu_info_)) 177 VLOG(1) << "gpu::CollectGraphicsInfo failed"; 178 GetContentClient()->SetGpuInfo(gpu_info_); 179 180 #if defined(OS_WIN) 181 // This is slow, but it's the only thing the unsandboxed GPU process does, 182 // and GpuDataManager prevents us from sending multiple collecting requests, 183 // so it's OK to be blocking. 184 gpu::GetDxDiagnostics(&gpu_info_.dx_diagnostics); 185 gpu_info_.finalized = true; 186 #endif // OS_WIN 187 188 Send(new GpuHostMsg_GraphicsInfoCollected(gpu_info_)); 189 190 #if defined(OS_WIN) 191 if (!in_browser_process_) { 192 // The unsandboxed GPU process fulfilled its duty. Rest in peace. 193 base::MessageLoop::current()->Quit(); 194 } 195 #endif // OS_WIN 196 } 197 198 void GpuChildThread::OnGetVideoMemoryUsageStats() { 199 GPUVideoMemoryUsageStats video_memory_usage_stats; 200 if (gpu_channel_manager_) 201 gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats( 202 &video_memory_usage_stats); 203 Send(new GpuHostMsg_VideoMemoryUsageStats(video_memory_usage_stats)); 204 } 205 206 void GpuChildThread::OnClean() { 207 VLOG(1) << "GPU: Removing all contexts"; 208 if (gpu_channel_manager_) 209 gpu_channel_manager_->LoseAllContexts(); 210 } 211 212 void GpuChildThread::OnCrash() { 213 VLOG(1) << "GPU: Simulating GPU crash"; 214 // Good bye, cruel world. 215 volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL; 216 *it_s_the_end_of_the_world_as_we_know_it = 0xdead; 217 } 218 219 void GpuChildThread::OnHang() { 220 VLOG(1) << "GPU: Simulating GPU hang"; 221 for (;;) { 222 // Do not sleep here. The GPU watchdog timer tracks the amount of user 223 // time this thread is using and it doesn't use much while calling Sleep. 224 } 225 } 226 227 void GpuChildThread::OnDisableWatchdog() { 228 VLOG(1) << "GPU: Disabling watchdog thread"; 229 if (watchdog_thread_.get()) { 230 // Disarm the watchdog before shutting down the message loop. This prevents 231 // the future posting of tasks to the message loop. 232 if (watchdog_thread_->message_loop()) 233 watchdog_thread_->PostAcknowledge(); 234 // Prevent rearming. 235 watchdog_thread_->Stop(); 236 } 237 } 238 239 } // namespace content 240 241