Index: chrome/browser/gpu_process_host.cc |
=================================================================== |
--- chrome/browser/gpu_process_host.cc (revision 43024) |
+++ chrome/browser/gpu_process_host.cc (working copy) |
@@ -5,41 +5,80 @@ |
#include "chrome/browser/gpu_process_host.h" |
#include "base/command_line.h" |
-#include "base/singleton.h" |
#include "base/thread.h" |
#include "chrome/browser/browser_process.h" |
-#include "chrome/browser/child_process_host.h" |
-#include "chrome/browser/child_process_launcher.h" |
-#include "chrome/browser/io_thread.h" |
-#include "chrome/browser/renderer_host/render_process_host.h" |
-#include "chrome/common/child_process_info.h" |
+#include "chrome/browser/chrome_thread.h" |
+#include "chrome/browser/gpu_process_host_ui_shim.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/gpu_messages.h" |
#include "chrome/common/render_messages.h" |
#include "ipc/ipc_switches.h" |
-GpuProcessHost::GpuProcessHost() : last_routing_id_(1) { |
+namespace { |
+ |
+// Tasks used by this file |
+class RouteOnUIThreadTask : public Task { |
+ public: |
+ explicit RouteOnUIThreadTask(const IPC::Message& msg) { |
+ msg_ = new IPC::Message(msg); |
+ } |
+ |
+ private: |
+ void Run() { |
+ GpuProcessHostUIShim::Get()->OnMessageReceived(*msg_); |
+ delete msg_; |
+ msg_ = NULL; |
+ } |
+ IPC::Message* msg_; |
+}; |
+ |
+// Global GpuProcessHost instance. |
+// We can not use Singleton<GpuProcessHost> because that gets |
+// terminated on the wrong thread (main thread). We need the |
+// GpuProcessHost to be terminated on the same thread on which it is |
+// initialized, the IO thread. |
+static GpuProcessHost* sole_instance_; |
+ |
+} // anonymous namespace |
+ |
+GpuProcessHost::GpuProcessHost() |
+ : ChildProcessHost(GPU_PROCESS, NULL), |
+ initialized_(false), |
+ initialized_successfully_(false) { |
+} |
+ |
+GpuProcessHost::~GpuProcessHost() { |
+ while (!queued_synchronization_replies_.empty()) { |
+ delete queued_synchronization_replies_.front().reply; |
+ queued_synchronization_replies_.pop(); |
+ } |
+} |
+ |
+bool GpuProcessHost::EnsureInitialized() { |
+ if (!initialized_) { |
+ initialized_ = true; |
+ initialized_successfully_ = Init(); |
+ } |
+ return initialized_successfully_; |
+} |
+ |
+bool GpuProcessHost::Init() { |
+ if (!CreateChannel()) |
+ return false; |
+ |
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); |
std::wstring gpu_launcher = |
browser_command_line.GetSwitchValue(switches::kGpuLauncher); |
FilePath exe_path = ChildProcessHost::GetChildPath(gpu_launcher.empty()); |
if (exe_path.empty()) |
- return; |
+ return false; |
- std::string channel_id = ChildProcessInfo::GenerateRandomChannelID(this); |
- channel_.reset(new IPC::ChannelProxy( |
- channel_id, |
- IPC::Channel::MODE_SERVER, |
- this, |
- NULL, // No filter (for now). |
- g_browser_process->io_thread()->message_loop())); |
- |
CommandLine* cmd_line = new CommandLine(exe_path); |
cmd_line->AppendSwitchWithValue(switches::kProcessType, |
switches::kGpuProcess); |
cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, |
- ASCIIToWide(channel_id)); |
+ ASCIIToWide(channel_id())); |
const CommandLine& browser_cmd_line = *CommandLine::ForCurrentProcess(); |
PropagateBrowserCommandLineToGpu(browser_cmd_line, cmd_line); |
@@ -48,110 +87,67 @@ |
if (!gpu_launcher.empty()) |
cmd_line->PrependWrapper(gpu_launcher); |
- // Spawn the child process asynchronously to avoid blocking the UI thread. |
- child_process_.reset(new ChildProcessLauncher( |
+ Launch( |
#if defined(OS_WIN) |
FilePath(), |
#elif defined(POSIX) |
false, // Never use the zygote (GPU plugin can't be sandboxed). |
base::environment_vector(), |
- channel_->GetClientFileDescriptor(), |
#endif |
- cmd_line, |
- this)); |
-} |
+ cmd_line); |
-GpuProcessHost::~GpuProcessHost() { |
- while (!queued_synchronization_replies_.empty()) { |
- delete queued_synchronization_replies_.front(); |
- queued_synchronization_replies_.pop(); |
- } |
+ return true; |
} |
// static |
GpuProcessHost* GpuProcessHost::Get() { |
- GpuProcessHost* host = Singleton<GpuProcessHost>::get(); |
- if (!host->child_process_.get()) |
- return NULL; // Failed to init. |
- return host; |
+ if (sole_instance_ == NULL) |
+ sole_instance_ = new GpuProcessHost(); |
+ return sole_instance_; |
} |
-int32 GpuProcessHost::GetNextRoutingId() { |
- return ++last_routing_id_; |
+// static |
+void GpuProcessHost::Shutdown() { |
+ if (sole_instance_) { |
+ delete sole_instance_; |
+ sole_instance_ = NULL; |
+ } |
} |
-int32 GpuProcessHost::NewRenderWidgetHostView(GpuNativeWindowHandle parent) { |
- int32 routing_id = GetNextRoutingId(); |
- Send(new GpuMsg_NewRenderWidgetHostView(parent, routing_id)); |
- return routing_id; |
-} |
- |
bool GpuProcessHost::Send(IPC::Message* msg) { |
- if (!channel_.get()) { |
- delete msg; |
+ if (!EnsureInitialized()) |
return false; |
- } |
- if (child_process_.get() && child_process_->IsStarting()) { |
- queued_messages_.push(msg); |
- return true; |
- } |
- |
- return channel_->Send(msg); |
+ return ChildProcessHost::Send(msg); |
} |
void GpuProcessHost::OnMessageReceived(const IPC::Message& message) { |
if (message.routing_id() == MSG_ROUTING_CONTROL) { |
OnControlMessageReceived(message); |
} else { |
- router_.OnMessageReceived(message); |
+ // Need to transfer this message to the UI thread and the |
+ // GpuProcessHostUIShim for dispatching via its message router. |
+ ChromeThread::PostTask(ChromeThread::UI, |
+ FROM_HERE, |
+ new RouteOnUIThreadTask(message)); |
} |
} |
-void GpuProcessHost::OnChannelConnected(int32 peer_pid) { |
-} |
- |
-void GpuProcessHost::OnChannelError() { |
-} |
- |
-void GpuProcessHost::OnProcessLaunched() { |
- while (!queued_messages_.empty()) { |
- Send(queued_messages_.front()); |
- queued_messages_.pop(); |
+void GpuProcessHost::EstablishGpuChannel(int renderer_id, |
+ ResourceMessageFilter* filter) { |
+ if (Send(new GpuMsg_EstablishChannel(renderer_id))) { |
+ sent_requests_.push(ChannelRequest(filter)); |
+ } else { |
+ ReplyToRenderer(IPC::ChannelHandle(), filter); |
} |
} |
-void GpuProcessHost::AddRoute(int32 routing_id, |
- IPC::Channel::Listener* listener) { |
- router_.AddRoute(routing_id, listener); |
+void GpuProcessHost::Synchronize(IPC::Message* reply, |
+ ResourceMessageFilter* filter) { |
+ queued_synchronization_replies_.push(SynchronizationRequest(reply, filter)); |
+ Send(new GpuMsg_Synchronize()); |
} |
-void GpuProcessHost::RemoveRoute(int32 routing_id) { |
- router_.RemoveRoute(routing_id); |
-} |
- |
-void GpuProcessHost::EstablishGpuChannel(int renderer_id) { |
- if (Send(new GpuMsg_EstablishChannel(renderer_id))) |
- sent_requests_.push(ChannelRequest(renderer_id)); |
- else |
- ReplyToRenderer(renderer_id, IPC::ChannelHandle()); |
-} |
- |
-void GpuProcessHost::Synchronize(int renderer_id, IPC::Message* reply) { |
- // ************ |
- // TODO(kbr): the handling of this synchronous message (which is |
- // needed for proper initialization semantics of APIs like WebGL) is |
- // currently broken on Windows because the renderer is sending a |
- // synchronous message to the browser's UI thread. To fix this, the |
- // GpuProcessHost needs to move to the IO thread, and any backing |
- // store handling needs to remain on the UI thread in a new |
- // GpuProcessHostProxy, where work is sent from the IO thread to the |
- // UI thread via PostTask. |
- // ************ |
- queued_synchronization_replies_.push(reply); |
- CHECK(Send(new GpuMsg_Synchronize(renderer_id))); |
-} |
- |
void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) { |
IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message) |
IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished) |
@@ -163,37 +159,27 @@ |
void GpuProcessHost::OnChannelEstablished( |
const IPC::ChannelHandle& channel_handle) { |
const ChannelRequest& request = sent_requests_.front(); |
- |
- ReplyToRenderer(request.renderer_id, channel_handle); |
+ ReplyToRenderer(channel_handle, request.filter); |
sent_requests_.pop(); |
} |
-void GpuProcessHost::OnSynchronizeReply(int renderer_id) { |
- IPC::Message* reply = queued_synchronization_replies_.front(); |
+void GpuProcessHost::OnSynchronizeReply() { |
+ const SynchronizationRequest& request = |
+ queued_synchronization_replies_.front(); |
+ request.filter->Send(request.reply); |
queued_synchronization_replies_.pop(); |
- RenderProcessHost* process_host = RenderProcessHost::FromID(renderer_id); |
- if (!process_host) { |
- delete reply; |
- return; |
- } |
- CHECK(process_host->Send(reply)); |
} |
void GpuProcessHost::ReplyToRenderer( |
- int renderer_id, |
- const IPC::ChannelHandle& channel) { |
- // Check whether the renderer process is still around. |
- RenderProcessHost* process_host = RenderProcessHost::FromID(renderer_id); |
- if (!process_host) |
- return; |
- |
- ViewMsg_GpuChannelEstablished* msg = |
+ const IPC::ChannelHandle& channel, |
+ ResourceMessageFilter* filter) { |
+ ViewMsg_GpuChannelEstablished* message = |
new ViewMsg_GpuChannelEstablished(channel); |
// If the renderer process is performing synchronous initialization, |
// it needs to handle this message before receiving the reply for |
// the synchronous ViewHostMsg_SynchronizeGpu message. |
- msg->set_unblock(true); |
- CHECK(process_host->Send(msg)); |
+ message->set_unblock(true); |
+ filter->Send(message); |
} |
void GpuProcessHost::PropagateBrowserCommandLineToGpu( |
@@ -215,3 +201,14 @@ |
} |
} |
} |
+ |
+URLRequestContext* GpuProcessHost::GetRequestContext( |
+ uint32 request_id, |
+ const ViewHostMsg_Resource_Request& request_data) { |
+ return NULL; |
+} |
+ |
+bool GpuProcessHost::CanShutdown() { |
+ return true; |
+} |
+ |