Silence an MSVC warning
[chromium-blink-merge.git] / ppapi / native_client / src / trusted / plugin / pnacl_coordinator.cc
blob969591b6190dc7d30b1c329e8c5a38850a90c8fe
1 // Copyright (c) 2011 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 "native_client/src/trusted/plugin/pnacl_coordinator.h"
7 #include <utility>
8 #include <vector>
10 #include "native_client/src/include/portability_io.h"
11 #include "native_client/src/shared/platform/nacl_check.h"
12 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
13 #include "native_client/src/trusted/plugin/browser_interface.h"
14 #include "native_client/src/trusted/plugin/nacl_subprocess.h"
15 #include "native_client/src/trusted/plugin/nexe_arch.h"
16 #include "native_client/src/trusted/plugin/plugin.h"
17 #include "native_client/src/trusted/plugin/plugin_error.h"
18 #include "native_client/src/trusted/plugin/pnacl_srpc_lib.h"
19 #include "native_client/src/trusted/plugin/scriptable_handle.h"
20 #include "native_client/src/trusted/plugin/utility.h"
22 #include "ppapi/c/pp_errors.h"
24 namespace {
26 typedef std::vector<nacl::string> string_vector;
27 int32_t kArbitraryStackSize = 128 << 10;
29 } // namespace
31 namespace plugin {
33 class Plugin;
35 void PnaclResources::AddFDForUrl(const nacl::string& url, int32_t fd) {
36 resource_wrappers_[url] =
37 plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY);
40 void PnaclCoordinator::Initialize(Plugin* plugin) {
41 PLUGIN_PRINTF(("PnaclCoordinator::Initialize (this=%p)\n",
42 static_cast<void*>(this)));
43 CHECK(plugin != NULL);
44 CHECK(plugin_ == NULL); // Can only initialize once.
45 plugin_ = plugin;
46 callback_factory_.Initialize(this);
47 resources_.reset(new PnaclResources(plugin));
50 PnaclCoordinator::~PnaclCoordinator() {
51 PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n",
52 static_cast<void*>(this)));
54 // Join helper threads which will block the page from refreshing while a
55 // translation is happening.
56 if (translate_thread_.get() != NULL || link_thread_.get() != NULL) {
57 SetSubprocessesShouldDie(true);
59 if (translate_thread_.get() != NULL) {
60 NaClThreadJoin(translate_thread_.get());
62 if (link_thread_.get() != NULL) {
63 NaClThreadJoin(link_thread_.get());
66 // Delete all delayed_callbacks.
67 delayed_callbacks.erase(delayed_callbacks.begin(), delayed_callbacks.end());
70 void PnaclCoordinator::ReportLoadAbort() {
71 plugin_->ReportLoadAbort();
74 void PnaclCoordinator::ReportLoadError(const ErrorInfo& error) {
75 plugin_->ReportLoadError(error);
78 void PnaclCoordinator::PnaclPpapiError(int32_t pp_error) {
79 // Attempt to free all the intermediate callbacks we ever created.
80 callback_factory_.CancelAll();
81 translate_notify_callback_.Run(pp_error);
84 void PnaclCoordinator::PnaclNonPpapiError() {
85 PnaclPpapiError(PP_ERROR_FAILED);
88 void PnaclCoordinator::PnaclDidFinish(int32_t pp_error,
89 PnaclTranslationUnit* translation_unit) {
90 UNREFERENCED_PARAMETER(translation_unit);
91 PLUGIN_PRINTF(("PnaclCoordinator::PnaclDidFinish (pp_error=%"
92 NACL_PRId32")\n", pp_error));
93 translate_notify_callback_.Run(pp_error);
96 //////////////////////////////////////////////////////////////////////
98 DelayedCallback*
99 PnaclCoordinator::MakeDelayedCallback(pp::CompletionCallback cb,
100 uint32_t num_deps) {
101 DelayedCallback* delayed_callback = new DelayedCallback(cb, num_deps);
102 delayed_callbacks.insert(delayed_callback);
103 return delayed_callback;
106 int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error,
107 const nacl::string& url,
108 const nacl::string& component) {
109 ErrorInfo error_info;
110 int32_t file_desc = plugin_->GetPOSIXFileDesc(url);
111 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) {
112 if (pp_error == PP_ERROR_ABORTED) {
113 ReportLoadAbort();
114 } else {
115 // TODO(jvoung): Make a generic load error, or just use ERROR_UNKNOWN?
116 error_info.SetReport(ERROR_UNKNOWN,
117 "PNaCl " + component + " load failed.");
118 ReportLoadError(error_info);
120 return -1;
122 int32_t file_desc_ok_to_close = DUP(file_desc);
123 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) {
124 // TODO(jvoung): Make a generic load error, or just use ERROR_UNKNOWN?
125 error_info.SetReport(ERROR_UNKNOWN,
126 "PNaCl " + component + " load failed: "
127 "could not dup fd.");
128 ReportLoadError(error_info);
129 return -1;
131 return file_desc_ok_to_close;
134 NaClSubprocessId PnaclCoordinator::HelperNexeDidLoad(int32_t fd,
135 ErrorInfo* error_info) {
136 // Inform JavaScript that we successfully loaded a helper nexe.
137 plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress);
138 nacl::scoped_ptr<nacl::DescWrapper>
139 wrapper(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY));
141 return plugin_->LoadHelperNaClModule(wrapper.get(), error_info);
144 //////////////////////////////////////////////////////////////////////
145 // First few callbacks.
147 void PnaclCoordinator::LLCReady(int32_t pp_error,
148 const nacl::string& llc_url,
149 DelayedCallback* delayed_callback) {
150 // pp_error is checked by GetLoadedFileDesc.
151 int32_t file_desc_ok_to_close = GetLoadedFileDesc(pp_error, llc_url, "llc");
152 ErrorInfo error_info;
153 if (file_desc_ok_to_close < 0) {
154 PnaclPpapiError(pp_error);
155 return;
157 NaClSubprocessId llc_id =
158 HelperNexeDidLoad(file_desc_ok_to_close, &error_info);
159 PLUGIN_PRINTF(("PnaclCoordinator::LLCReady (pp_error=%"
160 NACL_PRId32" nexe_id=%"
161 NACL_PRId32")\n",
162 pp_error,
163 llc_id));
164 if (kInvalidNaClSubprocessId == llc_id) {
165 error_info.SetReport(ERROR_UNKNOWN,
166 "Could not load pnacl compiler nexe");
167 ReportLoadError(error_info);
168 PnaclNonPpapiError();
169 return;
171 llc_subprocess_ = plugin_ ->nacl_subprocess(llc_id);
172 delayed_callback->RunIfTime();
175 void PnaclCoordinator::LDReady(int32_t pp_error,
176 const nacl::string& ld_url,
177 DelayedCallback* delayed_callback) {
178 // pp_error is checked by GetLoadedFileDesc.
179 int32_t file_desc_ok_to_close = GetLoadedFileDesc(pp_error, ld_url, "ld");
180 ErrorInfo error_info;
181 if (file_desc_ok_to_close < 0) {
182 PnaclPpapiError(pp_error);
183 return;
185 NaClSubprocessId ld_id =
186 HelperNexeDidLoad(file_desc_ok_to_close, &error_info);
187 PLUGIN_PRINTF(("PnaclCoordinator::LDReady (pp_error=%"
188 NACL_PRId32" nexe_id=%"
189 NACL_PRId32")\n",
190 pp_error,
191 ld_id));
192 if (kInvalidNaClSubprocessId == ld_id) {
193 error_info.SetReport(ERROR_UNKNOWN,
194 "Could not load pnacl linker nexe");
195 ReportLoadError(error_info);
196 PnaclNonPpapiError();
197 return;
199 ld_subprocess_ = plugin_ ->nacl_subprocess(ld_id);
200 delayed_callback->RunIfTime();
203 void PnaclCoordinator::LinkResourceReady(int32_t pp_error,
204 const nacl::string& url,
205 DelayedCallback* delayed_callback) {
206 PLUGIN_PRINTF(("PnaclCoordinator::LinkResourceReady (pp_error=%"
207 NACL_PRId32", url=%s)\n", pp_error, url.c_str()));
208 // pp_error is checked by GetLoadedFileDesc.
209 int32_t fd = GetLoadedFileDesc(pp_error, url, "linker resource " + url);
210 if (fd < 0) {
211 PnaclPpapiError(pp_error);
212 } else {
213 resources_->AddFDForUrl(url, fd);
214 delayed_callback->RunIfTime();
218 void PnaclCoordinator::PexeReady(int32_t pp_error,
219 const nacl::string& pexe_url,
220 PnaclTranslationUnit* translation_unit,
221 DelayedCallback* delayed_callback) {
222 PLUGIN_PRINTF(("PnaclCoordinator::PexeReady (pp_error=%"
223 NACL_PRId32")\n", pp_error));
224 // pp_error is checked by GetLoadedFileDesc.
225 int32_t fd = GetLoadedFileDesc(pp_error, pexe_url, "pexe");
226 if (fd < 0) {
227 PnaclPpapiError(pp_error);
228 } else {
229 translation_unit->pexe_wrapper.reset(
230 plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY));
231 delayed_callback->RunIfTime();
235 //////////////////////////////////////////////////////////////////////
237 namespace {
238 void AbortTranslateThread(PnaclTranslationUnit* translation_unit,
239 const nacl::string& error_string) {
240 pp::Core* core = pp::Module::Get()->core();
241 translation_unit->error_info.SetReport(ERROR_UNKNOWN, error_string);
242 core->CallOnMainThread(0, translation_unit->translate_done_cb,
243 PP_ERROR_FAILED);
244 NaClThreadExit(1);
247 void WINAPI DoTranslateThread(void* arg) {
248 PnaclTranslationUnit* p = reinterpret_cast<PnaclTranslationUnit*>(arg);
249 PnaclCoordinator* coordinator = p->coordinator;
250 NaClSubprocess* llc_subprocess = coordinator->llc_subprocess();
251 Plugin* plugin = coordinator->plugin();
252 BrowserInterface* browser = plugin->browser_interface();
254 // Set up LLC flags first.
255 // TODO(jvoung): Bake these into the llc nexe?
256 // May also want to improve scriptability, but the only thing we need
257 // probably is PIC vs non-PIC and micro-arch specification.
258 const char* llc_args_x8632[] = { "-march=x86",
259 "-mcpu=pentium4",
260 "-mtriple=i686-none-nacl-gnu",
261 "-asm-verbose=false",
262 "-filetype=obj" };
263 const char* llc_args_x8664[] = { "-march=x86-64",
264 "-mcpu=core2",
265 "-mtriple=x86_64-none-nacl-gnu",
266 "-asm-verbose=false",
267 "-filetype=obj" };
268 const char* llc_args_arm[] = { "-march=arm",
269 "-mcpu=cortex-a8",
270 "-mtriple=armv7a-none-nacl-gnueabi",
271 "-asm-verbose=false",
272 "-filetype=obj",
273 "-arm-reserve-r9",
274 "-sfi-disable-cp",
275 "-arm_static_tls",
276 "-sfi-store",
277 "-sfi-load",
278 "-sfi-stack",
279 "-sfi-branch",
280 "-sfi-data",
281 "-no-inline-jumptables" };
283 nacl::string sandbox_isa = GetSandboxISA();
284 const char** llc_args;
285 size_t num_args;
287 if (sandbox_isa.compare("x86-32") == 0) {
288 llc_args = llc_args_x8632;
289 num_args = NACL_ARRAY_SIZE(llc_args_x8632);
290 } else if (sandbox_isa.compare("x86-64") == 0) {
291 llc_args = llc_args_x8664;
292 num_args = NACL_ARRAY_SIZE(llc_args_x8664);
293 } else if (sandbox_isa.compare("arm") == 0) {
294 llc_args = llc_args_arm;
295 num_args = NACL_ARRAY_SIZE(llc_args_arm);
296 } else {
297 AbortTranslateThread(p,
298 "PnaclCoordinator compiler unhandled ISA " +
299 sandbox_isa + ".");
300 return;
303 for (uint32_t i = 0; i < num_args; i++) {
304 if (coordinator->SubprocessesShouldDie()) {
305 NaClThreadExit(1);
307 SrpcParams dummy_params;
308 if (!PnaclSrpcLib::InvokeSrpcMethod(browser,
309 llc_subprocess,
310 "AddArg",
311 "C",
312 &dummy_params,
313 llc_args[i])) {
314 AbortTranslateThread(p,
315 "PnaclCoordinator compiler AddArg(" +
316 nacl::string(llc_args[i]) + ") failed.");
320 if (coordinator->SubprocessesShouldDie()) {
321 NaClThreadExit(1);
323 SrpcParams params;
324 if (!PnaclSrpcLib::InvokeSrpcMethod(browser,
325 llc_subprocess,
326 "Translate",
327 "h",
328 &params,
329 p->pexe_wrapper->desc())) {
330 AbortTranslateThread(p,
331 "PnaclCoordinator compile failed.");
332 } else {
333 // Grab the outparams.
334 p->obj_wrapper.reset(
335 plugin->wrapper_factory()->MakeGeneric(params.outs()[0]->u.hval));
336 p->obj_len = params.outs()[1]->u.ival;
337 p->is_shared_library = params.outs()[2]->u.ival != 0;
338 p->soname = params.outs()[3]->arrays.str;
339 p->lib_dependencies = params.outs()[4]->arrays.str;
340 PLUGIN_PRINTF(("PnaclCoordinator::Translate SRPC succeeded (bytes=%"
341 NACL_PRId32", is_shared_library=%d, soname='%s', "
342 "lib_dependencies='%s')\n", p->obj_len,
343 p->is_shared_library, p->soname.c_str(),
344 p->lib_dependencies.c_str()));
346 if (coordinator->SubprocessesShouldDie()) {
347 NaClThreadExit(1);
349 pp::Core* core = pp::Module::Get()->core();
350 core->CallOnMainThread(0, p->translate_done_cb, PP_OK);
351 NaClThreadExit(0);
354 } // namespace
356 void
357 PnaclCoordinator::RunTranslateDidFinish(int32_t pp_error,
358 PnaclTranslationUnit* translation_unit,
359 DelayedCallback* link_callback) {
360 PLUGIN_PRINTF(("PnaclCoordinator::RunTranslateDidFinish (pp_error=%"
361 NACL_PRId32")\n", pp_error));
362 if (pp_error != PP_OK) {
363 ReportLoadError(translation_unit->error_info);
364 PnaclPpapiError(pp_error);
365 return;
367 plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress);
368 link_callback->RunIfTime();
371 void PnaclCoordinator::RunTranslate(int32_t pp_error,
372 PnaclTranslationUnit* translation_unit,
373 DelayedCallback* delayed_link_callback) {
374 PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%"
375 NACL_PRId32")\n", pp_error));
376 assert(PP_OK == pp_error);
378 // Invoke llvm asynchronously.
379 // RunTranslateDidFinish runs on the main thread when llvm is done.
380 translation_unit->translate_done_cb =
381 callback_factory_.NewCallback(&PnaclCoordinator::RunTranslateDidFinish,
382 translation_unit,
383 delayed_link_callback);
384 translate_thread_.reset(new NaClThread);
385 if (translate_thread_ != NULL) {
386 if (!NaClThreadCreateJoinable(translate_thread_.get(),
387 DoTranslateThread,
388 translation_unit,
389 kArbitraryStackSize)) {
390 ErrorInfo error_info;
391 error_info.SetReport(ERROR_UNKNOWN,
392 "Could not create a translator thread.\n");
393 ReportLoadError(error_info);
394 PnaclNonPpapiError();
396 } else {
397 ErrorInfo error_info;
398 error_info.SetReport(ERROR_UNKNOWN,
399 "Could not allocate DoTranslateThread()\n");
400 ReportLoadError(error_info);
401 PnaclNonPpapiError();
405 //////////////////////////////////////////////////////////////////////
406 // Helper functions for loading native libs.
407 // Done here to avoid hacking on the manifest parser further...
409 namespace {
411 // Fake filename for the object file generated by llvm.
412 nacl::string GeneratedObjectFileName() {
413 return nacl::string("___PNACL_GENERATED");
416 string_vector LinkResources(const nacl::string& sandbox_isa,
417 bool withGenerated) {
418 string_vector results;
419 nacl::string base_dir = "pnacl_support/" + sandbox_isa;
421 // NOTE: order of items == link order.
422 if (withGenerated) {
423 results.push_back(GeneratedObjectFileName());
425 results.push_back(base_dir + "/libcrt_platform.a");
426 results.push_back(base_dir + "/libgcc.a");
427 results.push_back(base_dir + "/libgcc_eh.a");
428 return results;
431 } // namespace
433 //////////////////////////////////////////////////////////////////////
434 // Final link callbacks.
436 namespace {
438 void AbortLinkThread(PnaclTranslationUnit* translation_unit,
439 const nacl::string& error_string) {
440 ErrorInfo error_info;
441 pp::Core* core = pp::Module::Get()->core();
442 translation_unit->error_info.SetReport(ERROR_UNKNOWN, error_string);
443 core->CallOnMainThread(0, translation_unit->link_done_cb, PP_ERROR_FAILED);
444 NaClThreadExit(1);
447 void WINAPI DoLinkThread(void* arg) {
448 PnaclTranslationUnit* p = reinterpret_cast<PnaclTranslationUnit*>(arg);
449 PnaclCoordinator* coordinator = p->coordinator;
450 NaClSubprocess* ld_subprocess = coordinator->ld_subprocess();
451 Plugin* plugin = coordinator->plugin();
452 BrowserInterface* browser_interface = plugin->browser_interface();
454 // Set up command line arguments (flags then files).
456 //// Flags.
457 // TODO(jvoung): Be able to handle the dynamic linking flags too,
458 // and don't hardcode so much here.
459 string_vector flags;
460 nacl::string sandbox_isa = GetSandboxISA();
461 flags.push_back("-nostdlib");
462 flags.push_back("-m");
463 if (sandbox_isa.compare("x86-32") == 0) {
464 flags.push_back("elf_nacl");
465 } else if (sandbox_isa.compare("x86-64") == 0) {
466 flags.push_back("elf64_nacl");
467 } else if (sandbox_isa.compare("arm") == 0) {
468 flags.push_back("armelf_nacl");
469 } else {
470 AbortLinkThread(p,
471 "PnaclCoordinator linker unhandled ISA " +
472 sandbox_isa + ".");
475 for (string_vector::iterator i = flags.begin(), e = flags.end();
476 i != e; ++i) {
477 const nacl::string& flag = *i;
478 if (coordinator->SubprocessesShouldDie()) {
479 NaClThreadExit(1);
481 SrpcParams dummy_params;
482 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface,
483 ld_subprocess,
484 "AddArg",
485 "C",
486 &dummy_params,
487 flag.c_str())) {
488 AbortLinkThread(p,
489 "PnaclCoordinator linker AddArg(" + flag +
490 ") failed.");
494 //// Files.
495 string_vector files = LinkResources(sandbox_isa, true);
496 PnaclResources* resources = coordinator->resources();
497 for (string_vector::iterator i = files.begin(), e = files.end();
498 i != e; ++i) {
499 const nacl::string& link_file = *i;
500 if (coordinator->SubprocessesShouldDie()) {
501 NaClThreadExit(1);
503 // Add as argument.
504 SrpcParams dummy_params;
505 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface,
506 ld_subprocess,
507 "AddArg",
508 "C",
509 &dummy_params,
510 link_file.c_str())) {
511 AbortLinkThread(p,
512 "PnaclCoordinator linker AddArg(" +
513 link_file + ") failed.");
515 // Also map the file name to descriptor.
516 if (i->compare(GeneratedObjectFileName()) == 0) {
517 SrpcParams dummy_params2;
518 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface,
519 ld_subprocess,
520 "AddFileWithSize",
521 "Chi",
522 &dummy_params2,
523 link_file.c_str(),
524 p->obj_wrapper->desc(),
525 p->obj_len)) {
526 AbortLinkThread(p,
527 "PnaclCoordinator linker AddFileWithSize"
528 "(" + link_file + ") failed.");
530 } else {
531 SrpcParams dummy_params2;
532 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface,
533 ld_subprocess,
534 "AddFile",
535 "Ch",
536 &dummy_params2,
537 link_file.c_str(),
538 resources->DescForUrl(link_file))) {
539 AbortLinkThread(p,
540 "PnaclCoordinator linker AddFile(" + link_file +
541 ") failed.");
546 if (coordinator->SubprocessesShouldDie()) {
547 NaClThreadExit(1);
550 // Finally, do the Link!
551 SrpcParams params;
552 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface,
553 ld_subprocess,
554 "Link",
556 &params)) {
557 AbortLinkThread(p, "PnaclCoordinator link failed.");
558 } else {
559 // Grab the outparams.
560 p->nexe_wrapper.reset(
561 plugin->wrapper_factory()->MakeGeneric(params.outs()[0]->u.hval));
562 int32_t nexe_size = params.outs()[1]->u.ival; // only for debug.
563 PLUGIN_PRINTF(("PnaclCoordinator::InvokeLink succeeded (bytes=%"
564 NACL_PRId32")\n", nexe_size));
566 if (coordinator->SubprocessesShouldDie()) {
567 NaClThreadExit(1);
569 pp::Core* core = pp::Module::Get()->core();
570 core->CallOnMainThread(0, p->link_done_cb, PP_OK);
571 NaClThreadExit(0);
574 } // namespace
576 void PnaclCoordinator::RunLinkDidFinish(
577 int32_t pp_error,
578 PnaclTranslationUnit* translation_unit) {
579 PLUGIN_PRINTF(("PnaclCoordinator::RunLinkDidFinish (pp_error=%"
580 NACL_PRId32")\n", pp_error));
581 if (pp_error != PP_OK) {
582 ReportLoadError(translation_unit->error_info);
583 PnaclPpapiError(pp_error);
584 return;
586 // Transfer ownership of the nexe wrapper to the coordinator.
587 translated_fd_.reset(translation_unit->nexe_wrapper.release());
588 plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress);
589 PnaclDidFinish(PP_OK, translation_unit);
592 void PnaclCoordinator::RunLink(int32_t pp_error,
593 PnaclTranslationUnit* translation_unit) {
594 PLUGIN_PRINTF(("PnaclCoordinator::RunLink (pp_error=%"
595 NACL_PRId32")\n", pp_error));
596 assert(PP_OK == pp_error);
598 // Invoke ld asynchronously.
599 // When ld has completed, RunLinkDidFinish is run on the main thread.
600 translation_unit->link_done_cb =
601 callback_factory_.NewCallback(&PnaclCoordinator::RunLinkDidFinish,
602 translation_unit);
603 link_thread_.reset(new NaClThread);
604 if (link_thread_ != NULL) {
605 if (!NaClThreadCreateJoinable(link_thread_.get(),
606 DoLinkThread,
607 translation_unit,
608 kArbitraryStackSize)) {
609 ErrorInfo error_info;
610 error_info.SetReport(ERROR_UNKNOWN,
611 "Could not create a linker thread.\n");
612 ReportLoadError(error_info);
613 PnaclNonPpapiError();
615 } else {
616 ErrorInfo error_info;
617 error_info.SetReport(ERROR_UNKNOWN,
618 "Could not allocate DoLinkThread()\n");
619 ReportLoadError(error_info);
620 PnaclNonPpapiError();
624 //////////////////////////////////////////////////////////////////////
626 bool PnaclCoordinator::ScheduleDownload(const nacl::string& url,
627 const pp::CompletionCallback& cb) {
628 if (!plugin_->StreamAsFile(url, cb.pp_completion_callback())) {
629 ErrorInfo error_info;
630 error_info.SetReport(ERROR_UNKNOWN,
631 "PnaclCoordinator: Failed to download file: " +
632 url + "\n");
633 ReportLoadError(error_info);
634 PnaclNonPpapiError();
635 return false;
637 return true;
640 void PnaclCoordinator::AddDownloadToDelayedCallback(
641 void (PnaclCoordinator::*handler)(int32_t,
642 const nacl::string&,
643 DelayedCallback*),
644 DelayedCallback* delayed_callback,
645 const nacl::string& url,
646 std::vector<url_callback_pair>& queue) {
647 // Queue up the URL download w/ a callback that invokes the delayed_callback.
648 queue.push_back(std::make_pair(
649 url,
650 callback_factory_.NewCallback(handler, url, delayed_callback)));
651 delayed_callback->IncrRequirements(1);
654 void PnaclCoordinator::AddDownloadToDelayedCallback(
655 void (PnaclCoordinator::*handler)(int32_t,
656 const nacl::string&,
657 PnaclTranslationUnit*,
658 DelayedCallback*),
659 DelayedCallback* delayed_callback,
660 const nacl::string& url,
661 PnaclTranslationUnit* translation_unit,
662 std::vector<url_callback_pair>& queue) {
663 // Queue up the URL download w/ a callback that invokes the delayed_callback.
664 queue.push_back(std::make_pair(
665 url,
666 callback_factory_.NewCallback(handler,
667 url,
668 translation_unit,
669 delayed_callback)));
670 delayed_callback->IncrRequirements(1);
673 void PnaclCoordinator::BitcodeToNative(
674 const nacl::string& pexe_url,
675 const nacl::string& llc_url,
676 const nacl::string& ld_url,
677 const pp::CompletionCallback& finish_callback) {
678 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (pexe=%s, llc=%s, ld=%s)\n",
679 pexe_url.c_str(),
680 llc_url.c_str(),
681 ld_url.c_str()));
682 translate_notify_callback_ = finish_callback;
684 string_vector link_resources = LinkResources(GetSandboxISA(), false);
686 // TODO(sehr): revise to download llc, ld, and native libraries in one step.
687 // TODO(sehr): save these resources for possible multiple uses (e.g., psos).
689 // Steps:
690 // (1) Schedule downloads for llc, ld nexes, and native libraries.
691 // (2) When llc download and pexe has completed, run the translation.
692 // (3) When llc translation has finished, and ld, native libs are available,
693 // do the link.
694 // (4) When the link is done, we are done, call the finish_callback.
695 // Hand off the SHM file descriptor returned by link.
697 // Set up async callbacks for these steps in reverse order.
699 // (3) Run link.
701 translation_unit_.reset(new PnaclTranslationUnit(this));
703 pp::CompletionCallback run_link_callback =
704 callback_factory_.NewCallback(&PnaclCoordinator::RunLink,
705 translation_unit_.get());
706 DelayedCallback* delayed_link_callback =
707 MakeDelayedCallback(run_link_callback, 0);
709 // (2) Run translation.
710 pp::CompletionCallback run_translate_callback =
711 callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate,
712 translation_unit_.get(),
713 delayed_link_callback);
714 // Linking depends on the compile finishing, so incr requirements by one.
715 delayed_link_callback->IncrRequirements(1);
717 DelayedCallback* delayed_translate_callback =
718 MakeDelayedCallback(run_translate_callback, 0);
720 // (1) Load nexes and assets using StreamAsFile(). This will kick off
721 // the whole process.
723 // First, just collect the list of stuff to download.
724 std::vector<url_callback_pair> downloads;
726 AddDownloadToDelayedCallback(&PnaclCoordinator::PexeReady,
727 delayed_translate_callback,
728 pexe_url,
729 translation_unit_.get(),
730 downloads);
731 AddDownloadToDelayedCallback(&PnaclCoordinator::LLCReady,
732 delayed_translate_callback,
733 llc_url,
734 downloads);
735 AddDownloadToDelayedCallback(&PnaclCoordinator::LDReady,
736 delayed_link_callback,
737 ld_url,
738 downloads);
739 for (string_vector::iterator
740 i = link_resources.begin(), e = link_resources.end();
741 i != e;
742 ++i) {
743 AddDownloadToDelayedCallback(&PnaclCoordinator::LinkResourceReady,
744 delayed_link_callback,
746 downloads);
749 // Finally, actually schedule the downloads.
750 for (size_t i = 0; i < downloads.size(); ++i) {
751 if (!ScheduleDownload(downloads[i].first, downloads[i].second)) {
752 break; // error should have been reported by ScheduleDownload.
755 downloads.clear();
758 } // namespace plugin