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"
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"
26 typedef std::vector
<nacl::string
> string_vector
;
27 int32_t kArbitraryStackSize
= 128 << 10;
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.
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 //////////////////////////////////////////////////////////////////////
99 PnaclCoordinator::MakeDelayedCallback(pp::CompletionCallback cb
,
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
) {
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
);
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
);
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
);
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=%"
164 if (kInvalidNaClSubprocessId
== llc_id
) {
165 error_info
.SetReport(ERROR_UNKNOWN
,
166 "Could not load pnacl compiler nexe");
167 ReportLoadError(error_info
);
168 PnaclNonPpapiError();
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
);
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=%"
192 if (kInvalidNaClSubprocessId
== ld_id
) {
193 error_info
.SetReport(ERROR_UNKNOWN
,
194 "Could not load pnacl linker nexe");
195 ReportLoadError(error_info
);
196 PnaclNonPpapiError();
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
);
211 PnaclPpapiError(pp_error
);
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");
227 PnaclPpapiError(pp_error
);
229 translation_unit
->pexe_wrapper
.reset(
230 plugin_
->wrapper_factory()->MakeFileDesc(fd
, O_RDONLY
));
231 delayed_callback
->RunIfTime();
235 //////////////////////////////////////////////////////////////////////
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
,
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",
260 "-mtriple=i686-none-nacl-gnu",
261 "-asm-verbose=false",
263 const char* llc_args_x8664
[] = { "-march=x86-64",
265 "-mtriple=x86_64-none-nacl-gnu",
266 "-asm-verbose=false",
268 const char* llc_args_arm
[] = { "-march=arm",
270 "-mtriple=armv7a-none-nacl-gnueabi",
271 "-asm-verbose=false",
281 "-no-inline-jumptables" };
283 nacl::string sandbox_isa
= GetSandboxISA();
284 const char** llc_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
);
297 AbortTranslateThread(p
,
298 "PnaclCoordinator compiler unhandled ISA " +
303 for (uint32_t i
= 0; i
< num_args
; i
++) {
304 if (coordinator
->SubprocessesShouldDie()) {
307 SrpcParams dummy_params
;
308 if (!PnaclSrpcLib::InvokeSrpcMethod(browser
,
314 AbortTranslateThread(p
,
315 "PnaclCoordinator compiler AddArg(" +
316 nacl::string(llc_args
[i
]) + ") failed.");
320 if (coordinator
->SubprocessesShouldDie()) {
324 if (!PnaclSrpcLib::InvokeSrpcMethod(browser
,
329 p
->pexe_wrapper
->desc())) {
330 AbortTranslateThread(p
,
331 "PnaclCoordinator compile failed.");
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()) {
349 pp::Core
* core
= pp::Module::Get()->core();
350 core
->CallOnMainThread(0, p
->translate_done_cb
, PP_OK
);
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
);
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
,
383 delayed_link_callback
);
384 translate_thread_
.reset(new NaClThread
);
385 if (translate_thread_
!= NULL
) {
386 if (!NaClThreadCreateJoinable(translate_thread_
.get(),
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();
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...
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.
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");
433 //////////////////////////////////////////////////////////////////////
434 // Final link callbacks.
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
);
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).
457 // TODO(jvoung): Be able to handle the dynamic linking flags too,
458 // and don't hardcode so much here.
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");
471 "PnaclCoordinator linker unhandled ISA " +
475 for (string_vector::iterator i
= flags
.begin(), e
= flags
.end();
477 const nacl::string
& flag
= *i
;
478 if (coordinator
->SubprocessesShouldDie()) {
481 SrpcParams dummy_params
;
482 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface
,
489 "PnaclCoordinator linker AddArg(" + flag
+
495 string_vector files
= LinkResources(sandbox_isa
, true);
496 PnaclResources
* resources
= coordinator
->resources();
497 for (string_vector::iterator i
= files
.begin(), e
= files
.end();
499 const nacl::string
& link_file
= *i
;
500 if (coordinator
->SubprocessesShouldDie()) {
504 SrpcParams dummy_params
;
505 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface
,
510 link_file
.c_str())) {
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
,
524 p
->obj_wrapper
->desc(),
527 "PnaclCoordinator linker AddFileWithSize"
528 "(" + link_file
+ ") failed.");
531 SrpcParams dummy_params2
;
532 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface
,
538 resources
->DescForUrl(link_file
))) {
540 "PnaclCoordinator linker AddFile(" + link_file
+
546 if (coordinator
->SubprocessesShouldDie()) {
550 // Finally, do the Link!
552 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface
,
557 AbortLinkThread(p
, "PnaclCoordinator link failed.");
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()) {
569 pp::Core
* core
= pp::Module::Get()->core();
570 core
->CallOnMainThread(0, p
->link_done_cb
, PP_OK
);
576 void PnaclCoordinator::RunLinkDidFinish(
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
);
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
,
603 link_thread_
.reset(new NaClThread
);
604 if (link_thread_
!= NULL
) {
605 if (!NaClThreadCreateJoinable(link_thread_
.get(),
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();
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: " +
633 ReportLoadError(error_info
);
634 PnaclNonPpapiError();
640 void PnaclCoordinator::AddDownloadToDelayedCallback(
641 void (PnaclCoordinator::*handler
)(int32_t,
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(
650 callback_factory_
.NewCallback(handler
, url
, delayed_callback
)));
651 delayed_callback
->IncrRequirements(1);
654 void PnaclCoordinator::AddDownloadToDelayedCallback(
655 void (PnaclCoordinator::*handler
)(int32_t,
657 PnaclTranslationUnit
*,
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(
666 callback_factory_
.NewCallback(handler
,
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",
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).
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,
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.
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
,
729 translation_unit_
.get(),
731 AddDownloadToDelayedCallback(&PnaclCoordinator::LLCReady
,
732 delayed_translate_callback
,
735 AddDownloadToDelayedCallback(&PnaclCoordinator::LDReady
,
736 delayed_link_callback
,
739 for (string_vector::iterator
740 i
= link_resources
.begin(), e
= link_resources
.end();
743 AddDownloadToDelayedCallback(&PnaclCoordinator::LinkResourceReady
,
744 delayed_link_callback
,
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.
758 } // namespace plugin