OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "native_client/src/trusted/plugin/pnacl_translate_thread.h" | 5 #include "native_client/src/trusted/plugin/pnacl_translate_thread.h" |
6 | 6 |
7 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" | 7 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" |
8 #include "native_client/src/trusted/plugin/plugin.h" | 8 #include "native_client/src/trusted/plugin/plugin.h" |
9 #include "native_client/src/trusted/plugin/pnacl_resources.h" | 9 #include "native_client/src/trusted/plugin/pnacl_resources.h" |
10 #include "native_client/src/trusted/plugin/srpc_params.h" | 10 #include "native_client/src/trusted/plugin/srpc_params.h" |
11 #include "native_client/src/trusted/plugin/temporary_file.h" | 11 #include "native_client/src/trusted/plugin/temporary_file.h" |
12 #include "native_client/src/trusted/plugin/utility.h" | 12 #include "native_client/src/trusted/plugin/utility.h" |
13 | 13 |
14 namespace plugin { | 14 namespace plugin { |
15 | 15 |
16 PnaclTranslateThread::PnaclTranslateThread() : subprocesses_should_die_(false), | 16 PnaclTranslateThread::PnaclTranslateThread() : llc_subprocess_active_(false), |
17 current_rev_interface_(NULL), | 17 ld_subprocess_active_(false), |
18 done_(false), | 18 done_(false), |
19 manifest_(NULL), | 19 manifest_(NULL), |
20 ld_manifest_(NULL), | 20 ld_manifest_(NULL), |
21 obj_file_(NULL), | 21 obj_file_(NULL), |
22 nexe_file_(NULL), | 22 nexe_file_(NULL), |
23 coordinator_error_info_(NULL), | 23 coordinator_error_info_(NULL), |
24 resources_(NULL), | 24 resources_(NULL), |
25 plugin_(NULL) { | 25 plugin_(NULL) { |
26 NaClXMutexCtor(&subprocess_mu_); | 26 NaClXMutexCtor(&subprocess_mu_); |
27 NaClXMutexCtor(&cond_mu_); | 27 NaClXMutexCtor(&cond_mu_); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 } | 115 } |
116 | 116 |
117 void WINAPI PnaclTranslateThread::DoTranslateThread(void* arg) { | 117 void WINAPI PnaclTranslateThread::DoTranslateThread(void* arg) { |
118 PnaclTranslateThread* translator = | 118 PnaclTranslateThread* translator = |
119 reinterpret_cast<PnaclTranslateThread*>(arg); | 119 reinterpret_cast<PnaclTranslateThread*>(arg); |
120 translator->DoTranslate(); | 120 translator->DoTranslate(); |
121 } | 121 } |
122 | 122 |
123 void PnaclTranslateThread::DoTranslate() { | 123 void PnaclTranslateThread::DoTranslate() { |
124 ErrorInfo error_info; | 124 ErrorInfo error_info; |
125 nacl::scoped_ptr<NaClSubprocess> llc_subprocess( | |
126 StartSubprocess(PnaclUrls::GetLlcUrl(), manifest_, &error_info)); | |
127 if (llc_subprocess == NULL) { | |
128 TranslateFailed("Compile process could not be created: " + | |
129 error_info.message()); | |
130 return; | |
131 } | |
132 // Run LLC. | |
133 SrpcParams params; | 125 SrpcParams params; |
134 nacl::DescWrapper* llc_out_file = obj_file_->get_wrapper(); | 126 nacl::DescWrapper* llc_out_file = obj_file_->get_wrapper(); |
135 PluginReverseInterface* llc_reverse = | |
136 llc_subprocess->service_runtime()->rev_interface(); | |
137 llc_reverse->AddTempQuotaManagedFile(obj_file_->identifier()); | |
138 RegisterReverseInterface(llc_reverse); | |
139 | 127 |
140 if (!llc_subprocess->InvokeSrpcMethod("StreamInit", | 128 { |
141 "h", | 129 nacl::MutexLocker ml(&subprocess_mu_); |
142 ¶ms, | 130 llc_subprocess_.reset( |
143 llc_out_file->desc())) { | 131 StartSubprocess(PnaclUrls::GetLlcUrl(), manifest_, &error_info)); |
144 // StreamInit returns an error message if the RPC fails. | 132 if (llc_subprocess_ == NULL) { |
145 TranslateFailed(nacl::string("Stream init failed: ") + | 133 TranslateFailed("Compile process could not be created: " + |
146 nacl::string(params.outs()[0]->arrays.str)); | 134 error_info.message()); |
| 135 return; |
| 136 } |
| 137 llc_subprocess_active_ = true; |
| 138 // Run LLC. |
| 139 PluginReverseInterface* llc_reverse = |
| 140 llc_subprocess_->service_runtime()->rev_interface(); |
| 141 llc_reverse->AddTempQuotaManagedFile(obj_file_->identifier()); |
| 142 } |
| 143 |
| 144 if (!llc_subprocess_->InvokeSrpcMethod("StreamInit", |
| 145 "h", |
| 146 ¶ms, |
| 147 llc_out_file->desc())) { |
| 148 if (llc_subprocess_->srpc_client()->GetLastError() == |
| 149 NACL_SRPC_RESULT_APP_ERROR) { |
| 150 // The error message is only present if the error was returned from llc |
| 151 TranslateFailed(nacl::string("Stream init failed: ") + |
| 152 nacl::string(params.outs()[0]->arrays.str)); |
| 153 } else { |
| 154 TranslateFailed("Stream init internal error"); |
| 155 } |
147 return; | 156 return; |
148 } | 157 } |
149 | 158 |
150 PLUGIN_PRINTF(("PnaclCoordinator: StreamInit successful\n")); | 159 PLUGIN_PRINTF(("PnaclCoordinator: StreamInit successful\n")); |
151 | 160 |
152 // llc process is started. | 161 // llc process is started. |
153 while(!done_ || data_buffers_.size() > 0) { | 162 while(!done_ || data_buffers_.size() > 0) { |
154 NaClXMutexLock(&cond_mu_); | 163 NaClXMutexLock(&cond_mu_); |
155 while(!done_ && data_buffers_.size() == 0) { | 164 while(!done_ && data_buffers_.size() == 0) { |
156 NaClXCondVarWait(&buffer_cond_, &cond_mu_); | 165 NaClXCondVarWait(&buffer_cond_, &cond_mu_); |
157 } | 166 } |
158 PLUGIN_PRINTF(("PnaclTranslateThread awake, done %d, size %d\n", | 167 PLUGIN_PRINTF(("PnaclTranslateThread awake, done %d, size %d\n", |
159 done_, data_buffers_.size())); | 168 done_, data_buffers_.size())); |
160 if (data_buffers_.size() > 0) { | 169 if (data_buffers_.size() > 0) { |
161 std::vector<char> data; | 170 std::vector<char> data; |
162 data.swap(data_buffers_.front()); | 171 data.swap(data_buffers_.front()); |
163 data_buffers_.pop_front(); | 172 data_buffers_.pop_front(); |
164 NaClXMutexUnlock(&cond_mu_); | 173 NaClXMutexUnlock(&cond_mu_); |
165 PLUGIN_PRINTF(("StreamChunk\n")); | 174 PLUGIN_PRINTF(("StreamChunk\n")); |
166 if (!llc_subprocess->InvokeSrpcMethod("StreamChunk", | 175 if (!llc_subprocess_->InvokeSrpcMethod("StreamChunk", |
167 "C", | 176 "C", |
168 ¶ms, | 177 ¶ms, |
169 &data[0], | 178 &data[0], |
170 data.size())) { | 179 data.size())) { |
171 TranslateFailed("Compile stream chunk failed."); | 180 TranslateFailed("Compile stream chunk failed."); |
172 return; | 181 return; |
173 } | 182 } |
174 PLUGIN_PRINTF(("StreamChunk Successful\n")); | 183 PLUGIN_PRINTF(("StreamChunk Successful\n")); |
175 } else { | 184 } else { |
176 NaClXMutexUnlock(&cond_mu_); | 185 NaClXMutexUnlock(&cond_mu_); |
177 } | 186 } |
178 if (SubprocessesShouldDie()) { | |
179 TranslateFailed("Stopped by coordinator."); | |
180 return; | |
181 } | |
182 } | 187 } |
183 PLUGIN_PRINTF(("PnaclTranslateThread done with chunks\n")); | 188 PLUGIN_PRINTF(("PnaclTranslateThread done with chunks\n")); |
184 // Finish llc. | 189 // Finish llc. |
185 if(!llc_subprocess->InvokeSrpcMethod("StreamEnd", | 190 if(!llc_subprocess_->InvokeSrpcMethod("StreamEnd", |
186 "", | 191 "", |
187 ¶ms)) { | 192 ¶ms)) { |
188 PLUGIN_PRINTF(("PnaclTranslateThread StreamEnd failed\n")); | 193 PLUGIN_PRINTF(("PnaclTranslateThread StreamEnd failed\n")); |
189 TranslateFailed(params.outs()[3]->arrays.str); | 194 if (llc_subprocess_->srpc_client()->GetLastError() == |
| 195 NACL_SRPC_RESULT_APP_ERROR) { |
| 196 // The error string is only present if the error was sent back from llc |
| 197 TranslateFailed(params.outs()[3]->arrays.str); |
| 198 } else { |
| 199 TranslateFailed("Compile StreamEnd internal error"); |
| 200 } |
190 return; | 201 return; |
191 } | 202 } |
192 // LLC returns values that are used to determine how linking is done. | 203 // LLC returns values that are used to determine how linking is done. |
193 int is_shared_library = (params.outs()[0]->u.ival != 0); | 204 int is_shared_library = (params.outs()[0]->u.ival != 0); |
194 nacl::string soname = params.outs()[1]->arrays.str; | 205 nacl::string soname = params.outs()[1]->arrays.str; |
195 nacl::string lib_dependencies = params.outs()[2]->arrays.str; | 206 nacl::string lib_dependencies = params.outs()[2]->arrays.str; |
196 PLUGIN_PRINTF(("PnaclCoordinator: compile (translator=%p) succeeded" | 207 PLUGIN_PRINTF(("PnaclCoordinator: compile (translator=%p) succeeded" |
197 " is_shared_library=%d, soname='%s', lib_dependencies='%s')\n", | 208 " is_shared_library=%d, soname='%s', lib_dependencies='%s')\n", |
198 this, is_shared_library, soname.c_str(), | 209 this, is_shared_library, soname.c_str(), |
199 lib_dependencies.c_str())); | 210 lib_dependencies.c_str())); |
200 | 211 |
201 // Shut down the llc subprocess. | 212 // Shut down the llc subprocess. |
202 RegisterReverseInterface(NULL); | 213 NaClXMutexLock(&subprocess_mu_); |
203 llc_subprocess.reset(NULL); | 214 llc_subprocess_active_ = false; |
204 if (SubprocessesShouldDie()) { | 215 llc_subprocess_.reset(NULL); |
205 TranslateFailed("stopped by coordinator."); | 216 NaClXMutexUnlock(&subprocess_mu_); |
206 return; | |
207 } | |
208 | 217 |
209 if(!RunLdSubprocess(is_shared_library, soname, lib_dependencies)) { | 218 if(!RunLdSubprocess(is_shared_library, soname, lib_dependencies)) { |
210 return; | 219 return; |
211 } | 220 } |
212 pp::Core* core = pp::Module::Get()->core(); | 221 pp::Core* core = pp::Module::Get()->core(); |
213 core->CallOnMainThread(0, report_translate_finished_, PP_OK); | 222 core->CallOnMainThread(0, report_translate_finished_, PP_OK); |
214 } | 223 } |
215 | 224 |
216 bool PnaclTranslateThread::RunLdSubprocess(int is_shared_library, | 225 bool PnaclTranslateThread::RunLdSubprocess(int is_shared_library, |
217 const nacl::string& soname, | 226 const nacl::string& soname, |
218 const nacl::string& lib_dependencies | 227 const nacl::string& lib_dependencies |
219 ) { | 228 ) { |
220 ErrorInfo error_info; | 229 ErrorInfo error_info; |
221 nacl::scoped_ptr<NaClSubprocess> ld_subprocess( | |
222 StartSubprocess(PnaclUrls::GetLdUrl(), ld_manifest_, &error_info)); | |
223 if (ld_subprocess == NULL) { | |
224 TranslateFailed("Link process could not be created: " + | |
225 error_info.message()); | |
226 return false; | |
227 } | |
228 // Run LD. | |
229 SrpcParams params; | 230 SrpcParams params; |
230 | |
231 // Reset object file for reading first. | 231 // Reset object file for reading first. |
232 if (!obj_file_->Reset()) { | 232 if (!obj_file_->Reset()) { |
233 TranslateFailed("Link process could not reset object file"); | 233 TranslateFailed("Link process could not reset object file"); |
234 return false; | 234 return false; |
235 } | 235 } |
236 nacl::DescWrapper* ld_in_file = obj_file_->get_wrapper(); | 236 nacl::DescWrapper* ld_in_file = obj_file_->get_wrapper(); |
237 nacl::DescWrapper* ld_out_file = nexe_file_->write_wrapper(); | 237 nacl::DescWrapper* ld_out_file = nexe_file_->write_wrapper(); |
238 PluginReverseInterface* ld_reverse = | 238 |
239 ld_subprocess->service_runtime()->rev_interface(); | 239 { |
240 ld_reverse->AddQuotaManagedFile(nexe_file_->identifier(), | 240 // Create LD process |
241 nexe_file_->write_file_io()); | 241 nacl::MutexLocker ml(&subprocess_mu_); |
242 RegisterReverseInterface(ld_reverse); | 242 ld_subprocess_.reset( |
243 if (!ld_subprocess->InvokeSrpcMethod("RunWithDefaultCommandLine", | 243 StartSubprocess(PnaclUrls::GetLdUrl(), ld_manifest_, &error_info)); |
| 244 if (ld_subprocess_ == NULL) { |
| 245 TranslateFailed("Link process could not be created: " + |
| 246 error_info.message()); |
| 247 return false; |
| 248 } |
| 249 ld_subprocess_active_ = true; |
| 250 PluginReverseInterface* ld_reverse = |
| 251 ld_subprocess_->service_runtime()->rev_interface(); |
| 252 ld_reverse->AddQuotaManagedFile(nexe_file_->identifier(), |
| 253 nexe_file_->write_file_io()); |
| 254 } |
| 255 // Run LD. |
| 256 if (!ld_subprocess_->InvokeSrpcMethod("RunWithDefaultCommandLine", |
244 "hhiss", | 257 "hhiss", |
245 ¶ms, | 258 ¶ms, |
246 ld_in_file->desc(), | 259 ld_in_file->desc(), |
247 ld_out_file->desc(), | 260 ld_out_file->desc(), |
248 is_shared_library, | 261 is_shared_library, |
249 soname.c_str(), | 262 soname.c_str(), |
250 lib_dependencies.c_str())) { | 263 lib_dependencies.c_str())) { |
251 TranslateFailed("link failed."); | 264 TranslateFailed("link failed."); |
252 return false; | 265 return false; |
253 } | 266 } |
254 PLUGIN_PRINTF(("PnaclCoordinator: link (translator=%p) succeeded\n", | 267 PLUGIN_PRINTF(("PnaclCoordinator: link (translator=%p) succeeded\n", |
255 this)); | 268 this)); |
256 // Shut down the ld subprocess. | 269 // Shut down the ld subprocess. |
257 RegisterReverseInterface(NULL); | 270 NaClXMutexLock(&subprocess_mu_); |
258 ld_subprocess.reset(NULL); | 271 ld_subprocess_active_ = false; |
259 if (SubprocessesShouldDie()) { | 272 ld_subprocess_.reset(NULL); |
260 TranslateFailed("stopped by coordinator."); | 273 NaClXMutexUnlock(&subprocess_mu_); |
261 return false; | |
262 } | |
263 return true; | 274 return true; |
264 } | 275 } |
265 | 276 |
266 void PnaclTranslateThread::TranslateFailed(const nacl::string& error_string) { | 277 void PnaclTranslateThread::TranslateFailed(const nacl::string& error_string) { |
267 PLUGIN_PRINTF(("PnaclTranslateThread::TranslateFailed (error_string='%s')\n", | 278 PLUGIN_PRINTF(("PnaclTranslateThread::TranslateFailed (error_string='%s')\n", |
268 error_string.c_str())); | 279 error_string.c_str())); |
269 pp::Core* core = pp::Module::Get()->core(); | 280 pp::Core* core = pp::Module::Get()->core(); |
270 if (coordinator_error_info_->message().empty()) { | 281 if (coordinator_error_info_->message().empty()) { |
271 // Only use our message if one hasn't already been set by the coordinator | 282 // Only use our message if one hasn't already been set by the coordinator |
272 // (e.g. pexe load failed). | 283 // (e.g. pexe load failed). |
273 coordinator_error_info_->SetReport(ERROR_UNKNOWN, | 284 coordinator_error_info_->SetReport(ERROR_UNKNOWN, |
274 nacl::string("PnaclCoordinator: ") + | 285 nacl::string("PnaclCoordinator: ") + |
275 error_string); | 286 error_string); |
276 } | 287 } |
277 core->CallOnMainThread(0, report_translate_finished_, PP_ERROR_FAILED); | 288 core->CallOnMainThread(0, report_translate_finished_, PP_ERROR_FAILED); |
278 } | 289 } |
279 | 290 |
280 // This synchronization method (using the pointer directly in the | 291 void PnaclTranslateThread::AbortSubprocesses() { |
281 // translation thread, setting a copy here, and calling shutdown on the | 292 PLUGIN_PRINTF(("PnaclTranslateThread::AbortSubprocesses\n")); |
282 // main thread) is safe only because only the translation thread sets | |
283 // the copy, and the shutdown method is thread-safe. This method must be | |
284 // called on the translation thread before any RPCs are called, and called | |
285 // again with NULL before the object is destroyed. | |
286 void PnaclTranslateThread::RegisterReverseInterface( | |
287 PluginReverseInterface *iface) { | |
288 nacl::MutexLocker ml(&subprocess_mu_); | |
289 current_rev_interface_ = iface; | |
290 } | |
291 | |
292 | |
293 bool PnaclTranslateThread::SubprocessesShouldDie() { | |
294 nacl::MutexLocker ml(&subprocess_mu_); | |
295 return subprocesses_should_die_; | |
296 } | |
297 | |
298 void PnaclTranslateThread::SetSubprocessesShouldDie() { | |
299 PLUGIN_PRINTF(("PnaclTranslateThread::SetSubprocessesShouldDie\n")); | |
300 NaClXMutexLock(&subprocess_mu_); | 293 NaClXMutexLock(&subprocess_mu_); |
301 subprocesses_should_die_ = true; | 294 if (llc_subprocess_ != NULL && llc_subprocess_active_) { |
302 if (current_rev_interface_) { | 295 llc_subprocess_->service_runtime()->Shutdown(); |
303 current_rev_interface_->ShutDown(); | 296 llc_subprocess_active_ = false; |
304 current_rev_interface_ = NULL; | 297 } |
| 298 if (ld_subprocess_ != NULL && ld_subprocess_active_) { |
| 299 ld_subprocess_->service_runtime()->Shutdown(); |
| 300 ld_subprocess_active_ = false; |
305 } | 301 } |
306 NaClXMutexUnlock(&subprocess_mu_); | 302 NaClXMutexUnlock(&subprocess_mu_); |
307 nacl::MutexLocker ml(&cond_mu_); | 303 nacl::MutexLocker ml(&cond_mu_); |
308 done_ = true; | 304 done_ = true; |
| 305 // Free all buffered bitcode chunks |
| 306 data_buffers_.clear(); |
309 NaClXCondVarSignal(&buffer_cond_); | 307 NaClXCondVarSignal(&buffer_cond_); |
310 } | 308 } |
311 | 309 |
312 PnaclTranslateThread::~PnaclTranslateThread() { | 310 PnaclTranslateThread::~PnaclTranslateThread() { |
313 PLUGIN_PRINTF(("~PnaclTranslateThread (translate_thread=%p)\n", this)); | 311 PLUGIN_PRINTF(("~PnaclTranslateThread (translate_thread=%p)\n", this)); |
314 SetSubprocessesShouldDie(); | 312 AbortSubprocesses(); |
315 NaClThreadJoin(translate_thread_.get()); | 313 NaClThreadJoin(translate_thread_.get()); |
316 PLUGIN_PRINTF(("~PnaclTranslateThread joined\n")); | 314 PLUGIN_PRINTF(("~PnaclTranslateThread joined\n")); |
| 315 NaClCondVarDtor(&buffer_cond_); |
| 316 NaClMutexDtor(&cond_mu_); |
317 NaClMutexDtor(&subprocess_mu_); | 317 NaClMutexDtor(&subprocess_mu_); |
318 } | 318 } |
319 | 319 |
320 } // namespace plugin | 320 } // namespace plugin |
OLD | NEW |