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

Side by Side Diff: ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc

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

Powered by Google App Engine
This is Rietveld 408576698