Content settings: remove some plugin-related code/resources when... there are no...
[chromium-blink-merge.git] / components / nacl / renderer / plugin / pnacl_translate_thread.cc
blob6e4d45d7711ddfef633aea4b3b752170c1680fa8
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
3 // found in the LICENSE file.
5 #include "components/nacl/renderer/plugin/pnacl_translate_thread.h"
7 #include <iterator>
8 #include <sstream>
10 #include "components/nacl/renderer/plugin/plugin.h"
11 #include "components/nacl/renderer/plugin/plugin_error.h"
12 #include "components/nacl/renderer/plugin/srpc_params.h"
13 #include "components/nacl/renderer/plugin/temporary_file.h"
14 #include "components/nacl/renderer/plugin/utility.h"
15 #include "native_client/src/shared/platform/nacl_check.h"
16 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
17 #include "ppapi/cpp/var.h"
19 namespace plugin {
20 namespace {
22 template <typename Val>
23 std::string MakeCommandLineArg(const char* key, const Val val) {
24 std::stringstream ss;
25 ss << key << val;
26 return ss.str();
29 void GetLlcCommandLine(std::vector<char>* split_args,
30 size_t obj_files_size,
31 int32_t opt_level,
32 bool is_debug,
33 const std::string& architecture_attributes) {
34 typedef std::vector<std::string> Args;
35 Args args;
37 // TODO(dschuff): This CL override is ugly. Change llc to default to
38 // using the number of modules specified in the first param, and
39 // ignore multiple uses of -split-module
40 args.push_back(MakeCommandLineArg("-split-module=", obj_files_size));
41 args.push_back(MakeCommandLineArg("-O", opt_level));
42 if (is_debug)
43 args.push_back("-bitcode-format=llvm");
44 if (!architecture_attributes.empty())
45 args.push_back("-mattr=" + architecture_attributes);
47 for (const std::string& arg : args) {
48 std::copy(arg.begin(), arg.end(), std::back_inserter(*split_args));
49 split_args->push_back('\x00');
53 void GetSubzeroCommandLine(std::vector<char>* split_args,
54 int32_t opt_level,
55 bool is_debug,
56 const std::string& architecture_attributes) {
57 typedef std::vector<std::string> Args;
58 Args args;
60 args.push_back(MakeCommandLineArg("-O", opt_level));
61 DCHECK(!is_debug);
62 // TODO(stichnot): enable this once the mattr flag formatting is
63 // compatible: https://code.google.com/p/nativeclient/issues/detail?id=4132
64 // if (!architecture_attributes.empty())
65 // args.push_back("-mattr=" + architecture_attributes);
67 for (const std::string& arg : args) {
68 std::copy(arg.begin(), arg.end(), std::back_inserter(*split_args));
69 split_args->push_back('\x00');
73 } // namespace
75 PnaclTranslateThread::PnaclTranslateThread()
76 : compiler_subprocess_(NULL),
77 ld_subprocess_(NULL),
78 compiler_subprocess_active_(false),
79 ld_subprocess_active_(false),
80 done_(false),
81 compile_time_(0),
82 obj_files_(NULL),
83 num_threads_(0),
84 nexe_file_(NULL),
85 coordinator_error_info_(NULL),
86 coordinator_(NULL) {
87 NaClXMutexCtor(&subprocess_mu_);
88 NaClXMutexCtor(&cond_mu_);
89 NaClXCondVarCtor(&buffer_cond_);
92 void PnaclTranslateThread::SetupState(
93 const pp::CompletionCallback& finish_callback,
94 NaClSubprocess* compiler_subprocess,
95 NaClSubprocess* ld_subprocess,
96 const std::vector<TempFile*>* obj_files,
97 int num_threads,
98 TempFile* nexe_file,
99 nacl::DescWrapper* invalid_desc_wrapper,
100 ErrorInfo* error_info,
101 PP_PNaClOptions* pnacl_options,
102 const std::string& architecture_attributes,
103 PnaclCoordinator* coordinator) {
104 PLUGIN_PRINTF(("PnaclTranslateThread::SetupState)\n"));
105 compiler_subprocess_ = compiler_subprocess;
106 ld_subprocess_ = ld_subprocess;
107 obj_files_ = obj_files;
108 num_threads_ = num_threads;
109 nexe_file_ = nexe_file;
110 invalid_desc_wrapper_ = invalid_desc_wrapper;
111 coordinator_error_info_ = error_info;
112 pnacl_options_ = pnacl_options;
113 architecture_attributes_ = architecture_attributes;
114 coordinator_ = coordinator;
116 report_translate_finished_ = finish_callback;
119 void PnaclTranslateThread::RunCompile(
120 const pp::CompletionCallback& compile_finished_callback) {
121 PLUGIN_PRINTF(("PnaclTranslateThread::RunCompile)\n"));
122 DCHECK(started());
123 DCHECK(compiler_subprocess_->service_runtime());
124 compiler_subprocess_active_ = true;
126 compile_finished_callback_ = compile_finished_callback;
127 translate_thread_.reset(new NaClThread);
128 if (translate_thread_ == NULL) {
129 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE,
130 "could not allocate thread struct.");
131 return;
133 const int32_t kArbitraryStackSize = 128 * 1024;
134 if (!NaClThreadCreateJoinable(translate_thread_.get(), DoCompileThread, this,
135 kArbitraryStackSize)) {
136 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE,
137 "could not create thread.");
138 translate_thread_.reset(NULL);
142 void PnaclTranslateThread::RunLink() {
143 PLUGIN_PRINTF(("PnaclTranslateThread::RunLink)\n"));
144 DCHECK(started());
145 DCHECK(ld_subprocess_->service_runtime());
146 ld_subprocess_active_ = true;
148 // Tear down the previous thread.
149 // TODO(jvoung): Use base/threading or something where we can have a
150 // persistent thread and easily post tasks to that persistent thread.
151 NaClThreadJoin(translate_thread_.get());
152 translate_thread_.reset(new NaClThread);
153 if (translate_thread_ == NULL) {
154 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE,
155 "could not allocate thread struct.");
156 return;
158 const int32_t kArbitraryStackSize = 128 * 1024;
159 if (!NaClThreadCreateJoinable(translate_thread_.get(), DoLinkThread, this,
160 kArbitraryStackSize)) {
161 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE,
162 "could not create thread.");
163 translate_thread_.reset(NULL);
167 // Called from main thread to send bytes to the translator.
168 void PnaclTranslateThread::PutBytes(const void* bytes, int32_t count) {
169 CHECK(bytes != NULL);
170 NaClXMutexLock(&cond_mu_);
171 data_buffers_.push_back(std::vector<char>());
172 data_buffers_.back().insert(data_buffers_.back().end(),
173 static_cast<const char*>(bytes),
174 static_cast<const char*>(bytes) + count);
175 NaClXCondVarSignal(&buffer_cond_);
176 NaClXMutexUnlock(&cond_mu_);
179 void PnaclTranslateThread::EndStream() {
180 NaClXMutexLock(&cond_mu_);
181 done_ = true;
182 NaClXCondVarSignal(&buffer_cond_);
183 NaClXMutexUnlock(&cond_mu_);
186 void WINAPI PnaclTranslateThread::DoCompileThread(void* arg) {
187 PnaclTranslateThread* translator =
188 reinterpret_cast<PnaclTranslateThread*>(arg);
189 translator->DoCompile();
192 void PnaclTranslateThread::DoCompile() {
194 nacl::MutexLocker ml(&subprocess_mu_);
195 // If the main thread asked us to exit in between starting the thread
196 // and now, just leave now.
197 if (!compiler_subprocess_active_)
198 return;
199 // Now that we are in helper thread, we can do the the blocking
200 // StartSrpcServices operation.
201 if (!compiler_subprocess_->StartSrpcServices()) {
202 TranslateFailed(
203 PP_NACL_ERROR_SRPC_CONNECTION_FAIL,
204 "SRPC connection failure for " + compiler_subprocess_->description());
205 return;
209 SrpcParams params;
210 std::vector<nacl::DescWrapper*> compile_out_files;
211 size_t i;
212 for (i = 0; i < obj_files_->size(); i++)
213 compile_out_files.push_back((*obj_files_)[i]->write_wrapper());
214 for (; i < PnaclCoordinator::kMaxTranslatorObjectFiles; i++)
215 compile_out_files.push_back(invalid_desc_wrapper_);
217 PLUGIN_PRINTF(("DoCompile using subzero: %d\n", pnacl_options_->use_subzero));
219 pp::Core* core = pp::Module::Get()->core();
220 int64_t do_compile_start_time = NaClGetTimeOfDayMicroseconds();
221 bool init_success;
223 std::vector<char> split_args;
224 if (pnacl_options_->use_subzero) {
225 GetSubzeroCommandLine(&split_args, pnacl_options_->opt_level,
226 pnacl_options_->is_debug, architecture_attributes_);
227 } else {
228 GetLlcCommandLine(&split_args, obj_files_->size(),
229 pnacl_options_->opt_level, pnacl_options_->is_debug,
230 architecture_attributes_);
233 init_success = compiler_subprocess_->InvokeSrpcMethod(
234 "StreamInitWithSplit", "ihhhhhhhhhhhhhhhhC", &params, num_threads_,
235 compile_out_files[0]->desc(), compile_out_files[1]->desc(),
236 compile_out_files[2]->desc(), compile_out_files[3]->desc(),
237 compile_out_files[4]->desc(), compile_out_files[5]->desc(),
238 compile_out_files[6]->desc(), compile_out_files[7]->desc(),
239 compile_out_files[8]->desc(), compile_out_files[9]->desc(),
240 compile_out_files[10]->desc(), compile_out_files[11]->desc(),
241 compile_out_files[12]->desc(), compile_out_files[13]->desc(),
242 compile_out_files[14]->desc(), compile_out_files[15]->desc(),
243 &split_args[0], split_args.size());
244 if (!init_success) {
245 if (compiler_subprocess_->srpc_client()->GetLastError() ==
246 NACL_SRPC_RESULT_APP_ERROR) {
247 // The error message is only present if the error was returned from llc
248 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
249 std::string("Stream init failed: ") +
250 std::string(params.outs()[0]->arrays.str));
251 } else {
252 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
253 "Stream init internal error");
255 return;
257 PLUGIN_PRINTF(("PnaclCoordinator: StreamInit successful\n"));
259 // llc process is started.
260 while(!done_ || data_buffers_.size() > 0) {
261 NaClXMutexLock(&cond_mu_);
262 while(!done_ && data_buffers_.size() == 0) {
263 NaClXCondVarWait(&buffer_cond_, &cond_mu_);
265 PLUGIN_PRINTF(("PnaclTranslateThread awake (done=%d, size=%" NACL_PRIuS
266 ")\n",
267 done_, data_buffers_.size()));
268 if (data_buffers_.size() > 0) {
269 std::vector<char> data;
270 data.swap(data_buffers_.front());
271 data_buffers_.pop_front();
272 NaClXMutexUnlock(&cond_mu_);
273 PLUGIN_PRINTF(("StreamChunk\n"));
274 if (!compiler_subprocess_->InvokeSrpcMethod("StreamChunk", "C", &params,
275 &data[0], data.size())) {
276 if (compiler_subprocess_->srpc_client()->GetLastError() !=
277 NACL_SRPC_RESULT_APP_ERROR) {
278 // If the error was reported by the translator, then we fall through
279 // and call StreamEnd, which returns a string describing the error,
280 // which we can then send to the Javascript console. Otherwise just
281 // fail here, since the translator has probably crashed or asserted.
282 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
283 "Compile stream chunk failed. "
284 "The PNaCl translator has probably crashed.");
285 return;
287 break;
288 } else {
289 PLUGIN_PRINTF(("StreamChunk Successful\n"));
290 core->CallOnMainThread(
292 coordinator_->GetCompileProgressCallback(data.size()),
293 PP_OK);
295 } else {
296 NaClXMutexUnlock(&cond_mu_);
299 PLUGIN_PRINTF(("PnaclTranslateThread done with chunks\n"));
300 // Finish llc.
301 if (!compiler_subprocess_->InvokeSrpcMethod("StreamEnd", std::string(),
302 &params)) {
303 PLUGIN_PRINTF(("PnaclTranslateThread StreamEnd failed\n"));
304 if (compiler_subprocess_->srpc_client()->GetLastError() ==
305 NACL_SRPC_RESULT_APP_ERROR) {
306 // The error string is only present if the error was sent back from llc.
307 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
308 params.outs()[3]->arrays.str);
309 } else {
310 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
311 "Compile StreamEnd internal error");
313 return;
315 compile_time_ = NaClGetTimeOfDayMicroseconds() - do_compile_start_time;
316 GetNaClInterface()->LogTranslateTime("NaCl.Perf.PNaClLoadTime.CompileTime",
317 compile_time_);
318 GetNaClInterface()->LogTranslateTime(
319 pnacl_options_->use_subzero
320 ? "NaCl.Perf.PNaClLoadTime.CompileTime.Subzero"
321 : "NaCl.Perf.PNaClLoadTime.CompileTime.LLC",
322 compile_time_);
324 // Shut down the compiler subprocess.
325 NaClXMutexLock(&subprocess_mu_);
326 compiler_subprocess_active_ = false;
327 compiler_subprocess_->Shutdown();
328 NaClXMutexUnlock(&subprocess_mu_);
330 core->CallOnMainThread(0, compile_finished_callback_, PP_OK);
333 void WINAPI PnaclTranslateThread::DoLinkThread(void* arg) {
334 PnaclTranslateThread* translator =
335 reinterpret_cast<PnaclTranslateThread*>(arg);
336 translator->DoLink();
339 void PnaclTranslateThread::DoLink() {
341 nacl::MutexLocker ml(&subprocess_mu_);
342 // If the main thread asked us to exit in between starting the thread
343 // and now, just leave now.
344 if (!ld_subprocess_active_)
345 return;
346 // Now that we are in helper thread, we can do the the blocking
347 // StartSrpcServices operation.
348 if (!ld_subprocess_->StartSrpcServices()) {
349 TranslateFailed(
350 PP_NACL_ERROR_SRPC_CONNECTION_FAIL,
351 "SRPC connection failure for " + ld_subprocess_->description());
352 return;
356 SrpcParams params;
357 std::vector<nacl::DescWrapper*> ld_in_files;
358 size_t i;
359 for (i = 0; i < obj_files_->size(); i++) {
360 // Reset object file for reading first.
361 if (!(*obj_files_)[i]->Reset()) {
362 TranslateFailed(PP_NACL_ERROR_PNACL_LD_SETUP,
363 "Link process could not reset object file");
365 ld_in_files.push_back((*obj_files_)[i]->read_wrapper());
367 for (; i < PnaclCoordinator::kMaxTranslatorObjectFiles; i++)
368 ld_in_files.push_back(invalid_desc_wrapper_);
370 nacl::DescWrapper* ld_out_file = nexe_file_->write_wrapper();
371 int64_t link_start_time = NaClGetTimeOfDayMicroseconds();
372 // Run LD.
373 bool success = ld_subprocess_->InvokeSrpcMethod(
374 "RunWithSplit",
375 "ihhhhhhhhhhhhhhhhh",
376 &params,
377 static_cast<int>(obj_files_->size()),
378 ld_in_files[0]->desc(),
379 ld_in_files[1]->desc(),
380 ld_in_files[2]->desc(),
381 ld_in_files[3]->desc(),
382 ld_in_files[4]->desc(),
383 ld_in_files[5]->desc(),
384 ld_in_files[6]->desc(),
385 ld_in_files[7]->desc(),
386 ld_in_files[8]->desc(),
387 ld_in_files[9]->desc(),
388 ld_in_files[10]->desc(),
389 ld_in_files[11]->desc(),
390 ld_in_files[12]->desc(),
391 ld_in_files[13]->desc(),
392 ld_in_files[14]->desc(),
393 ld_in_files[15]->desc(),
394 ld_out_file->desc());
395 if (!success) {
396 TranslateFailed(PP_NACL_ERROR_PNACL_LD_INTERNAL,
397 "link failed.");
398 return;
400 GetNaClInterface()->LogTranslateTime(
401 "NaCl.Perf.PNaClLoadTime.LinkTime",
402 NaClGetTimeOfDayMicroseconds() - link_start_time);
403 PLUGIN_PRINTF(("PnaclCoordinator: link (translator=%p) succeeded\n",
404 this));
406 // Shut down the ld subprocess.
407 NaClXMutexLock(&subprocess_mu_);
408 ld_subprocess_active_ = false;
409 ld_subprocess_->Shutdown();
410 NaClXMutexUnlock(&subprocess_mu_);
412 pp::Core* core = pp::Module::Get()->core();
413 core->CallOnMainThread(0, report_translate_finished_, PP_OK);
416 void PnaclTranslateThread::TranslateFailed(
417 PP_NaClError err_code,
418 const std::string& error_string) {
419 PLUGIN_PRINTF(("PnaclTranslateThread::TranslateFailed (error_string='%s')\n",
420 error_string.c_str()));
421 pp::Core* core = pp::Module::Get()->core();
422 if (coordinator_error_info_->message().empty()) {
423 // Only use our message if one hasn't already been set by the coordinator
424 // (e.g. pexe load failed).
425 coordinator_error_info_->SetReport(err_code,
426 std::string("PnaclCoordinator: ") +
427 error_string);
429 core->CallOnMainThread(0, report_translate_finished_, PP_ERROR_FAILED);
432 void PnaclTranslateThread::AbortSubprocesses() {
433 PLUGIN_PRINTF(("PnaclTranslateThread::AbortSubprocesses\n"));
434 NaClXMutexLock(&subprocess_mu_);
435 if (compiler_subprocess_ != NULL && compiler_subprocess_active_) {
436 // We only run the service_runtime's Shutdown and do not run the
437 // NaClSubprocess Shutdown, which would otherwise nullify some
438 // pointers that could still be in use (srpc_client, etc.).
439 compiler_subprocess_->service_runtime()->Shutdown();
440 compiler_subprocess_active_ = false;
442 if (ld_subprocess_ != NULL && ld_subprocess_active_) {
443 ld_subprocess_->service_runtime()->Shutdown();
444 ld_subprocess_active_ = false;
446 NaClXMutexUnlock(&subprocess_mu_);
447 nacl::MutexLocker ml(&cond_mu_);
448 done_ = true;
449 // Free all buffered bitcode chunks
450 data_buffers_.clear();
451 NaClXCondVarSignal(&buffer_cond_);
454 PnaclTranslateThread::~PnaclTranslateThread() {
455 PLUGIN_PRINTF(("~PnaclTranslateThread (translate_thread=%p)\n", this));
456 AbortSubprocesses();
457 if (translate_thread_ != NULL)
458 NaClThreadJoin(translate_thread_.get());
459 PLUGIN_PRINTF(("~PnaclTranslateThread joined\n"));
460 NaClCondVarDtor(&buffer_cond_);
461 NaClMutexDtor(&cond_mu_);
462 NaClMutexDtor(&subprocess_mu_);
465 } // namespace plugin