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 "components/nacl/renderer/plugin/pnacl_translate_thread.h" | 5 #include "components/nacl/renderer/plugin/pnacl_translate_thread.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <iterator> | 9 #include <iterator> |
10 #include <sstream> | 10 #include <sstream> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "components/nacl/renderer/plugin/plugin.h" | 13 #include "components/nacl/renderer/plugin/plugin.h" |
14 #include "components/nacl/renderer/plugin/plugin_error.h" | 14 #include "components/nacl/renderer/plugin/plugin_error.h" |
15 #include "components/nacl/renderer/plugin/srpc_params.h" | 15 #include "components/nacl/renderer/plugin/srpc_params.h" |
16 #include "components/nacl/renderer/plugin/temporary_file.h" | 16 #include "components/nacl/renderer/plugin/temporary_file.h" |
17 #include "components/nacl/renderer/plugin/utility.h" | 17 #include "components/nacl/renderer/plugin/utility.h" |
| 18 #include "content/public/common/sandbox_init.h" |
18 #include "native_client/src/shared/platform/nacl_sync_raii.h" | 19 #include "native_client/src/shared/platform/nacl_sync_raii.h" |
19 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" | 20 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" |
| 21 #include "ppapi/c/ppb_file_io.h" |
20 #include "ppapi/cpp/var.h" | 22 #include "ppapi/cpp/var.h" |
| 23 #include "ppapi/proxy/ppapi_messages.h" |
21 | 24 |
22 namespace plugin { | 25 namespace plugin { |
23 namespace { | 26 namespace { |
24 | 27 |
25 template <typename Val> | 28 template <typename Val> |
26 std::string MakeCommandLineArg(const char* key, const Val val) { | 29 std::string MakeCommandLineArg(const char* key, const Val val) { |
27 std::stringstream ss; | 30 std::stringstream ss; |
28 ss << key << val; | 31 ss << key << val; |
29 return ss.str(); | 32 return ss.str(); |
30 } | 33 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 : compiler_subprocess_(NULL), | 82 : compiler_subprocess_(NULL), |
80 ld_subprocess_(NULL), | 83 ld_subprocess_(NULL), |
81 compiler_subprocess_active_(false), | 84 compiler_subprocess_active_(false), |
82 ld_subprocess_active_(false), | 85 ld_subprocess_active_(false), |
83 done_(false), | 86 done_(false), |
84 compile_time_(0), | 87 compile_time_(0), |
85 obj_files_(NULL), | 88 obj_files_(NULL), |
86 num_threads_(0), | 89 num_threads_(0), |
87 nexe_file_(NULL), | 90 nexe_file_(NULL), |
88 coordinator_error_info_(NULL), | 91 coordinator_error_info_(NULL), |
89 coordinator_(NULL) { | 92 coordinator_(NULL), |
| 93 ld_channel_peer_pid_(base::kNullProcessId) { |
90 NaClXMutexCtor(&subprocess_mu_); | 94 NaClXMutexCtor(&subprocess_mu_); |
91 NaClXMutexCtor(&cond_mu_); | 95 NaClXMutexCtor(&cond_mu_); |
92 NaClXCondVarCtor(&buffer_cond_); | 96 NaClXCondVarCtor(&buffer_cond_); |
93 } | 97 } |
94 | 98 |
95 void PnaclTranslateThread::SetupState( | 99 void PnaclTranslateThread::SetupState( |
96 const pp::CompletionCallback& finish_callback, | 100 const pp::CompletionCallback& finish_callback, |
97 NaClSubprocess* compiler_subprocess, | 101 NaClSubprocess* compiler_subprocess, |
98 NaClSubprocess* ld_subprocess, | 102 NaClSubprocess* ld_subprocess, |
99 const std::vector<TempFile*>* obj_files, | 103 const std::vector<TempFile*>* obj_files, |
(...skipping 19 matching lines...) Expand all Loading... |
119 report_translate_finished_ = finish_callback; | 123 report_translate_finished_ = finish_callback; |
120 } | 124 } |
121 | 125 |
122 void PnaclTranslateThread::RunCompile( | 126 void PnaclTranslateThread::RunCompile( |
123 const pp::CompletionCallback& compile_finished_callback) { | 127 const pp::CompletionCallback& compile_finished_callback) { |
124 PLUGIN_PRINTF(("PnaclTranslateThread::RunCompile)\n")); | 128 PLUGIN_PRINTF(("PnaclTranslateThread::RunCompile)\n")); |
125 DCHECK(started()); | 129 DCHECK(started()); |
126 DCHECK(compiler_subprocess_->service_runtime()); | 130 DCHECK(compiler_subprocess_->service_runtime()); |
127 compiler_subprocess_active_ = true; | 131 compiler_subprocess_active_ = true; |
128 | 132 |
| 133 // Free this IPC channel now to make sure that it does not get freed on |
| 134 // the child thread when the child thread calls Shutdown(). |
| 135 // TODO(mseaborn): Convert DoCompile() to using Chrome IPC instead of SRPC, |
| 136 // the same way DoLink() has been converted. Then we will use this IPC |
| 137 // channel instead of just freeing it here. |
| 138 compiler_subprocess_->service_runtime()->TakeTranslatorChannel(); |
| 139 |
129 compile_finished_callback_ = compile_finished_callback; | 140 compile_finished_callback_ = compile_finished_callback; |
130 translate_thread_.reset(new NaClThread); | 141 translate_thread_.reset(new NaClThread); |
131 if (translate_thread_ == NULL) { | 142 if (translate_thread_ == NULL) { |
132 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE, | 143 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE, |
133 "could not allocate thread struct."); | 144 "could not allocate thread struct."); |
134 return; | 145 return; |
135 } | 146 } |
136 const int32_t kArbitraryStackSize = 128 * 1024; | 147 const int32_t kArbitraryStackSize = 128 * 1024; |
137 if (!NaClThreadCreateJoinable(translate_thread_.get(), DoCompileThread, this, | 148 if (!NaClThreadCreateJoinable(translate_thread_.get(), DoCompileThread, this, |
138 kArbitraryStackSize)) { | 149 kArbitraryStackSize)) { |
139 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE, | 150 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE, |
140 "could not create thread."); | 151 "could not create thread."); |
141 translate_thread_.reset(NULL); | 152 translate_thread_.reset(NULL); |
142 } | 153 } |
143 } | 154 } |
144 | 155 |
145 void PnaclTranslateThread::RunLink() { | 156 void PnaclTranslateThread::RunLink() { |
146 PLUGIN_PRINTF(("PnaclTranslateThread::RunLink)\n")); | 157 PLUGIN_PRINTF(("PnaclTranslateThread::RunLink)\n")); |
147 DCHECK(started()); | 158 DCHECK(started()); |
148 DCHECK(ld_subprocess_->service_runtime()); | 159 DCHECK(ld_subprocess_->service_runtime()); |
149 ld_subprocess_active_ = true; | 160 ld_subprocess_active_ = true; |
150 | 161 |
| 162 // Take ownership of this IPC channel to make sure that it does not get |
| 163 // freed on the child thread when the child thread calls Shutdown(). |
| 164 ld_channel_ = ld_subprocess_->service_runtime()->TakeTranslatorChannel(); |
| 165 // ld_channel_ is a IPC::SyncChannel, which is not thread-safe and cannot be |
| 166 // used directly by the child thread, so create a SyncMessageFilter which |
| 167 // can be used by the child thread. |
| 168 ld_channel_filter_ = ld_channel_->CreateSyncMessageFilter(); |
| 169 // Make a copy of the process ID, again to avoid any thread-safety issues |
| 170 // involved in accessing ld_subprocess_ on the child thread. |
| 171 ld_channel_peer_pid_ = ld_subprocess_->service_runtime()->get_process_id(); |
| 172 |
151 // Tear down the previous thread. | 173 // Tear down the previous thread. |
152 // TODO(jvoung): Use base/threading or something where we can have a | 174 // TODO(jvoung): Use base/threading or something where we can have a |
153 // persistent thread and easily post tasks to that persistent thread. | 175 // persistent thread and easily post tasks to that persistent thread. |
154 NaClThreadJoin(translate_thread_.get()); | 176 NaClThreadJoin(translate_thread_.get()); |
155 translate_thread_.reset(new NaClThread); | 177 translate_thread_.reset(new NaClThread); |
156 if (translate_thread_ == NULL) { | 178 if (translate_thread_ == NULL) { |
157 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE, | 179 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE, |
158 "could not allocate thread struct."); | 180 "could not allocate thread struct."); |
159 return; | 181 return; |
160 } | 182 } |
(...skipping 18 matching lines...) Expand all Loading... |
179 NaClXMutexUnlock(&cond_mu_); | 201 NaClXMutexUnlock(&cond_mu_); |
180 } | 202 } |
181 | 203 |
182 void PnaclTranslateThread::EndStream() { | 204 void PnaclTranslateThread::EndStream() { |
183 NaClXMutexLock(&cond_mu_); | 205 NaClXMutexLock(&cond_mu_); |
184 done_ = true; | 206 done_ = true; |
185 NaClXCondVarSignal(&buffer_cond_); | 207 NaClXCondVarSignal(&buffer_cond_); |
186 NaClXMutexUnlock(&cond_mu_); | 208 NaClXMutexUnlock(&cond_mu_); |
187 } | 209 } |
188 | 210 |
| 211 ppapi::proxy::SerializedHandle PnaclTranslateThread::GetHandleForSubprocess( |
| 212 TempFile* file, int32_t open_flags) { |
| 213 IPC::PlatformFileForTransit file_for_transit; |
| 214 |
| 215 #if defined(OS_WIN) |
| 216 if (!content::BrokerDuplicateHandle( |
| 217 file->GetFileHandle(), |
| 218 ld_channel_peer_pid_, |
| 219 &file_for_transit, |
| 220 0, // desired_access is 0 since we're using DUPLICATE_SAME_ACCESS. |
| 221 DUPLICATE_SAME_ACCESS)) { |
| 222 return ppapi::proxy::SerializedHandle(); |
| 223 } |
| 224 #else |
| 225 file_for_transit = base::FileDescriptor(dup(file->GetFileHandle()), true); |
| 226 #endif |
| 227 |
| 228 // Using 0 disables any use of quota enforcement for this file handle. |
| 229 PP_Resource file_io = 0; |
| 230 |
| 231 ppapi::proxy::SerializedHandle handle; |
| 232 handle.set_file_handle(file_for_transit, open_flags, file_io); |
| 233 return handle; |
| 234 } |
| 235 |
189 void WINAPI PnaclTranslateThread::DoCompileThread(void* arg) { | 236 void WINAPI PnaclTranslateThread::DoCompileThread(void* arg) { |
190 PnaclTranslateThread* translator = | 237 PnaclTranslateThread* translator = |
191 reinterpret_cast<PnaclTranslateThread*>(arg); | 238 reinterpret_cast<PnaclTranslateThread*>(arg); |
192 translator->DoCompile(); | 239 translator->DoCompile(); |
193 } | 240 } |
194 | 241 |
195 void PnaclTranslateThread::DoCompile() { | 242 void PnaclTranslateThread::DoCompile() { |
196 { | 243 { |
197 nacl::MutexLocker ml(&subprocess_mu_); | 244 nacl::MutexLocker ml(&subprocess_mu_); |
198 // If the main thread asked us to exit in between starting the thread | 245 // If the main thread asked us to exit in between starting the thread |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 translator->DoLink(); | 388 translator->DoLink(); |
342 } | 389 } |
343 | 390 |
344 void PnaclTranslateThread::DoLink() { | 391 void PnaclTranslateThread::DoLink() { |
345 { | 392 { |
346 nacl::MutexLocker ml(&subprocess_mu_); | 393 nacl::MutexLocker ml(&subprocess_mu_); |
347 // If the main thread asked us to exit in between starting the thread | 394 // If the main thread asked us to exit in between starting the thread |
348 // and now, just leave now. | 395 // and now, just leave now. |
349 if (!ld_subprocess_active_) | 396 if (!ld_subprocess_active_) |
350 return; | 397 return; |
351 // Now that we are in helper thread, we can do the the blocking | 398 } |
352 // StartSrpcServices operation. | 399 |
353 if (!ld_subprocess_->StartSrpcServices()) { | 400 // Reset object files for reading first. We do this before duplicating |
354 TranslateFailed( | 401 // handles/FDs to prevent any handle/FD leaks in case any of the Reset() |
355 PP_NACL_ERROR_SRPC_CONNECTION_FAIL, | 402 // calls fail. |
356 "SRPC connection failure for " + ld_subprocess_->description()); | 403 for (TempFile* obj_file : *obj_files_) { |
| 404 if (!obj_file->Reset()) { |
| 405 TranslateFailed(PP_NACL_ERROR_PNACL_LD_SETUP, |
| 406 "Link process could not reset object file"); |
357 return; | 407 return; |
358 } | 408 } |
359 } | 409 } |
360 | 410 |
361 SrpcParams params; | 411 ppapi::proxy::SerializedHandle nexe_file = |
362 std::vector<nacl::DescWrapper*> ld_in_files; | 412 GetHandleForSubprocess(nexe_file_, PP_FILEOPENFLAG_WRITE); |
363 size_t i; | 413 std::vector<ppapi::proxy::SerializedHandle> ld_input_files; |
364 for (i = 0; i < obj_files_->size(); i++) { | 414 for (TempFile* obj_file : *obj_files_) { |
365 // Reset object file for reading first. | 415 ld_input_files.push_back( |
366 if (!(*obj_files_)[i]->Reset()) { | 416 GetHandleForSubprocess(obj_file, PP_FILEOPENFLAG_READ)); |
367 TranslateFailed(PP_NACL_ERROR_PNACL_LD_SETUP, | |
368 "Link process could not reset object file"); | |
369 } | |
370 ld_in_files.push_back((*obj_files_)[i]->read_wrapper()); | |
371 } | 417 } |
372 for (; i < PnaclCoordinator::kMaxTranslatorObjectFiles; i++) | |
373 ld_in_files.push_back(invalid_desc_wrapper_); | |
374 | 418 |
375 nacl::DescWrapper* ld_out_file = nexe_file_->write_wrapper(); | |
376 int64_t link_start_time = NaClGetTimeOfDayMicroseconds(); | 419 int64_t link_start_time = NaClGetTimeOfDayMicroseconds(); |
377 // Run LD. | 420 bool success = false; |
378 bool success = ld_subprocess_->InvokeSrpcMethod( | 421 bool sent = ld_channel_filter_->Send( |
379 "RunWithSplit", | 422 new PpapiMsg_PnaclTranslatorLink(ld_input_files, nexe_file, &success)); |
380 "ihhhhhhhhhhhhhhhhh", | 423 if (!sent) { |
381 ¶ms, | 424 TranslateFailed(PP_NACL_ERROR_PNACL_LD_INTERNAL, |
382 static_cast<int>(obj_files_->size()), | 425 "link failed: reply not received from linker."); |
383 ld_in_files[0]->desc(), | 426 return; |
384 ld_in_files[1]->desc(), | 427 } |
385 ld_in_files[2]->desc(), | |
386 ld_in_files[3]->desc(), | |
387 ld_in_files[4]->desc(), | |
388 ld_in_files[5]->desc(), | |
389 ld_in_files[6]->desc(), | |
390 ld_in_files[7]->desc(), | |
391 ld_in_files[8]->desc(), | |
392 ld_in_files[9]->desc(), | |
393 ld_in_files[10]->desc(), | |
394 ld_in_files[11]->desc(), | |
395 ld_in_files[12]->desc(), | |
396 ld_in_files[13]->desc(), | |
397 ld_in_files[14]->desc(), | |
398 ld_in_files[15]->desc(), | |
399 ld_out_file->desc()); | |
400 if (!success) { | 428 if (!success) { |
401 TranslateFailed(PP_NACL_ERROR_PNACL_LD_INTERNAL, | 429 TranslateFailed(PP_NACL_ERROR_PNACL_LD_INTERNAL, |
402 "link failed."); | 430 "link failed: linker returned failure status."); |
403 return; | 431 return; |
404 } | 432 } |
| 433 |
405 GetNaClInterface()->LogTranslateTime( | 434 GetNaClInterface()->LogTranslateTime( |
406 "NaCl.Perf.PNaClLoadTime.LinkTime", | 435 "NaCl.Perf.PNaClLoadTime.LinkTime", |
407 NaClGetTimeOfDayMicroseconds() - link_start_time); | 436 NaClGetTimeOfDayMicroseconds() - link_start_time); |
408 PLUGIN_PRINTF(("PnaclCoordinator: link (translator=%p) succeeded\n", | 437 PLUGIN_PRINTF(("PnaclCoordinator: link (translator=%p) succeeded\n", |
409 this)); | 438 this)); |
410 | 439 |
411 // Shut down the ld subprocess. | 440 // Shut down the ld subprocess. |
412 NaClXMutexLock(&subprocess_mu_); | 441 NaClXMutexLock(&subprocess_mu_); |
413 ld_subprocess_active_ = false; | 442 ld_subprocess_active_ = false; |
414 ld_subprocess_->Shutdown(); | 443 ld_subprocess_->Shutdown(); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 AbortSubprocesses(); | 490 AbortSubprocesses(); |
462 if (translate_thread_ != NULL) | 491 if (translate_thread_ != NULL) |
463 NaClThreadJoin(translate_thread_.get()); | 492 NaClThreadJoin(translate_thread_.get()); |
464 PLUGIN_PRINTF(("~PnaclTranslateThread joined\n")); | 493 PLUGIN_PRINTF(("~PnaclTranslateThread joined\n")); |
465 NaClCondVarDtor(&buffer_cond_); | 494 NaClCondVarDtor(&buffer_cond_); |
466 NaClMutexDtor(&cond_mu_); | 495 NaClMutexDtor(&cond_mu_); |
467 NaClMutexDtor(&subprocess_mu_); | 496 NaClMutexDtor(&subprocess_mu_); |
468 } | 497 } |
469 | 498 |
470 } // namespace plugin | 499 } // namespace plugin |
OLD | NEW |