Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(681)

Side by Side Diff: chrome/browser/gpu_process_host.cc

Issue 1546001: Split GpuProcessHost into GpuProcessHostUIShim, which runs on the UI... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/gpu_process_host.h ('k') | chrome/browser/gpu_process_host_ui_shim.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/gpu_process_host.h" 5 #include "chrome/browser/gpu_process_host.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/singleton.h"
9 #include "base/thread.h" 8 #include "base/thread.h"
10 #include "chrome/browser/browser_process.h" 9 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/child_process_host.h" 10 #include "chrome/browser/chrome_thread.h"
12 #include "chrome/browser/child_process_launcher.h" 11 #include "chrome/browser/gpu_process_host_ui_shim.h"
13 #include "chrome/browser/io_thread.h"
14 #include "chrome/browser/renderer_host/render_process_host.h"
15 #include "chrome/common/child_process_info.h"
16 #include "chrome/common/chrome_switches.h" 12 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/gpu_messages.h" 13 #include "chrome/common/gpu_messages.h"
18 #include "chrome/common/render_messages.h" 14 #include "chrome/common/render_messages.h"
19 #include "ipc/ipc_switches.h" 15 #include "ipc/ipc_switches.h"
20 16
21 GpuProcessHost::GpuProcessHost() : last_routing_id_(1) { 17 namespace {
18
19 // Tasks used by this file
20 class RouteOnUIThreadTask : public Task {
21 public:
22 explicit RouteOnUIThreadTask(const IPC::Message& msg) {
23 msg_ = new IPC::Message(msg);
24 }
25
26 private:
27 void Run() {
28 GpuProcessHostUIShim::Get()->OnMessageReceived(*msg_);
29 delete msg_;
30 msg_ = NULL;
31 }
32 IPC::Message* msg_;
33 };
34
35 // Global GpuProcessHost instance.
36 // We can not use Singleton<GpuProcessHost> because that gets
37 // terminated on the wrong thread (main thread). We need the
38 // GpuProcessHost to be terminated on the same thread on which it is
39 // initialized, the IO thread.
40 static GpuProcessHost* sole_instance_;
41
42 } // anonymous namespace
43
44 GpuProcessHost::GpuProcessHost()
45 : ChildProcessHost(GPU_PROCESS, NULL),
46 initialized_(false),
47 initialized_successfully_(false) {
48 }
49
50 GpuProcessHost::~GpuProcessHost() {
51 while (!queued_synchronization_replies_.empty()) {
52 delete queued_synchronization_replies_.front().reply;
53 queued_synchronization_replies_.pop();
54 }
55 }
56
57 bool GpuProcessHost::EnsureInitialized() {
58 if (!initialized_) {
59 initialized_ = true;
60 initialized_successfully_ = Init();
61 }
62 return initialized_successfully_;
63 }
64
65 bool GpuProcessHost::Init() {
66 if (!CreateChannel())
67 return false;
68
22 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); 69 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
23 std::wstring gpu_launcher = 70 std::wstring gpu_launcher =
24 browser_command_line.GetSwitchValue(switches::kGpuLauncher); 71 browser_command_line.GetSwitchValue(switches::kGpuLauncher);
25 72
26 FilePath exe_path = ChildProcessHost::GetChildPath(gpu_launcher.empty()); 73 FilePath exe_path = ChildProcessHost::GetChildPath(gpu_launcher.empty());
27 if (exe_path.empty()) 74 if (exe_path.empty())
28 return; 75 return false;
29
30 std::string channel_id = ChildProcessInfo::GenerateRandomChannelID(this);
31 channel_.reset(new IPC::ChannelProxy(
32 channel_id,
33 IPC::Channel::MODE_SERVER,
34 this,
35 NULL, // No filter (for now).
36 g_browser_process->io_thread()->message_loop()));
37 76
38 CommandLine* cmd_line = new CommandLine(exe_path); 77 CommandLine* cmd_line = new CommandLine(exe_path);
39 cmd_line->AppendSwitchWithValue(switches::kProcessType, 78 cmd_line->AppendSwitchWithValue(switches::kProcessType,
40 switches::kGpuProcess); 79 switches::kGpuProcess);
41 cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, 80 cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
42 ASCIIToWide(channel_id)); 81 ASCIIToWide(channel_id()));
43 82
44 const CommandLine& browser_cmd_line = *CommandLine::ForCurrentProcess(); 83 const CommandLine& browser_cmd_line = *CommandLine::ForCurrentProcess();
45 PropagateBrowserCommandLineToGpu(browser_cmd_line, cmd_line); 84 PropagateBrowserCommandLineToGpu(browser_cmd_line, cmd_line);
46 85
47 // If specified, prepend a launcher program to the command line. 86 // If specified, prepend a launcher program to the command line.
48 if (!gpu_launcher.empty()) 87 if (!gpu_launcher.empty())
49 cmd_line->PrependWrapper(gpu_launcher); 88 cmd_line->PrependWrapper(gpu_launcher);
50 89
51 // Spawn the child process asynchronously to avoid blocking the UI thread. 90 Launch(
52 child_process_.reset(new ChildProcessLauncher(
53 #if defined(OS_WIN) 91 #if defined(OS_WIN)
54 FilePath(), 92 FilePath(),
55 #elif defined(POSIX) 93 #elif defined(POSIX)
56 false, // Never use the zygote (GPU plugin can't be sandboxed). 94 false, // Never use the zygote (GPU plugin can't be sandboxed).
57 base::environment_vector(), 95 base::environment_vector(),
58 channel_->GetClientFileDescriptor(),
59 #endif 96 #endif
60 cmd_line, 97 cmd_line);
61 this));
62 }
63 98
64 GpuProcessHost::~GpuProcessHost() { 99 return true;
65 while (!queued_synchronization_replies_.empty()) {
66 delete queued_synchronization_replies_.front();
67 queued_synchronization_replies_.pop();
68 }
69 } 100 }
70 101
71 // static 102 // static
72 GpuProcessHost* GpuProcessHost::Get() { 103 GpuProcessHost* GpuProcessHost::Get() {
73 GpuProcessHost* host = Singleton<GpuProcessHost>::get(); 104 if (sole_instance_ == NULL)
74 if (!host->child_process_.get()) 105 sole_instance_ = new GpuProcessHost();
75 return NULL; // Failed to init. 106 return sole_instance_;
76 return host;
77 } 107 }
78 108
79 int32 GpuProcessHost::GetNextRoutingId() { 109 // static
80 return ++last_routing_id_; 110 void GpuProcessHost::Shutdown() {
81 } 111 if (sole_instance_) {
82 112 delete sole_instance_;
83 int32 GpuProcessHost::NewRenderWidgetHostView(GpuNativeWindowHandle parent) { 113 sole_instance_ = NULL;
84 int32 routing_id = GetNextRoutingId(); 114 }
85 Send(new GpuMsg_NewRenderWidgetHostView(parent, routing_id));
86 return routing_id;
87 } 115 }
88 116
89 bool GpuProcessHost::Send(IPC::Message* msg) { 117 bool GpuProcessHost::Send(IPC::Message* msg) {
90 if (!channel_.get()) { 118 if (!EnsureInitialized())
91 delete msg;
92 return false; 119 return false;
93 }
94 120
95 if (child_process_.get() && child_process_->IsStarting()) { 121 return ChildProcessHost::Send(msg);
96 queued_messages_.push(msg);
97 return true;
98 }
99
100 return channel_->Send(msg);
101 } 122 }
102 123
103 void GpuProcessHost::OnMessageReceived(const IPC::Message& message) { 124 void GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
104 if (message.routing_id() == MSG_ROUTING_CONTROL) { 125 if (message.routing_id() == MSG_ROUTING_CONTROL) {
105 OnControlMessageReceived(message); 126 OnControlMessageReceived(message);
106 } else { 127 } else {
107 router_.OnMessageReceived(message); 128 // Need to transfer this message to the UI thread and the
129 // GpuProcessHostUIShim for dispatching via its message router.
130 ChromeThread::PostTask(ChromeThread::UI,
131 FROM_HERE,
132 new RouteOnUIThreadTask(message));
108 } 133 }
109 } 134 }
110 135
111 void GpuProcessHost::OnChannelConnected(int32 peer_pid) { 136 void GpuProcessHost::EstablishGpuChannel(int renderer_id,
112 } 137 ResourceMessageFilter* filter) {
113 138 if (Send(new GpuMsg_EstablishChannel(renderer_id))) {
114 void GpuProcessHost::OnChannelError() { 139 sent_requests_.push(ChannelRequest(filter));
115 } 140 } else {
116 141 ReplyToRenderer(IPC::ChannelHandle(), filter);
117 void GpuProcessHost::OnProcessLaunched() {
118 while (!queued_messages_.empty()) {
119 Send(queued_messages_.front());
120 queued_messages_.pop();
121 } 142 }
122 } 143 }
123 144
124 void GpuProcessHost::AddRoute(int32 routing_id, 145 void GpuProcessHost::Synchronize(IPC::Message* reply,
125 IPC::Channel::Listener* listener) { 146 ResourceMessageFilter* filter) {
126 router_.AddRoute(routing_id, listener); 147 queued_synchronization_replies_.push(SynchronizationRequest(reply, filter));
127 } 148 Send(new GpuMsg_Synchronize());
128
129 void GpuProcessHost::RemoveRoute(int32 routing_id) {
130 router_.RemoveRoute(routing_id);
131 }
132
133 void GpuProcessHost::EstablishGpuChannel(int renderer_id) {
134 if (Send(new GpuMsg_EstablishChannel(renderer_id)))
135 sent_requests_.push(ChannelRequest(renderer_id));
136 else
137 ReplyToRenderer(renderer_id, IPC::ChannelHandle());
138 }
139
140 void GpuProcessHost::Synchronize(int renderer_id, IPC::Message* reply) {
141 // ************
142 // TODO(kbr): the handling of this synchronous message (which is
143 // needed for proper initialization semantics of APIs like WebGL) is
144 // currently broken on Windows because the renderer is sending a
145 // synchronous message to the browser's UI thread. To fix this, the
146 // GpuProcessHost needs to move to the IO thread, and any backing
147 // store handling needs to remain on the UI thread in a new
148 // GpuProcessHostProxy, where work is sent from the IO thread to the
149 // UI thread via PostTask.
150 // ************
151 queued_synchronization_replies_.push(reply);
152 CHECK(Send(new GpuMsg_Synchronize(renderer_id)));
153 } 149 }
154 150
155 void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) { 151 void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
156 IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message) 152 IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
157 IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished) 153 IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
158 IPC_MESSAGE_HANDLER(GpuHostMsg_SynchronizeReply, OnSynchronizeReply) 154 IPC_MESSAGE_HANDLER(GpuHostMsg_SynchronizeReply, OnSynchronizeReply)
159 IPC_MESSAGE_UNHANDLED_ERROR() 155 IPC_MESSAGE_UNHANDLED_ERROR()
160 IPC_END_MESSAGE_MAP() 156 IPC_END_MESSAGE_MAP()
161 } 157 }
162 158
163 void GpuProcessHost::OnChannelEstablished( 159 void GpuProcessHost::OnChannelEstablished(
164 const IPC::ChannelHandle& channel_handle) { 160 const IPC::ChannelHandle& channel_handle) {
165 const ChannelRequest& request = sent_requests_.front(); 161 const ChannelRequest& request = sent_requests_.front();
166 162 ReplyToRenderer(channel_handle, request.filter);
167 ReplyToRenderer(request.renderer_id, channel_handle);
168 sent_requests_.pop(); 163 sent_requests_.pop();
169 } 164 }
170 165
171 void GpuProcessHost::OnSynchronizeReply(int renderer_id) { 166 void GpuProcessHost::OnSynchronizeReply() {
172 IPC::Message* reply = queued_synchronization_replies_.front(); 167 const SynchronizationRequest& request =
168 queued_synchronization_replies_.front();
169 request.filter->Send(request.reply);
173 queued_synchronization_replies_.pop(); 170 queued_synchronization_replies_.pop();
174 RenderProcessHost* process_host = RenderProcessHost::FromID(renderer_id);
175 if (!process_host) {
176 delete reply;
177 return;
178 }
179 CHECK(process_host->Send(reply));
180 } 171 }
181 172
182 void GpuProcessHost::ReplyToRenderer( 173 void GpuProcessHost::ReplyToRenderer(
183 int renderer_id, 174 const IPC::ChannelHandle& channel,
184 const IPC::ChannelHandle& channel) { 175 ResourceMessageFilter* filter) {
185 // Check whether the renderer process is still around. 176 ViewMsg_GpuChannelEstablished* message =
186 RenderProcessHost* process_host = RenderProcessHost::FromID(renderer_id);
187 if (!process_host)
188 return;
189
190 ViewMsg_GpuChannelEstablished* msg =
191 new ViewMsg_GpuChannelEstablished(channel); 177 new ViewMsg_GpuChannelEstablished(channel);
192 // If the renderer process is performing synchronous initialization, 178 // If the renderer process is performing synchronous initialization,
193 // it needs to handle this message before receiving the reply for 179 // it needs to handle this message before receiving the reply for
194 // the synchronous ViewHostMsg_SynchronizeGpu message. 180 // the synchronous ViewHostMsg_SynchronizeGpu message.
195 msg->set_unblock(true); 181 message->set_unblock(true);
196 CHECK(process_host->Send(msg)); 182 filter->Send(message);
197 } 183 }
198 184
199 void GpuProcessHost::PropagateBrowserCommandLineToGpu( 185 void GpuProcessHost::PropagateBrowserCommandLineToGpu(
200 const CommandLine& browser_cmd, 186 const CommandLine& browser_cmd,
201 CommandLine* gpu_cmd) const { 187 CommandLine* gpu_cmd) const {
202 // Propagate the following switches to the GPU process command line (along 188 // Propagate the following switches to the GPU process command line (along
203 // with any associated values) if present in the browser command line. 189 // with any associated values) if present in the browser command line.
204 static const char* const switch_names[] = { 190 static const char* const switch_names[] = {
205 switches::kDisableLogging, 191 switches::kDisableLogging,
206 switches::kEnableLogging, 192 switches::kEnableLogging,
207 switches::kGpuStartupDialog, 193 switches::kGpuStartupDialog,
208 switches::kLoggingLevel, 194 switches::kLoggingLevel,
209 }; 195 };
210 196
211 for (size_t i = 0; i < arraysize(switch_names); ++i) { 197 for (size_t i = 0; i < arraysize(switch_names); ++i) {
212 if (browser_cmd.HasSwitch(switch_names[i])) { 198 if (browser_cmd.HasSwitch(switch_names[i])) {
213 gpu_cmd->AppendSwitchWithValue(switch_names[i], 199 gpu_cmd->AppendSwitchWithValue(switch_names[i],
214 browser_cmd.GetSwitchValueASCII(switch_names[i])); 200 browser_cmd.GetSwitchValueASCII(switch_names[i]));
215 } 201 }
216 } 202 }
217 } 203 }
204
205 URLRequestContext* GpuProcessHost::GetRequestContext(
206 uint32 request_id,
207 const ViewHostMsg_Resource_Request& request_data) {
208 return NULL;
209 }
210
211 bool GpuProcessHost::CanShutdown() {
212 return true;
213 }
214
OLDNEW
« no previous file with comments | « chrome/browser/gpu_process_host.h ('k') | chrome/browser/gpu_process_host_ui_shim.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698