Componentize component_updater: Copy over test data with executable bit.
[chromium-blink-merge.git] / ppapi / native_client / src / trusted / plugin / pnacl_translate_thread.cc
blob7247f39193a6a32c17486d699465beabf02b59f3
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 "ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h"
7 #include <iterator>
9 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
10 #include "ppapi/cpp/var.h"
11 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
12 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
13 #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h"
14 #include "ppapi/native_client/src/trusted/plugin/srpc_params.h"
15 #include "ppapi/native_client/src/trusted/plugin/temporary_file.h"
16 #include "ppapi/native_client/src/trusted/plugin/utility.h"
18 namespace plugin {
19 namespace {
21 template <typename Val>
22 nacl::string MakeCommandLineArg(const char* key, const Val val) {
23 nacl::stringstream ss;
24 ss << key << val;
25 return ss.str();
28 void GetLlcCommandLine(Plugin* plugin,
29 std::vector<char>* split_args,
30 size_t obj_files_size,
31 int32_t opt_level,
32 bool is_debug,
33 const nacl::string &architecture_attributes) {
34 typedef std::vector<nacl::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 (Args::const_iterator arg(args.begin()); arg != args.end(); ++arg) {
48 std::copy(arg->begin(), arg->end(), std::back_inserter(*split_args));
49 split_args->push_back('\x00');
53 } // namespace
55 PnaclTranslateThread::PnaclTranslateThread() : llc_subprocess_active_(false),
56 ld_subprocess_active_(false),
57 subprocesses_aborted_(false),
58 done_(false),
59 compile_time_(0),
60 obj_files_(NULL),
61 nexe_file_(NULL),
62 coordinator_error_info_(NULL),
63 resources_(NULL),
64 coordinator_(NULL),
65 plugin_(NULL) {
66 NaClXMutexCtor(&subprocess_mu_);
67 NaClXMutexCtor(&cond_mu_);
68 NaClXCondVarCtor(&buffer_cond_);
71 void PnaclTranslateThread::RunTranslate(
72 const pp::CompletionCallback& finish_callback,
73 const std::vector<TempFile*>* obj_files,
74 TempFile* nexe_file,
75 nacl::DescWrapper* invalid_desc_wrapper,
76 ErrorInfo* error_info,
77 PnaclResources* resources,
78 PP_PNaClOptions* pnacl_options,
79 const nacl::string &architecture_attributes,
80 PnaclCoordinator* coordinator,
81 Plugin* plugin) {
82 PLUGIN_PRINTF(("PnaclStreamingTranslateThread::RunTranslate)\n"));
83 obj_files_ = obj_files;
84 nexe_file_ = nexe_file;
85 invalid_desc_wrapper_ = invalid_desc_wrapper;
86 coordinator_error_info_ = error_info;
87 resources_ = resources;
88 pnacl_options_ = pnacl_options;
89 architecture_attributes_ = architecture_attributes;
90 coordinator_ = coordinator;
91 plugin_ = plugin;
93 // Invoke llc followed by ld off the main thread. This allows use of
94 // blocking RPCs that would otherwise block the JavaScript main thread.
95 report_translate_finished_ = finish_callback;
96 translate_thread_.reset(new NaClThread);
97 if (translate_thread_ == NULL) {
98 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE,
99 "could not allocate thread struct.");
100 return;
102 const int32_t kArbitraryStackSize = 128 * 1024;
103 if (!NaClThreadCreateJoinable(translate_thread_.get(),
104 DoTranslateThread,
105 this,
106 kArbitraryStackSize)) {
107 TranslateFailed(PP_NACL_ERROR_PNACL_THREAD_CREATE,
108 "could not create thread.");
109 translate_thread_.reset(NULL);
113 // Called from main thread to send bytes to the translator.
114 void PnaclTranslateThread::PutBytes(const void* bytes, int32_t count) {
115 CHECK(bytes != NULL);
116 NaClXMutexLock(&cond_mu_);
117 data_buffers_.push_back(std::vector<char>());
118 data_buffers_.back().insert(data_buffers_.back().end(),
119 static_cast<const char*>(bytes),
120 static_cast<const char*>(bytes) + count);
121 NaClXCondVarSignal(&buffer_cond_);
122 NaClXMutexUnlock(&cond_mu_);
125 void PnaclTranslateThread::EndStream() {
126 NaClXMutexLock(&cond_mu_);
127 done_ = true;
128 NaClXCondVarSignal(&buffer_cond_);
129 NaClXMutexUnlock(&cond_mu_);
132 void WINAPI PnaclTranslateThread::DoTranslateThread(void* arg) {
133 PnaclTranslateThread* translator =
134 reinterpret_cast<PnaclTranslateThread*>(arg);
135 translator->DoTranslate();
138 void PnaclTranslateThread::DoTranslate() {
139 ErrorInfo error_info;
140 SrpcParams params;
141 std::vector<nacl::DescWrapper*> llc_out_files;
142 size_t i;
143 for (i = 0; i < obj_files_->size(); i++)
144 llc_out_files.push_back((*obj_files_)[i]->write_wrapper());
145 for (; i < PnaclCoordinator::kMaxTranslatorObjectFiles; i++)
146 llc_out_files.push_back(invalid_desc_wrapper_);
148 pp::Core* core = pp::Module::Get()->core();
149 int64_t llc_start_time = NaClGetTimeOfDayMicroseconds();
150 PP_NaClFileInfo llc_file_info = resources_->TakeLlcFileInfo();
151 // On success, ownership of llc_file_info is transferred.
152 NaClSubprocess* llc_subprocess = plugin_->LoadHelperNaClModule(
153 resources_->GetLlcUrl(), llc_file_info, &error_info);
154 if (llc_subprocess == NULL) {
155 if (llc_file_info.handle != PP_kInvalidFileHandle)
156 CloseFileHandle(llc_file_info.handle);
157 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_SETUP,
158 "Compile process could not be created: " +
159 error_info.message());
160 return;
162 GetNaClInterface()->LogTranslateTime(
163 "NaCl.Perf.PNaClLoadTime.LoadCompiler",
164 NaClGetTimeOfDayMicroseconds() - llc_start_time);
167 nacl::MutexLocker ml(&subprocess_mu_);
168 // If we received a call to AbortSubprocesses() before we had a chance to
169 // set llc_subprocess_, shut down and clean up the subprocess started here.
170 if (subprocesses_aborted_) {
171 llc_subprocess->service_runtime()->Shutdown();
172 delete llc_subprocess;
173 return;
175 llc_subprocess_.reset(llc_subprocess);
176 llc_subprocess = NULL;
177 llc_subprocess_active_ = true;
180 int64_t compile_start_time = NaClGetTimeOfDayMicroseconds();
181 bool init_success;
183 std::vector<char> split_args;
184 GetLlcCommandLine(plugin_,
185 &split_args,
186 obj_files_->size(),
187 pnacl_options_->opt_level,
188 pnacl_options_->is_debug,
189 architecture_attributes_);
190 init_success = llc_subprocess_->InvokeSrpcMethod(
191 "StreamInitWithSplit",
192 "ihhhhhhhhhhhhhhhhC",
193 &params,
194 static_cast<int>(obj_files_->size()),
195 llc_out_files[0]->desc(),
196 llc_out_files[1]->desc(),
197 llc_out_files[2]->desc(),
198 llc_out_files[3]->desc(),
199 llc_out_files[4]->desc(),
200 llc_out_files[5]->desc(),
201 llc_out_files[6]->desc(),
202 llc_out_files[7]->desc(),
203 llc_out_files[8]->desc(),
204 llc_out_files[9]->desc(),
205 llc_out_files[10]->desc(),
206 llc_out_files[11]->desc(),
207 llc_out_files[12]->desc(),
208 llc_out_files[13]->desc(),
209 llc_out_files[14]->desc(),
210 llc_out_files[15]->desc(),
211 &split_args[0],
212 split_args.size());
213 if (!init_success) {
214 if (llc_subprocess_->srpc_client()->GetLastError() ==
215 NACL_SRPC_RESULT_APP_ERROR) {
216 // The error message is only present if the error was returned from llc
217 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
218 nacl::string("Stream init failed: ") +
219 nacl::string(params.outs()[0]->arrays.str));
220 } else {
221 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
222 "Stream init internal error");
224 return;
226 PLUGIN_PRINTF(("PnaclCoordinator: StreamInit successful\n"));
228 // llc process is started.
229 while(!done_ || data_buffers_.size() > 0) {
230 NaClXMutexLock(&cond_mu_);
231 while(!done_ && data_buffers_.size() == 0) {
232 NaClXCondVarWait(&buffer_cond_, &cond_mu_);
234 PLUGIN_PRINTF(("PnaclTranslateThread awake (done=%d, size=%" NACL_PRIuS
235 ")\n",
236 done_, data_buffers_.size()));
237 if (data_buffers_.size() > 0) {
238 std::vector<char> data;
239 data.swap(data_buffers_.front());
240 data_buffers_.pop_front();
241 NaClXMutexUnlock(&cond_mu_);
242 PLUGIN_PRINTF(("StreamChunk\n"));
243 if (!llc_subprocess_->InvokeSrpcMethod("StreamChunk",
244 "C",
245 &params,
246 &data[0],
247 data.size())) {
248 if (llc_subprocess_->srpc_client()->GetLastError() !=
249 NACL_SRPC_RESULT_APP_ERROR) {
250 // If the error was reported by the translator, then we fall through
251 // and call StreamEnd, which returns a string describing the error,
252 // which we can then send to the Javascript console. Otherwise just
253 // fail here, since the translator has probably crashed or asserted.
254 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
255 "Compile stream chunk failed. "
256 "The PNaCl translator has probably crashed.");
257 return;
259 break;
260 } else {
261 PLUGIN_PRINTF(("StreamChunk Successful\n"));
262 core->CallOnMainThread(
264 coordinator_->GetCompileProgressCallback(data.size()),
265 PP_OK);
267 } else {
268 NaClXMutexUnlock(&cond_mu_);
271 PLUGIN_PRINTF(("PnaclTranslateThread done with chunks\n"));
272 // Finish llc.
273 if (!llc_subprocess_->InvokeSrpcMethod("StreamEnd", std::string(), &params)) {
274 PLUGIN_PRINTF(("PnaclTranslateThread StreamEnd failed\n"));
275 if (llc_subprocess_->srpc_client()->GetLastError() ==
276 NACL_SRPC_RESULT_APP_ERROR) {
277 // The error string is only present if the error was sent back from llc.
278 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
279 params.outs()[3]->arrays.str);
280 } else {
281 TranslateFailed(PP_NACL_ERROR_PNACL_LLC_INTERNAL,
282 "Compile StreamEnd internal error");
284 return;
286 compile_time_ = NaClGetTimeOfDayMicroseconds() - compile_start_time;
287 GetNaClInterface()->LogTranslateTime("NaCl.Perf.PNaClLoadTime.CompileTime",
288 compile_time_);
290 // Shut down the llc subprocess.
291 NaClXMutexLock(&subprocess_mu_);
292 llc_subprocess_active_ = false;
293 llc_subprocess_.reset(NULL);
294 NaClXMutexUnlock(&subprocess_mu_);
296 if(!RunLdSubprocess()) {
297 return;
299 core->CallOnMainThread(0, report_translate_finished_, PP_OK);
302 bool PnaclTranslateThread::RunLdSubprocess() {
303 ErrorInfo error_info;
304 SrpcParams params;
306 std::vector<nacl::DescWrapper*> ld_in_files;
307 size_t i;
308 for (i = 0; i < obj_files_->size(); i++) {
309 // Reset object file for reading first.
310 if (!(*obj_files_)[i]->Reset()) {
311 TranslateFailed(PP_NACL_ERROR_PNACL_LD_SETUP,
312 "Link process could not reset object file");
313 return false;
315 ld_in_files.push_back((*obj_files_)[i]->read_wrapper());
317 for (; i < PnaclCoordinator::kMaxTranslatorObjectFiles; i++)
318 ld_in_files.push_back(invalid_desc_wrapper_);
320 nacl::DescWrapper* ld_out_file = nexe_file_->write_wrapper();
321 int64_t ld_start_time = NaClGetTimeOfDayMicroseconds();
322 PP_NaClFileInfo ld_file_info = resources_->TakeLdFileInfo();
323 // On success, ownership of ld_file_info is transferred.
324 nacl::scoped_ptr<NaClSubprocess> ld_subprocess(
325 plugin_->LoadHelperNaClModule(resources_->GetLdUrl(),
326 ld_file_info,
327 &error_info));
328 if (ld_subprocess.get() == NULL) {
329 if (ld_file_info.handle != PP_kInvalidFileHandle)
330 CloseFileHandle(ld_file_info.handle);
331 TranslateFailed(PP_NACL_ERROR_PNACL_LD_SETUP,
332 "Link process could not be created: " +
333 error_info.message());
334 return false;
336 GetNaClInterface()->LogTranslateTime(
337 "NaCl.Perf.PNaClLoadTime.LoadLinker",
338 NaClGetTimeOfDayMicroseconds() - ld_start_time);
340 nacl::MutexLocker ml(&subprocess_mu_);
341 // If we received a call to AbortSubprocesses() before we had a chance to
342 // set llc_subprocess_, shut down and clean up the subprocess started here.
343 if (subprocesses_aborted_) {
344 ld_subprocess->service_runtime()->Shutdown();
345 return false;
347 DCHECK(ld_subprocess_.get() == NULL);
348 ld_subprocess_.swap(ld_subprocess);
349 ld_subprocess_active_ = true;
352 int64_t link_start_time = NaClGetTimeOfDayMicroseconds();
353 // Run LD.
354 bool success = ld_subprocess_->InvokeSrpcMethod(
355 "RunWithSplit",
356 "ihhhhhhhhhhhhhhhhh",
357 &params,
358 static_cast<int>(obj_files_->size()),
359 ld_in_files[0]->desc(),
360 ld_in_files[1]->desc(),
361 ld_in_files[2]->desc(),
362 ld_in_files[3]->desc(),
363 ld_in_files[4]->desc(),
364 ld_in_files[5]->desc(),
365 ld_in_files[6]->desc(),
366 ld_in_files[7]->desc(),
367 ld_in_files[8]->desc(),
368 ld_in_files[9]->desc(),
369 ld_in_files[10]->desc(),
370 ld_in_files[11]->desc(),
371 ld_in_files[12]->desc(),
372 ld_in_files[13]->desc(),
373 ld_in_files[14]->desc(),
374 ld_in_files[15]->desc(),
375 ld_out_file->desc());
376 if (!success) {
377 TranslateFailed(PP_NACL_ERROR_PNACL_LD_INTERNAL,
378 "link failed.");
379 return false;
381 GetNaClInterface()->LogTranslateTime(
382 "NaCl.Perf.PNaClLoadTime.LinkTime",
383 NaClGetTimeOfDayMicroseconds() - link_start_time);
384 PLUGIN_PRINTF(("PnaclCoordinator: link (translator=%p) succeeded\n",
385 this));
386 // Shut down the ld subprocess.
387 NaClXMutexLock(&subprocess_mu_);
388 ld_subprocess_active_ = false;
389 ld_subprocess_.reset(NULL);
390 NaClXMutexUnlock(&subprocess_mu_);
391 return true;
394 void PnaclTranslateThread::TranslateFailed(
395 PP_NaClError err_code,
396 const nacl::string& error_string) {
397 PLUGIN_PRINTF(("PnaclTranslateThread::TranslateFailed (error_string='%s')\n",
398 error_string.c_str()));
399 pp::Core* core = pp::Module::Get()->core();
400 if (coordinator_error_info_->message().empty()) {
401 // Only use our message if one hasn't already been set by the coordinator
402 // (e.g. pexe load failed).
403 coordinator_error_info_->SetReport(err_code,
404 nacl::string("PnaclCoordinator: ") +
405 error_string);
407 core->CallOnMainThread(0, report_translate_finished_, PP_ERROR_FAILED);
410 void PnaclTranslateThread::AbortSubprocesses() {
411 PLUGIN_PRINTF(("PnaclTranslateThread::AbortSubprocesses\n"));
412 NaClXMutexLock(&subprocess_mu_);
413 if (llc_subprocess_ != NULL && llc_subprocess_active_) {
414 llc_subprocess_->service_runtime()->Shutdown();
415 llc_subprocess_active_ = false;
417 if (ld_subprocess_ != NULL && ld_subprocess_active_) {
418 ld_subprocess_->service_runtime()->Shutdown();
419 ld_subprocess_active_ = false;
421 subprocesses_aborted_ = true;
422 NaClXMutexUnlock(&subprocess_mu_);
423 nacl::MutexLocker ml(&cond_mu_);
424 done_ = true;
425 // Free all buffered bitcode chunks
426 data_buffers_.clear();
427 NaClXCondVarSignal(&buffer_cond_);
430 PnaclTranslateThread::~PnaclTranslateThread() {
431 PLUGIN_PRINTF(("~PnaclTranslateThread (translate_thread=%p)\n", this));
432 AbortSubprocesses();
433 if (translate_thread_ != NULL)
434 NaClThreadJoin(translate_thread_.get());
435 PLUGIN_PRINTF(("~PnaclTranslateThread joined\n"));
436 NaClCondVarDtor(&buffer_cond_);
437 NaClMutexDtor(&cond_mu_);
438 NaClMutexDtor(&subprocess_mu_);
441 } // namespace plugin