summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-30 00:31:22 +0000
committerkbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-30 00:31:22 +0000
commit1082b1dd85c92e5260911989d8022988bacb676e (patch)
treedb12d29cafe47d38e3e9657dea037daf694348d7
parent66ee443252fd759c5e20cb93be1e90a732da0ebe (diff)
downloadchromium_src-1082b1dd85c92e5260911989d8022988bacb676e.zip
chromium_src-1082b1dd85c92e5260911989d8022988bacb676e.tar.gz
chromium_src-1082b1dd85c92e5260911989d8022988bacb676e.tar.bz2
Split GpuProcessHost into GpuProcessHostUIShim, which runs on the UI
thread, and GpuProcessHost, which now runs on the IO thread and derives from ChildProcessHost. This split was necessary in order to service synchronous messages from the renderer process. Moved message handlers for GPU messages from renderer to browser from BrowserRenderProcessHost to ResourceMessageFilter. Stopped sending multiple ViewHostMsg_EstablishGpuChannel messages from the same renderer if the connection was already established. Resetting the channel was causing failures in Send, and every other page reload containing WebGL content to fail. This cleanup will allow further simplification in the GPU process, but this is being left for a subsequent CL. Fixed bug in sandboxing of GPU process. Fixed latent bugs in cleanup code in GpuChannel and GpuChannelHost. Fixed crashes in ChildProcessHost if resource_dispatcher_host_ was NULL. Fixed apparent latent race conditions in creation of BackingStoreProxy and VideoLayerProxy. With these changes, WebGL content is running in the sandbox on both Mac and Windows. Linux support will be added in a following CL. BUG=29120 TEST=ran WebGL demos on Mac and Windows Review URL: http://codereview.chromium.org/1546001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43029 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/child_process_host.cc10
-rw-r--r--chrome/browser/gpu_process_host.cc215
-rw-r--r--chrome/browser/gpu_process_host.h101
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.cc69
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.h56
-rw-r--r--chrome/browser/io_thread.cc3
-rw-r--r--chrome/browser/renderer_host/backing_store_proxy.cc16
-rw-r--r--chrome/browser/renderer_host/backing_store_proxy.h6
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc12
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h6
-rw-r--r--chrome/browser/renderer_host/gpu_view_host.cc38
-rw-r--r--chrome/browser/renderer_host/gpu_view_host.h4
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc18
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h3
-rw-r--r--chrome/browser/renderer_host/video_layer_proxy.cc12
-rw-r--r--chrome/browser/renderer_host/video_layer_proxy.h6
-rwxr-xr-xchrome/chrome_browser.gypi2
-rw-r--r--chrome/common/gpu_messages_internal.h6
-rw-r--r--chrome/common/sandbox_policy.cc3
-rw-r--r--chrome/gpu/gpu_channel.cc6
-rw-r--r--chrome/gpu/gpu_thread.cc4
-rw-r--r--chrome/gpu/gpu_thread.h2
-rw-r--r--chrome/renderer/gpu_channel_host.cc1
-rw-r--r--chrome/renderer/render_thread.cc18
24 files changed, 377 insertions, 240 deletions
diff --git a/chrome/browser/child_process_host.cc b/chrome/browser/child_process_host.cc
index d9f5218..a9dcbd7 100644
--- a/chrome/browser/child_process_host.cc
+++ b/chrome/browser/child_process_host.cc
@@ -80,7 +80,8 @@ ChildProcessHost::ChildProcessHost(
ChildProcessHost::~ChildProcessHost() {
Singleton<ChildProcessList>::get()->remove(this);
- resource_dispatcher_host_->CancelRequestsForProcess(id());
+ if (resource_dispatcher_host_)
+ resource_dispatcher_host_->CancelRequestsForProcess(id());
}
// static
@@ -217,8 +218,11 @@ void ChildProcessHost::ListenerHook::OnMessageReceived(
#endif
bool msg_is_ok = true;
- bool handled = host_->resource_dispatcher_host_->OnMessageReceived(
- msg, host_, &msg_is_ok);
+ bool handled = false;
+
+ if (host_->resource_dispatcher_host_)
+ host_->resource_dispatcher_host_->OnMessageReceived(
+ msg, host_, &msg_is_ok);
if (!handled) {
if (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) {
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc
index 9981133..cae8a35 100644
--- a/chrome/browser/gpu_process_host.cc
+++ b/chrome/browser/gpu_process_host.cc
@@ -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;
-
- 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()));
+ return false;
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,108 +87,65 @@ GpuProcessHost::GpuProcessHost() : last_routing_id_(1) {
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;
-}
-
-int32 GpuProcessHost::GetNextRoutingId() {
- return ++last_routing_id_;
+ if (sole_instance_ == NULL)
+ sole_instance_ = new GpuProcessHost();
+ return sole_instance_;
}
-int32 GpuProcessHost::NewRenderWidgetHostView(GpuNativeWindowHandle parent) {
- int32 routing_id = GetNextRoutingId();
- Send(new GpuMsg_NewRenderWidgetHostView(parent, routing_id));
- return routing_id;
+// static
+void GpuProcessHost::Shutdown() {
+ if (sole_instance_) {
+ delete sole_instance_;
+ sole_instance_ = NULL;
+ }
}
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::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::Synchronize(IPC::Message* reply,
+ ResourceMessageFilter* filter) {
+ queued_synchronization_replies_.push(SynchronizationRequest(reply, filter));
+ Send(new GpuMsg_Synchronize());
}
void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
@@ -163,37 +159,27 @@ void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
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 @@ void GpuProcessHost::PropagateBrowserCommandLineToGpu(
}
}
}
+
+URLRequestContext* GpuProcessHost::GetRequestContext(
+ uint32 request_id,
+ const ViewHostMsg_Resource_Request& request_data) {
+ return NULL;
+}
+
+bool GpuProcessHost::CanShutdown() {
+ return true;
+}
+
diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h
index 27d3fe3..4065124 100644
--- a/chrome/browser/gpu_process_host.h
+++ b/chrome/browser/gpu_process_host.h
@@ -9,83 +9,74 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
-#include "chrome/browser/child_process_launcher.h"
-#include "chrome/common/gpu_native_window_handle.h"
-#include "chrome/common/message_router.h"
-#include "gfx/native_widget_types.h"
-#include "ipc/ipc_channel_handle.h"
-#include "ipc/ipc_channel_proxy.h"
+#include "chrome/browser/child_process_host.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
class ChildProcessLauncher;
class CommandBufferProxy;
-class GpuProcessHost : public IPC::Channel::Sender,
- public IPC::Channel::Listener,
- public ChildProcessLauncher::Client {
+class GpuProcessHost : public ChildProcessHost {
public:
// Getter for the singleton. This will return NULL on failure.
static GpuProcessHost* Get();
- int32 GetNextRoutingId();
+ // Shutdown routine, which should only be called upon process
+ // termination.
+ static void Shutdown();
- // Creates the new remote view and returns the routing ID for the view, or 0
- // on failure.
- int32 NewRenderWidgetHostView(GpuNativeWindowHandle parent);
-
- // IPC::Channel::Sender implementation.
virtual bool Send(IPC::Message* msg);
// IPC::Channel::Listener implementation.
virtual void OnMessageReceived(const IPC::Message& message);
- virtual void OnChannelConnected(int32 peer_pid);
- virtual void OnChannelError();
-
- // ChildProcessLauncher::Client implementation.
- virtual void OnProcessLaunched();
-
- // See documentation on MessageRouter for AddRoute and RemoveRoute
- void AddRoute(int32 routing_id, IPC::Channel::Listener* listener);
- void RemoveRoute(int32 routing_id);
// Tells the GPU process to create a new channel for communication with a
// renderer. Will asynchronously send message to object with given routing id
// on completion.
- void EstablishGpuChannel(int renderer_id);
+ void EstablishGpuChannel(int renderer_id,
+ ResourceMessageFilter* filter);
// Sends a reply message later when the next GpuHostMsg_SynchronizeReply comes
// in.
- void Synchronize(int renderer_id, IPC::Message* reply);
+ void Synchronize(IPC::Message* reply,
+ ResourceMessageFilter* filter);
private:
- friend struct DefaultSingletonTraits<GpuProcessHost>;
-
// Used to queue pending channel requests.
struct ChannelRequest {
- explicit ChannelRequest(int renderer_id) : renderer_id(renderer_id) {}
- // Used to identify the renderer. The ID is used instead of a pointer to
- // the RenderProcessHost in case it is destroyed while the request is
- // pending.
- // TODO(apatrick): investigate whether these IDs are used for future
- // render processes.
- int renderer_id;
+ explicit ChannelRequest(ResourceMessageFilter* filter)
+ : filter(filter) {}
+ // Used to send the reply message back to the renderer.
+ scoped_refptr<ResourceMessageFilter> filter;
+ };
+
+ // Used to queue pending synchronization requests.
+ struct SynchronizationRequest {
+ SynchronizationRequest(IPC::Message* reply,
+ ResourceMessageFilter* filter)
+ : reply(reply),
+ filter(filter) {}
+ // The delayed reply message which needs to be sent to the
+ // renderer.
+ IPC::Message* reply;
+
+ // Used to send the reply message back to the renderer.
+ scoped_refptr<ResourceMessageFilter> filter;
};
GpuProcessHost();
virtual ~GpuProcessHost();
+ bool EnsureInitialized();
+ bool Init();
+
void OnControlMessageReceived(const IPC::Message& message);
// Message handlers.
void OnChannelEstablished(const IPC::ChannelHandle& channel_handle);
- void OnSynchronizeReply(int renderer_id);
+ void OnSynchronizeReply();
- void ReplyToRenderer(int renderer_id,
- const IPC::ChannelHandle& channel);
-
- // These are the channel requests that we have already sent to
- // the GPU process, but haven't heard back about yet.
- std::queue<ChannelRequest> sent_requests_;
+ void ReplyToRenderer(const IPC::ChannelHandle& channel,
+ ResourceMessageFilter* filter);
// Copies applicable command line switches from the given |browser_cmd| line
// flags to the output |gpu_cmd| line flags. Not all switches will be
@@ -93,24 +84,22 @@ class GpuProcessHost : public IPC::Channel::Sender,
void PropagateBrowserCommandLineToGpu(const CommandLine& browser_cmd,
CommandLine* gpu_cmd) const;
- scoped_ptr<ChildProcessLauncher> child_process_;
-
- // A proxy for our IPC::Channel that lives on the IO thread (see
- // browser_process.h). This will be NULL if the class failed to connect.
- scoped_ptr<IPC::ChannelProxy> channel_;
+ // ResourceDispatcherHost::Receiver implementation:
+ virtual URLRequestContext* GetRequestContext(
+ uint32 request_id,
+ const ViewHostMsg_Resource_Request& request_data);
- int last_routing_id_;
+ virtual bool CanShutdown();
- MessageRouter router_;
+ bool initialized_;
+ bool initialized_successfully_;
- // Messages we queue while waiting for the process handle. We queue them here
- // instead of in the channel so that we ensure they're sent after init related
- // messages that are sent once the process handle is available. This is
- // because the queued messages may have dependencies on the init messages.
- std::queue<IPC::Message*> queued_messages_;
+ // These are the channel requests that we have already sent to
+ // the GPU process, but haven't heard back about yet.
+ std::queue<ChannelRequest> sent_requests_;
// The pending synchronization requests we need to reply to.
- std::queue<IPC::Message*> queued_synchronization_replies_;
+ std::queue<SynchronizationRequest> queued_synchronization_replies_;
DISALLOW_COPY_AND_ASSIGN(GpuProcessHost);
};
diff --git a/chrome/browser/gpu_process_host_ui_shim.cc b/chrome/browser/gpu_process_host_ui_shim.cc
new file mode 100644
index 0000000..0b25845
--- /dev/null
+++ b/chrome/browser/gpu_process_host_ui_shim.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/gpu_process_host_ui_shim.h"
+
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/gpu_process_host.h"
+#include "chrome/common/gpu_messages.h"
+
+// Tasks used by this file
+namespace {
+
+class SendOnIOThreadTask : public Task {
+ public:
+ explicit SendOnIOThreadTask(IPC::Message* msg) : msg_(msg) {
+ }
+
+ private:
+ void Run() {
+ GpuProcessHost::Get()->Send(msg_);
+ }
+ IPC::Message* msg_;
+};
+
+} // namespace
+
+GpuProcessHostUIShim::GpuProcessHostUIShim() : last_routing_id_(1) {
+}
+
+GpuProcessHostUIShim::~GpuProcessHostUIShim() {
+}
+
+// static
+GpuProcessHostUIShim* GpuProcessHostUIShim::Get() {
+ return Singleton<GpuProcessHostUIShim>::get();
+}
+
+int32 GpuProcessHostUIShim::NewRenderWidgetHostView(
+ GpuNativeWindowHandle parent) {
+ int32 routing_id = GetNextRoutingId();
+ Send(new GpuMsg_NewRenderWidgetHostView(parent, routing_id));
+ return routing_id;
+}
+
+bool GpuProcessHostUIShim::Send(IPC::Message* msg) {
+ ChromeThread::PostTask(ChromeThread::IO,
+ FROM_HERE,
+ new SendOnIOThreadTask(msg));
+ return true;
+}
+
+int32 GpuProcessHostUIShim::GetNextRoutingId() {
+ return ++last_routing_id_;
+}
+
+void GpuProcessHostUIShim::AddRoute(int32 routing_id,
+ IPC::Channel::Listener* listener) {
+ router_.AddRoute(routing_id, listener);
+}
+
+void GpuProcessHostUIShim::RemoveRoute(int32 routing_id) {
+ router_.RemoveRoute(routing_id);
+}
+
+void GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
+ router_.RouteMessage(message);
+}
+
diff --git a/chrome/browser/gpu_process_host_ui_shim.h b/chrome/browser/gpu_process_host_ui_shim.h
new file mode 100644
index 0000000..70696ca
--- /dev/null
+++ b/chrome/browser/gpu_process_host_ui_shim.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_GPU_PROCESS_HOST_UI_SHIM_H_
+#define CHROME_BROWSER_GPU_PROCESS_HOST_UI_SHIM_H_
+
+// This class lives on the UI thread and supports classes like the
+// BackingStoreProxy, which must live on the UI thread. The IO thread
+// portion of this class, the GpuProcessHost, is responsible for
+// shuttling messages between the browser and GPU processes.
+
+#include "base/singleton.h"
+#include "chrome/common/gpu_native_window_handle.h"
+#include "chrome/common/message_router.h"
+#include "ipc/ipc_channel.h"
+#include "gfx/native_widget_types.h"
+
+class GpuProcessHostUIShim : public IPC::Channel::Sender,
+ public IPC::Channel::Listener {
+ public:
+ // Getter for the singleton. This will return NULL on failure.
+ static GpuProcessHostUIShim* Get();
+
+ int32 GetNextRoutingId();
+
+ // Creates the new remote view and returns the routing ID for the view, or 0
+ // on failure.
+ int32 NewRenderWidgetHostView(GpuNativeWindowHandle parent);
+
+ // IPC::Channel::Sender implementation.
+ virtual bool Send(IPC::Message* msg);
+
+ // IPC::Channel::Listener implementation.
+ // The GpuProcessHost causes this to be called on the UI thread to
+ // dispatch the incoming messages from the GPU process, which are
+ // actually received on the IO thread.
+ virtual void OnMessageReceived(const IPC::Message& message);
+
+ // See documentation on MessageRouter for AddRoute and RemoveRoute
+ void AddRoute(int32 routing_id, IPC::Channel::Listener* listener);
+ void RemoveRoute(int32 routing_id);
+
+ private:
+ friend struct DefaultSingletonTraits<GpuProcessHostUIShim>;
+
+ GpuProcessHostUIShim();
+ virtual ~GpuProcessHostUIShim();
+
+ int last_routing_id_;
+
+ MessageRouter router_;
+};
+
+#endif // CHROME_BROWSER_GPU_PROCESS_HOST_UI_SHIM_H_
+
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 60d0d4e..5f9236b 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/browser/net/dns_global.h"
#include "chrome/browser/net/passive_log_collector.h"
@@ -169,6 +170,8 @@ void IOThread::CleanUp() {
globals_->host_resolver.get()->GetAsHostResolverImpl()->Shutdown();
}
+ GpuProcessHost::Shutdown();
+
delete globals_;
globals_ = NULL;
diff --git a/chrome/browser/renderer_host/backing_store_proxy.cc b/chrome/browser/renderer_host/backing_store_proxy.cc
index c41900d..ba3538b 100644
--- a/chrome/browser/renderer_host/backing_store_proxy.cc
+++ b/chrome/browser/renderer_host/backing_store_proxy.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/renderer_host/backing_store_proxy.h"
#include "build/build_config.h"
-#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/gpu_process_host_ui_shim.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/common/gpu_messages.h"
@@ -18,17 +18,17 @@
BackingStoreProxy::BackingStoreProxy(RenderWidgetHost* widget,
const gfx::Size& size,
- GpuProcessHost* process,
+ GpuProcessHostUIShim* process_shim,
int32 routing_id)
: BackingStore(widget, size),
- process_(process),
+ process_shim_(process_shim),
routing_id_(routing_id),
waiting_for_paint_ack_(false) {
- process_->AddRoute(routing_id_, this);
+ process_shim_->AddRoute(routing_id_, this);
}
BackingStoreProxy::~BackingStoreProxy() {
- process_->RemoveRoute(routing_id_);
+ process_shim_->RemoveRoute(routing_id_);
}
void BackingStoreProxy::PaintToBackingStore(
@@ -46,7 +46,7 @@ void BackingStoreProxy::PaintToBackingStore(
process_id = process->GetHandle();
#endif
- if (process_->Send(new GpuMsg_PaintToBackingStore(
+ if (process_shim_->Send(new GpuMsg_PaintToBackingStore(
routing_id_, process_id, bitmap, bitmap_rect, copy_rects))) {
// Message sent successfully, so the caller can not destroy the
// TransportDIB. OnDonePaintingToBackingStore will free it later.
@@ -67,8 +67,8 @@ bool BackingStoreProxy::CopyFromBackingStore(const gfx::Rect& rect,
void BackingStoreProxy::ScrollBackingStore(int dx, int dy,
const gfx::Rect& clip_rect,
const gfx::Size& view_size) {
- process_->Send(new GpuMsg_ScrollBackingStore(routing_id_, dx, dy,
- clip_rect, view_size));
+ process_shim_->Send(new GpuMsg_ScrollBackingStore(routing_id_, dx, dy,
+ clip_rect, view_size));
}
void BackingStoreProxy::OnMessageReceived(const IPC::Message& msg) {
diff --git a/chrome/browser/renderer_host/backing_store_proxy.h b/chrome/browser/renderer_host/backing_store_proxy.h
index 0b5059f..4d572b6 100644
--- a/chrome/browser/renderer_host/backing_store_proxy.h
+++ b/chrome/browser/renderer_host/backing_store_proxy.h
@@ -9,13 +9,13 @@
#include "chrome/browser/renderer_host/backing_store.h"
#include "ipc/ipc_channel.h"
-class GpuProcessHost;
+class GpuProcessHostUIShim;
class BackingStoreProxy : public BackingStore,
public IPC::Channel::Listener {
public:
BackingStoreProxy(RenderWidgetHost* widget, const gfx::Size& size,
- GpuProcessHost* process, int32 routing_id);
+ GpuProcessHostUIShim* process_shim, int32 routing_id);
virtual ~BackingStoreProxy();
// BackingStore implementation.
@@ -39,7 +39,7 @@ class BackingStoreProxy : public BackingStore,
// Message handlers.
void OnPaintToBackingStoreACK();
- GpuProcessHost* process_;
+ GpuProcessHostUIShim* process_shim_;
int32 routing_id_;
// Set to true when we're waiting for the GPU process to do a paint and send
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index 7f72a79..15517fc 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -773,10 +773,6 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
OnExtensionRemoveListener)
IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionCloseChannel,
OnExtensionCloseChannel)
- IPC_MESSAGE_HANDLER(ViewHostMsg_EstablishGpuChannel,
- OnMsgEstablishGpuChannel)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SynchronizeGpu,
- OnMsgSynchronizeGpu)
IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_RequestDictionary,
OnSpellCheckerRequestDictionary)
IPC_MESSAGE_UNHANDLED_ERROR()
@@ -981,14 +977,6 @@ void BrowserRenderProcessHost::OnExtensionCloseChannel(int port_id) {
}
}
-void BrowserRenderProcessHost::OnMsgEstablishGpuChannel() {
- GpuProcessHost::Get()->EstablishGpuChannel(id());
-}
-
-void BrowserRenderProcessHost::OnMsgSynchronizeGpu(IPC::Message* reply) {
- GpuProcessHost::Get()->Synchronize(id(), reply);
-}
-
void BrowserRenderProcessHost::OnSpellCheckerRequestDictionary() {
if (profile()->GetSpellCheckHost()) {
// The spellchecker initialization already started and finished; just send
diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h
index 9a9c833..277a53e 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.h
+++ b/chrome/browser/renderer_host/browser_render_process_host.h
@@ -110,12 +110,6 @@ class BrowserRenderProcessHost : public RenderProcessHost,
void OnExtensionAddListener(const std::string& event_name);
void OnExtensionRemoveListener(const std::string& event_name);
void OnExtensionCloseChannel(int port_id);
- // Renderer process is requesting that the browser process establish a GPU
- // channel.
- void OnMsgEstablishGpuChannel();
- // Renderer process is requesting that outstanding asynchronous GPU-related
- // messages are processed.
- void OnMsgSynchronizeGpu(IPC::Message* reply);
// Initialize support for visited links. Send the renderer process its initial
// set of visited links.
diff --git a/chrome/browser/renderer_host/gpu_view_host.cc b/chrome/browser/renderer_host/gpu_view_host.cc
index a81db6b..fa8c19c 100644
--- a/chrome/browser/renderer_host/gpu_view_host.cc
+++ b/chrome/browser/renderer_host/gpu_view_host.cc
@@ -4,43 +4,47 @@
#include "chrome/browser/renderer_host/gpu_view_host.h"
-#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/gpu_process_host_ui_shim.h"
#include "chrome/browser/renderer_host/backing_store_proxy.h"
#include "chrome/browser/renderer_host/video_layer_proxy.h"
#include "chrome/common/gpu_messages.h"
GpuViewHost::GpuViewHost(RenderWidgetHost* widget, GpuNativeWindowHandle parent)
: widget_(widget),
- process_(GpuProcessHost::Get()),
+ process_shim_(GpuProcessHostUIShim::Get()),
routing_id_(0) {
- if (!process_) {
+ if (!process_shim_) {
// TODO(brettw) handle error.
return;
}
- routing_id_ = process_->NewRenderWidgetHostView(parent);
+ routing_id_ = process_shim_->NewRenderWidgetHostView(parent);
}
GpuViewHost::~GpuViewHost() {
}
BackingStore* GpuViewHost::CreateBackingStore(const gfx::Size& size) {
- int32 backing_store_routing_id = process_->GetNextRoutingId();
- process_->Send(new GpuMsg_NewBackingStore(routing_id_,
- backing_store_routing_id,
- size));
- return new BackingStoreProxy(widget_, size,
- process_, backing_store_routing_id);
+ int32 backing_store_routing_id = process_shim_->GetNextRoutingId();
+ BackingStoreProxy* result =
+ new BackingStoreProxy(widget_, size,
+ process_shim_, backing_store_routing_id);
+ process_shim_->Send(new GpuMsg_NewBackingStore(routing_id_,
+ backing_store_routing_id,
+ size));
+ return result;
}
VideoLayer* GpuViewHost::CreateVideoLayer(const gfx::Size& size) {
- int32 video_layer_routing_id = process_->GetNextRoutingId();
- process_->Send(new GpuMsg_NewVideoLayer(routing_id_,
- video_layer_routing_id,
- size));
- return new VideoLayerProxy(widget_, size,
- process_, video_layer_routing_id);
+ int32 video_layer_routing_id = process_shim_->GetNextRoutingId();
+ VideoLayerProxy* result =
+ new VideoLayerProxy(widget_, size,
+ process_shim_, video_layer_routing_id);
+ process_shim_->Send(new GpuMsg_NewVideoLayer(routing_id_,
+ video_layer_routing_id,
+ size));
+ return result;
}
void GpuViewHost::OnWindowPainted() {
- process_->Send(new GpuMsg_WindowPainted(routing_id_));
+ process_shim_->Send(new GpuMsg_WindowPainted(routing_id_));
}
diff --git a/chrome/browser/renderer_host/gpu_view_host.h b/chrome/browser/renderer_host/gpu_view_host.h
index 910c978..8d19e07 100644
--- a/chrome/browser/renderer_host/gpu_view_host.h
+++ b/chrome/browser/renderer_host/gpu_view_host.h
@@ -9,7 +9,7 @@
#include "chrome/common/gpu_native_window_handle.h"
class BackingStore;
-class GpuProcessHost;
+class GpuProcessHostUIShim;
class RenderWidgetHost;
class VideoLayer;
@@ -40,7 +40,7 @@ class GpuViewHost {
private:
RenderWidgetHost* widget_;
- GpuProcessHost* process_;
+ GpuProcessHostUIShim* process_shim_;
int32 routing_id_;
DISALLOW_COPY_AND_ASSIGN(GpuViewHost);
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index de9e836..3dfcf63 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/geolocation/geolocation_permission_context.h"
#include "chrome/browser/geolocation/geolocation_dispatcher_host.h"
+#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
#include "chrome/browser/metrics/histogram_synchronizer.h"
@@ -540,6 +541,10 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
#if defined(USE_TCMALLOC)
IPC_MESSAGE_HANDLER(ViewHostMsg_RendererTcmalloc, OnRendererTcmalloc)
#endif
+ IPC_MESSAGE_HANDLER(ViewHostMsg_EstablishGpuChannel,
+ OnEstablishGpuChannel)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SynchronizeGpu,
+ OnSynchronizeGpu)
IPC_MESSAGE_UNHANDLED(
handled = false)
IPC_END_MESSAGE_MAP_EX()
@@ -1411,6 +1416,19 @@ void ResourceMessageFilter::OnRendererTcmalloc(base::ProcessId pid,
}
#endif
+void ResourceMessageFilter::OnEstablishGpuChannel() {
+ GpuProcessHost::Get()->EstablishGpuChannel(id(), this);
+}
+
+void ResourceMessageFilter::OnSynchronizeGpu(IPC::Message* reply) {
+ // We handle this message (and the other GPU process messages) here
+ // rather than handing the message to the GpuProcessHost for
+ // dispatch so that we can use the DELAY_REPLY macro to synthesize
+ // the reply message, and also send down a "this" pointer so that
+ // the GPU process host can send the reply later.
+ GpuProcessHost::Get()->Synchronize(reply, this);
+}
+
void ResourceMessageFilter::OnGetExtensionMessageBundle(
const std::string& extension_id, IPC::Message* reply_msg) {
ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index 2abc4c0..a69fd78 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -328,6 +328,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
void OnTranslateText(ViewHostMsg_TranslateTextParam param);
+ void OnEstablishGpuChannel();
+ void OnSynchronizeGpu(IPC::Message* reply);
+
#if defined(USE_X11)
void SendDelayedReply(IPC::Message* reply_msg);
void DoOnGetScreenInfo(gfx::NativeViewId view, IPC::Message* reply_msg);
diff --git a/chrome/browser/renderer_host/video_layer_proxy.cc b/chrome/browser/renderer_host/video_layer_proxy.cc
index 1fdae24..3df1d25 100644
--- a/chrome/browser/renderer_host/video_layer_proxy.cc
+++ b/chrome/browser/renderer_host/video_layer_proxy.cc
@@ -4,23 +4,23 @@
#include "chrome/browser/renderer_host/video_layer_proxy.h"
-#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/gpu_process_host_ui_shim.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/gpu_messages.h"
#include "gfx/rect.h"
VideoLayerProxy::VideoLayerProxy(RenderWidgetHost* widget,
const gfx::Size& size,
- GpuProcessHost* process,
+ GpuProcessHostUIShim* process_shim,
int32 routing_id)
: VideoLayer(widget, size),
- process_(process),
+ process_shim_(process_shim),
routing_id_(routing_id) {
- process_->AddRoute(routing_id_, this);
+ process_shim_->AddRoute(routing_id_, this);
}
VideoLayerProxy::~VideoLayerProxy() {
- process_->RemoveRoute(routing_id_);
+ process_shim_->RemoveRoute(routing_id_);
}
void VideoLayerProxy::CopyTransportDIB(RenderProcessHost* process,
@@ -33,7 +33,7 @@ void VideoLayerProxy::CopyTransportDIB(RenderProcessHost* process,
process_id = process->GetHandle();
#endif
- if (process_->Send(new GpuMsg_PaintToVideoLayer(
+ if (process_shim_->Send(new GpuMsg_PaintToVideoLayer(
routing_id_, process_id, bitmap, bitmap_rect))) {
} else {
// TODO(scherkus): what to do ?!?!
diff --git a/chrome/browser/renderer_host/video_layer_proxy.h b/chrome/browser/renderer_host/video_layer_proxy.h
index 637525e..02b90ed 100644
--- a/chrome/browser/renderer_host/video_layer_proxy.h
+++ b/chrome/browser/renderer_host/video_layer_proxy.h
@@ -8,13 +8,13 @@
#include "chrome/browser/renderer_host/video_layer.h"
#include "ipc/ipc_channel.h"
-class GpuProcessHost;
+class GpuProcessHostUIShim;
// Proxies YUV video layer data to the GPU process for rendering.
class VideoLayerProxy : public VideoLayer, public IPC::Channel::Listener {
public:
VideoLayerProxy(RenderWidgetHost* widget, const gfx::Size& size,
- GpuProcessHost* process, int32 routing_id);
+ GpuProcessHostUIShim* process_shim, int32 routing_id);
virtual ~VideoLayerProxy();
// VideoLayer implementation.
@@ -32,7 +32,7 @@ class VideoLayerProxy : public VideoLayer, public IPC::Channel::Listener {
void OnPaintToVideoLayerACK();
// GPU process receiving our proxied requests.
- GpuProcessHost* process_;
+ GpuProcessHostUIShim* process_shim_;
// IPC routing ID to use when communicating with the GPU process.
int32 routing_id_;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index cbd819bc..5335a20b 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1124,6 +1124,8 @@
'browser/google_util.h',
'browser/gpu_process_host.cc',
'browser/gpu_process_host.h',
+ 'browser/gpu_process_host_ui_shim.cc',
+ 'browser/gpu_process_host_ui_shim.h',
'browser/gtk/about_chrome_dialog.cc',
'browser/gtk/about_chrome_dialog.h',
'browser/gtk/accelerators_gtk.cc',
diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h
index 628671d..7c8f033 100644
--- a/chrome/common/gpu_messages_internal.h
+++ b/chrome/common/gpu_messages_internal.h
@@ -31,8 +31,7 @@ IPC_BEGIN_MESSAGES(Gpu)
// completed. (This message can't be synchronous because the
// GpuProcessHost uses an IPC::ChannelProxy, which sends all messages
// asynchronously.) Results in a GpuHostMsg_SynchronizeReply.
- IPC_MESSAGE_CONTROL1(GpuMsg_Synchronize,
- int /* renderer_id */)
+ IPC_MESSAGE_CONTROL0(GpuMsg_Synchronize)
IPC_MESSAGE_CONTROL2(GpuMsg_NewRenderWidgetHostView,
GpuNativeWindowHandle, /* parent window */
@@ -100,8 +99,7 @@ IPC_BEGIN_MESSAGES(GpuHost)
IPC::ChannelHandle /* channel_handle */)
// Response to a GpuMsg_Synchronize message.
- IPC_MESSAGE_CONTROL1(GpuHostMsg_SynchronizeReply,
- int /* renderer_id */)
+ IPC_MESSAGE_CONTROL0(GpuHostMsg_SynchronizeReply)
IPC_END_MESSAGES(GpuHost)
diff --git a/chrome/common/sandbox_policy.cc b/chrome/common/sandbox_policy.cc
index d0766e9..5153c4d 100644
--- a/chrome/common/sandbox_policy.cc
+++ b/chrome/common/sandbox_policy.cc
@@ -421,7 +421,8 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
(type != ChildProcessInfo::NACL_BROKER_PROCESS) &&
!browser_command_line.HasSwitch(switches::kNoSandbox) &&
(type != ChildProcessInfo::PLUGIN_PROCESS ||
- browser_command_line.HasSwitch(switches::kSafePlugins));
+ browser_command_line.HasSwitch(switches::kSafePlugins)) &&
+ (type != ChildProcessInfo::GPU_PROCESS);
#if !defined (GOOGLE_CHROME_BUILD)
if (browser_command_line.HasSwitch(switches::kInProcessPlugins)) {
// In process plugins won't work if the sandbox is enabled.
diff --git a/chrome/gpu/gpu_channel.cc b/chrome/gpu/gpu_channel.cc
index b2b5bf9..b775acf 100644
--- a/chrome/gpu/gpu_channel.cc
+++ b/chrome/gpu/gpu_channel.cc
@@ -91,8 +91,10 @@ void GpuChannel::OnChannelError() {
#if defined(ENABLE_GPU)
// Destroy all the stubs on this channel.
- for (size_t i = 0; i < stubs_.size(); ++i) {
- router_.RemoveRoute(stubs_[i]->route_id());
+ for (StubMap::const_iterator iter = stubs_.begin();
+ iter != stubs_.end();
+ ++iter) {
+ router_.RemoveRoute(iter->second->route_id());
}
stubs_.clear();
#endif
diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc
index 5e096a5..c2c190e 100644
--- a/chrome/gpu/gpu_thread.cc
+++ b/chrome/gpu/gpu_thread.cc
@@ -81,8 +81,8 @@ void GpuThread::OnEstablishChannel(int renderer_id) {
Send(new GpuHostMsg_ChannelEstablished(channel_handle));
}
-void GpuThread::OnSynchronize(int renderer_id) {
- Send(new GpuHostMsg_SynchronizeReply(renderer_id));
+void GpuThread::OnSynchronize() {
+ Send(new GpuHostMsg_SynchronizeReply());
}
void GpuThread::OnNewRenderWidgetHostView(GpuNativeWindowHandle parent_window,
diff --git a/chrome/gpu/gpu_thread.h b/chrome/gpu/gpu_thread.h
index bc06051..fdef70b 100644
--- a/chrome/gpu/gpu_thread.h
+++ b/chrome/gpu/gpu_thread.h
@@ -36,7 +36,7 @@ class GpuThread : public ChildThread {
// Message handlers.
void OnEstablishChannel(int renderer_id);
- void OnSynchronize(int renderer_id);
+ void OnSynchronize();
void OnNewRenderWidgetHostView(GpuNativeWindowHandle parent_window,
int32 routing_id);
diff --git a/chrome/renderer/gpu_channel_host.cc b/chrome/renderer/gpu_channel_host.cc
index 8d2cdd9..3562c0b 100644
--- a/chrome/renderer/gpu_channel_host.cc
+++ b/chrome/renderer/gpu_channel_host.cc
@@ -44,7 +44,6 @@ void GpuChannelHost::OnChannelError() {
// OpenGL as a lost context.
for (ProxyMap::iterator iter = proxies_.begin();
iter != proxies_.end(); iter++) {
- proxies_.erase(iter->first);
router_.RemoveRoute(iter->first);
iter->second->OnChannelError();
}
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index aff8fa6..81636c7 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -687,8 +687,10 @@ void RenderThread::UpdateActiveExtensions() {
void RenderThread::EstablishGpuChannel() {
if (gpu_channel_.get()) {
- // Do nothing if we are already establishing GPU channel.
- if (gpu_channel_->state() == GpuChannelHost::UNCONNECTED)
+ // Do nothing if we already have a GPU channel or are already
+ // establishing one.
+ if (gpu_channel_->state() == GpuChannelHost::UNCONNECTED ||
+ gpu_channel_->state() == GpuChannelHost::CONNECTED)
return;
// Recreate the channel if it has been lost.
@@ -704,8 +706,16 @@ void RenderThread::EstablishGpuChannel() {
}
GpuChannelHost* RenderThread::EstablishGpuChannelSync() {
- EstablishGpuChannel();
- Send(new ViewHostMsg_SynchronizeGpu());
+ // We may need to retry the connection establishment if an existing
+ // connection has gone bad, which will not be detected in
+ // EstablishGpuChannel since we do not send duplicate
+ // ViewHostMsg_EstablishGpuChannel messages -- doing so breaks the
+ // preexisting connection in bad ways.
+ bool retry = true;
+ for (int i = 0; i < 2 && retry; ++i) {
+ EstablishGpuChannel();
+ retry = !Send(new ViewHostMsg_SynchronizeGpu());
+ }
// TODO(kbr): the GPU channel is still in the unconnected state at this point.
// Need to figure out whether it is really safe to return it.
return gpu_channel_.get();