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_coordinator.h"
10 #include "native_client/src/include/checked_cast.h"
11 #include "native_client/src/include/portability_io.h"
12 #include "native_client/src/shared/platform/nacl_check.h"
13 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
15 #include "ppapi/c/pp_bool.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/c/private/ppb_uma_private.h"
19 #include "ppapi/native_client/src/trusted/plugin/manifest.h"
20 #include "ppapi/native_client/src/trusted/plugin/nacl_http_response_headers.h"
21 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
22 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
23 #include "ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h"
24 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
25 #include "ppapi/native_client/src/trusted/plugin/temporary_file.h"
29 //////////////////////////////////////////////////////////////////////
30 // Pnacl-specific manifest support.
31 //////////////////////////////////////////////////////////////////////
33 // The PNaCl linker gets file descriptors via the service runtime's
34 // reverse service lookup. The reverse service lookup requires a manifest.
35 // Normally, that manifest is an NMF containing mappings for shared libraries.
36 // Here, we provide a manifest that redirects to PNaCl component files
37 // that are part of Chrome.
38 class PnaclManifest : public Manifest {
40 PnaclManifest() : manifest_base_url_(PnaclUrls::GetBaseUrl()) { }
41 virtual ~PnaclManifest() { }
43 virtual bool GetProgramURL(nacl::string* full_url,
44 PnaclOptions* pnacl_options,
45 ErrorInfo* error_info) const {
46 // Does not contain program urls.
47 UNREFERENCED_PARAMETER(full_url);
48 UNREFERENCED_PARAMETER(pnacl_options);
49 UNREFERENCED_PARAMETER(error_info);
50 PLUGIN_PRINTF(("PnaclManifest does not contain a program\n"));
51 error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL,
52 "pnacl manifest does not contain a program.");
56 virtual bool ResolveURL(const nacl::string& relative_url,
57 nacl::string* full_url,
58 ErrorInfo* error_info) const {
59 // Does not do general URL resolution, simply appends relative_url to
60 // the end of manifest_base_url_.
61 UNREFERENCED_PARAMETER(error_info);
62 *full_url = manifest_base_url_ + relative_url;
66 virtual bool GetFileKeys(std::set<nacl::string>* keys) const {
67 // Does not support enumeration.
68 PLUGIN_PRINTF(("PnaclManifest does not support key enumeration\n"));
69 UNREFERENCED_PARAMETER(keys);
73 virtual bool ResolveKey(const nacl::string& key,
74 nacl::string* full_url,
75 PnaclOptions* pnacl_options,
76 ErrorInfo* error_info) const {
77 // All of the component files are native (do not require pnacl translate).
78 pnacl_options->set_translate(false);
79 // We can only resolve keys in the files/ namespace.
80 const nacl::string kFilesPrefix = "files/";
81 size_t files_prefix_pos = key.find(kFilesPrefix);
82 if (files_prefix_pos == nacl::string::npos) {
83 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
84 "key did not start with files/");
87 // Resolve the full URL to the file. Provide it with a platform-specific
89 nacl::string key_basename = key.substr(kFilesPrefix.length());
90 return ResolveURL(PnaclUrls::PrependPlatformPrefix(key_basename),
91 full_url, error_info);
95 NACL_DISALLOW_COPY_AND_ASSIGN(PnaclManifest);
97 nacl::string manifest_base_url_;
100 //////////////////////////////////////////////////////////////////////
102 //////////////////////////////////////////////////////////////////////
106 // Assume translation time metrics *can be* large.
108 const int64_t kTimeLargeMin = 10; // in ms
109 const int64_t kTimeLargeMax = 720000; // in ms
110 const uint32_t kTimeLargeBuckets = 100;
112 const int32_t kSizeKBMin = 1;
113 const int32_t kSizeKBMax = 512*1024; // very large .pexe / .nexe.
114 const uint32_t kSizeKBBuckets = 100;
116 const int32_t kRatioMin = 10;
117 const int32_t kRatioMax = 10*100; // max of 10x difference.
118 const uint32_t kRatioBuckets = 100;
120 const int32_t kKBPSMin = 1;
121 const int32_t kKBPSMax = 30*1000; // max of 30 MB / sec.
122 const uint32_t kKBPSBuckets = 100;
124 const PPB_UMA_Private* uma_interface = NULL;
126 const PPB_UMA_Private* GetUMAInterface() {
127 if (uma_interface != NULL) {
128 return uma_interface;
130 pp::Module *module = pp::Module::Get();
132 uma_interface = static_cast<const PPB_UMA_Private*>(
133 module->GetBrowserInterface(PPB_UMA_PRIVATE_INTERFACE));
134 return uma_interface;
137 void HistogramTime(const std::string& name, int64_t ms) {
140 const PPB_UMA_Private* ptr = GetUMAInterface();
141 if (ptr == NULL) return;
143 ptr->HistogramCustomTimes(pp::Var(name).pp_var(),
145 kTimeLargeMin, kTimeLargeMax,
149 void HistogramSizeKB(const std::string& name, int32_t kb) {
152 const PPB_UMA_Private* ptr = GetUMAInterface();
153 if (ptr == NULL) return;
155 ptr->HistogramCustomCounts(pp::Var(name).pp_var(),
157 kSizeKBMin, kSizeKBMax,
161 void HistogramRatio(const std::string& name, int64_t a, int64_t b) {
162 if (a < 0 || b <= 0) return;
164 const PPB_UMA_Private* ptr = GetUMAInterface();
165 if (ptr == NULL) return;
167 ptr->HistogramCustomCounts(pp::Var(name).pp_var(),
169 kRatioMin, kRatioMax,
173 void HistogramKBPerSec(const std::string& name, double kb, double s) {
174 if (kb < 0.0 || s <= 0.0) return;
176 const PPB_UMA_Private* ptr = GetUMAInterface();
177 if (ptr == NULL) return;
179 ptr->HistogramCustomCounts(pp::Var(name).pp_var(),
180 static_cast<int64_t>(kb / s),
185 void HistogramEnumerateTranslationCache(bool hit) {
186 const PPB_UMA_Private* ptr = GetUMAInterface();
187 if (ptr == NULL) return;
188 ptr->HistogramEnumeration(pp::Var("NaCl.Perf.PNaClCache.IsHit").pp_var(),
192 // Opt level is expected to be 0 to 3. Treating 4 as unknown.
193 const int8_t kOptUnknown = 4;
195 void HistogramOptLevel(int8_t opt_level) {
196 const PPB_UMA_Private* ptr = GetUMAInterface();
197 if (ptr == NULL) return;
198 if (opt_level < 0 || opt_level > 3) {
199 opt_level = kOptUnknown;
201 ptr->HistogramEnumeration(pp::Var("NaCl.Options.PNaCl.OptLevel").pp_var(),
202 opt_level, kOptUnknown+1);
208 //////////////////////////////////////////////////////////////////////
209 // The coordinator class.
210 //////////////////////////////////////////////////////////////////////
212 // Out-of-line destructor to keep it from getting put in every .o where
213 // callback_source.h is included
215 CallbackSource<FileStreamData>::~CallbackSource() {}
217 PnaclCoordinator* PnaclCoordinator::BitcodeToNative(
219 const nacl::string& pexe_url,
220 const PnaclOptions& pnacl_options,
221 const pp::CompletionCallback& translate_notify_callback) {
222 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (plugin=%p, pexe=%s)\n",
223 static_cast<void*>(plugin), pexe_url.c_str()));
224 PnaclCoordinator* coordinator =
225 new PnaclCoordinator(plugin, pexe_url,
227 translate_notify_callback);
228 coordinator->pnacl_init_time_ = NaClGetTimeOfDayMicroseconds();
229 coordinator->off_the_record_ =
230 plugin->nacl_interface()->IsOffTheRecord();
231 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (manifest=%p, "
232 "off_the_record=%d)\n",
233 reinterpret_cast<const void*>(coordinator->manifest_.get()),
234 coordinator->off_the_record_));
236 // First start a network request for the pexe, to tickle the component
237 // updater's On-Demand resource throttler, and to get Last-Modified/ETag
238 // cache information. We can cancel the request later if there's
239 // a bitcode->nexe cache hit.
240 coordinator->OpenBitcodeStream();
244 PnaclCoordinator::PnaclCoordinator(
246 const nacl::string& pexe_url,
247 const PnaclOptions& pnacl_options,
248 const pp::CompletionCallback& translate_notify_callback)
249 : translate_finish_error_(PP_OK),
251 translate_notify_callback_(translate_notify_callback),
252 translation_finished_reported_(false),
253 manifest_(new PnaclManifest()),
255 pnacl_options_(pnacl_options),
256 is_cache_hit_(PP_FALSE),
257 error_already_reported_(false),
258 off_the_record_(false),
261 pexe_bytes_compiled_(0),
262 expected_pexe_size_(-1) {
263 PLUGIN_PRINTF(("PnaclCoordinator::PnaclCoordinator (this=%p, plugin=%p)\n",
264 static_cast<void*>(this), static_cast<void*>(plugin)));
265 callback_factory_.Initialize(this);
268 PnaclCoordinator::~PnaclCoordinator() {
269 PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p, "
270 "translate_thread=%p\n",
271 static_cast<void*>(this), translate_thread_.get()));
272 // Stopping the translate thread will cause the translate thread to try to
273 // run translation_complete_callback_ on the main thread. This destructor is
274 // running from the main thread, and by the time it exits, callback_factory_
275 // will have been destroyed. This will result in the cancellation of
276 // translation_complete_callback_, so no notification will be delivered.
277 if (translate_thread_.get() != NULL) {
278 translate_thread_->AbortSubprocesses();
280 if (!translation_finished_reported_) {
281 plugin_->nacl_interface()->ReportTranslationFinished(
282 plugin_->pp_instance(),
287 nacl::DescWrapper* PnaclCoordinator::ReleaseTranslatedFD() {
288 DCHECK(temp_nexe_file_ != NULL);
289 return temp_nexe_file_->release_read_wrapper();
292 void PnaclCoordinator::ReportNonPpapiError(enum PluginErrorCode err_code,
293 const nacl::string& message) {
294 error_info_.SetReport(err_code, message);
298 void PnaclCoordinator::ReportPpapiError(enum PluginErrorCode err_code,
300 const nacl::string& message) {
301 nacl::stringstream ss;
302 ss << "PnaclCoordinator: " << message << " (pp_error=" << pp_error << ").";
303 error_info_.SetReport(err_code, ss.str());
307 void PnaclCoordinator::ExitWithError() {
308 PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError (error_code=%d, "
310 error_info_.error_code(),
311 error_info_.message().c_str()));
312 plugin_->ReportLoadError(error_info_);
313 // Free all the intermediate callbacks we ever created.
314 // Note: this doesn't *cancel* the callbacks from the factories attached
315 // to the various helper classes (e.g., pnacl_resources). Thus, those
316 // callbacks may still run asynchronously. We let those run but ignore
317 // any other errors they may generate so that they do not end up running
318 // translate_notify_callback_, which has already been freed.
319 callback_factory_.CancelAll();
320 if (!error_already_reported_) {
321 error_already_reported_ = true;
322 translation_finished_reported_ = true;
323 plugin_->nacl_interface()->ReportTranslationFinished(
324 plugin_->pp_instance(),
326 translate_notify_callback_.Run(PP_ERROR_FAILED);
328 PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError an earlier error was "
329 "already reported -- Skipping.\n"));
333 // Signal that Pnacl translation completed normally.
334 void PnaclCoordinator::TranslateFinished(int32_t pp_error) {
335 PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%"
336 NACL_PRId32 ")\n", pp_error));
337 // Bail out if there was an earlier error (e.g., pexe load failure),
338 // or if there is an error from the translation thread.
339 if (translate_finish_error_ != PP_OK || pp_error != PP_OK) {
343 // Send out one last progress event, to finish up the progress events
344 // that were delayed (see the delay inserted in BitcodeGotCompiled).
345 if (ExpectedProgressKnown()) {
346 pexe_bytes_compiled_ = expected_pexe_size_;
347 plugin_->EnqueueProgressEvent(plugin::Plugin::kProgressEventProgress,
349 plugin::Plugin::LENGTH_IS_COMPUTABLE,
350 pexe_bytes_compiled_,
351 expected_pexe_size_);
354 // If there are no errors, report stats from this thread (the main thread).
355 HistogramOptLevel(pnacl_options_.opt_level());
356 const plugin::PnaclTimeStats& time_stats = translate_thread_->GetTimeStats();
357 HistogramTime("NaCl.Perf.PNaClLoadTime.LoadCompiler",
358 time_stats.pnacl_llc_load_time / NACL_MICROS_PER_MILLI);
359 HistogramTime("NaCl.Perf.PNaClLoadTime.CompileTime",
360 time_stats.pnacl_compile_time / NACL_MICROS_PER_MILLI);
361 HistogramKBPerSec("NaCl.Perf.PNaClLoadTime.CompileKBPerSec",
363 time_stats.pnacl_compile_time / 1000000.0);
364 HistogramTime("NaCl.Perf.PNaClLoadTime.LoadLinker",
365 time_stats.pnacl_ld_load_time / NACL_MICROS_PER_MILLI);
366 HistogramTime("NaCl.Perf.PNaClLoadTime.LinkTime",
367 time_stats.pnacl_link_time / NACL_MICROS_PER_MILLI);
368 HistogramSizeKB("NaCl.Perf.Size.Pexe",
369 static_cast<int64_t>(pexe_size_ / 1024));
371 struct nacl_abi_stat stbuf;
372 struct NaClDesc* desc = temp_nexe_file_->read_wrapper()->desc();
374 if (0 != (stat_ret = (*((struct NaClDescVtbl const *) desc->base.vtbl)->
375 Fstat)(desc, &stbuf))) {
376 PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished can't stat nexe.\n"));
378 size_t nexe_size = stbuf.nacl_abi_st_size;
379 HistogramSizeKB("NaCl.Perf.Size.PNaClTranslatedNexe",
380 static_cast<int64_t>(nexe_size / 1024));
381 HistogramRatio("NaCl.Perf.Size.PexeNexeSizePct", pexe_size_, nexe_size);
384 int64_t total_time = NaClGetTimeOfDayMicroseconds() - pnacl_init_time_;
385 HistogramTime("NaCl.Perf.PNaClLoadTime.TotalUncachedTime",
386 total_time / NACL_MICROS_PER_MILLI);
387 HistogramKBPerSec("NaCl.Perf.PNaClLoadTime.TotalUncachedKBPerSec",
389 total_time / 1000000.0);
391 // The nexe is written to the temp_nexe_file_. We must Reset() the file
392 // pointer to be able to read it again from the beginning.
393 temp_nexe_file_->Reset();
395 // Report to the browser that translation finished. The browser will take
396 // care of storing the nexe in the cache.
397 translation_finished_reported_ = true;
398 plugin_->nacl_interface()->ReportTranslationFinished(
399 plugin_->pp_instance(), PP_TRUE);
401 NexeReadDidOpen(PP_OK);
404 void PnaclCoordinator::NexeReadDidOpen(int32_t pp_error) {
405 PLUGIN_PRINTF(("PnaclCoordinator::NexeReadDidOpen (pp_error=%"
406 NACL_PRId32 ")\n", pp_error));
407 if (pp_error != PP_OK) {
408 if (pp_error == PP_ERROR_FILENOTFOUND) {
409 ReportPpapiError(ERROR_PNACL_CACHE_FETCH_NOTFOUND,
411 "Failed to open translated nexe (not found).");
414 if (pp_error == PP_ERROR_NOACCESS) {
415 ReportPpapiError(ERROR_PNACL_CACHE_FETCH_NOACCESS,
417 "Failed to open translated nexe (no access).");
420 ReportPpapiError(ERROR_PNACL_CACHE_FETCH_OTHER,
422 "Failed to open translated nexe.");
426 translate_notify_callback_.Run(pp_error);
429 void PnaclCoordinator::OpenBitcodeStream() {
430 // Now open the pexe stream.
431 streaming_downloader_.reset(new FileDownloader());
432 streaming_downloader_->Initialize(plugin_);
433 // Mark the request as requesting a PNaCl bitcode file,
434 // so that component updater can detect this user action.
435 streaming_downloader_->set_request_headers(
436 "Accept: application/x-pnacl, */*");
438 // Even though we haven't started downloading, create the translation
439 // thread object immediately. This ensures that any pieces of the file
440 // that get downloaded before the compilation thread is accepting
441 // SRPCs won't get dropped.
442 translate_thread_.reset(new PnaclTranslateThread());
443 if (translate_thread_ == NULL) {
445 ERROR_PNACL_THREAD_CREATE,
446 "PnaclCoordinator: could not allocate translation thread.");
450 pp::CompletionCallback cb =
451 callback_factory_.NewCallback(&PnaclCoordinator::BitcodeStreamDidOpen);
452 if (!streaming_downloader_->OpenStream(pexe_url_, cb, this)) {
454 ERROR_PNACL_PEXE_FETCH_OTHER,
455 nacl::string("PnaclCoordinator: failed to open stream ") + pexe_url_);
460 void PnaclCoordinator::BitcodeStreamDidOpen(int32_t pp_error) {
461 if (pp_error != PP_OK) {
462 BitcodeStreamDidFinish(pp_error);
463 // We have not spun up the translation process yet, so we need to call
464 // TranslateFinished here.
465 TranslateFinished(pp_error);
469 // The component updater's resource throttles + OnDemand update/install
470 // should block the URL request until the compiler is present. Now we
471 // can load the resources (e.g. llc and ld nexes).
472 resources_.reset(new PnaclResources(plugin_, this, this->manifest_.get()));
473 CHECK(resources_ != NULL);
475 // The first step of loading resources: read the resource info file.
476 pp::CompletionCallback resource_info_read_cb =
477 callback_factory_.NewCallback(&PnaclCoordinator::ResourceInfoWasRead);
478 resources_->ReadResourceInfo(PnaclUrls::GetResourceInfoUrl(),
479 resource_info_read_cb);
482 void PnaclCoordinator::ResourceInfoWasRead(int32_t pp_error) {
483 PLUGIN_PRINTF(("PluginCoordinator::ResourceInfoWasRead (pp_error=%"
484 NACL_PRId32 ")\n", pp_error));
485 // Second step of loading resources: call StartLoad to load pnacl-llc
486 // and pnacl-ld, based on the filenames found in the resource info file.
487 pp::CompletionCallback resources_cb =
488 callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad);
489 resources_->StartLoad(resources_cb);
492 void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) {
493 PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%"
494 NACL_PRId32 ")\n", pp_error));
495 if (pp_error != PP_OK) {
496 // Finer-grained error code should have already been reported by
497 // the PnaclResources class.
501 // Okay, now that we've started the HTTP request for the pexe
502 // and we've ensured that the PNaCl compiler + metadata is installed,
503 // get the cache key from the response headers and from the
504 // compiler's version metadata.
505 nacl::string headers = streaming_downloader_->GetResponseHeaders();
506 NaClHttpResponseHeaders parser;
507 parser.Parse(headers);
509 temp_nexe_file_.reset(new TempFile(plugin_));
510 pp::CompletionCallback cb =
511 callback_factory_.NewCallback(&PnaclCoordinator::NexeFdDidOpen);
512 int32_t nexe_fd_err =
513 plugin_->nacl_interface()->GetNexeFd(
514 plugin_->pp_instance(),
515 streaming_downloader_->url().c_str(),
516 // TODO(dschuff): Get this value from the pnacl json file after it
517 // rolls in from NaCl.
519 pnacl_options_.opt_level(),
520 parser.GetHeader("last-modified").c_str(),
521 parser.GetHeader("etag").c_str(),
522 PP_FromBool(parser.CacheControlNoStore()),
524 temp_nexe_file_->existing_handle(),
525 cb.pp_completion_callback());
526 if (nexe_fd_err < PP_OK_COMPLETIONPENDING) {
527 ReportPpapiError(ERROR_PNACL_CREATE_TEMP, nexe_fd_err,
528 nacl::string("Call to GetNexeFd failed"));
532 void PnaclCoordinator::NexeFdDidOpen(int32_t pp_error) {
533 PLUGIN_PRINTF(("PnaclCoordinator::NexeFdDidOpen (pp_error=%"
534 NACL_PRId32 ", hit=%d, handle=%d)\n", pp_error,
535 is_cache_hit_ == PP_TRUE,
536 *temp_nexe_file_->existing_handle()));
537 if (pp_error < PP_OK) {
538 ReportPpapiError(ERROR_PNACL_CREATE_TEMP, pp_error,
539 nacl::string("GetNexeFd failed"));
543 if (*temp_nexe_file_->existing_handle() == PP_kInvalidFileHandle) {
545 ERROR_PNACL_CREATE_TEMP,
547 "PnaclCoordinator: Got bad temp file handle from GetNexeFd"));
550 HistogramEnumerateTranslationCache(is_cache_hit_);
552 if (is_cache_hit_ == PP_TRUE) {
553 // Cache hit -- no need to stream the rest of the file.
554 streaming_downloader_.reset(NULL);
555 // Open it for reading as the cached nexe file.
556 pp::CompletionCallback cb =
557 callback_factory_.NewCallback(&PnaclCoordinator::NexeReadDidOpen);
558 temp_nexe_file_->Open(cb, false);
560 // Open an object file first so the translator can start writing to it
561 // during streaming translation.
562 obj_file_.reset(new TempFile(plugin_));
563 pp::CompletionCallback obj_cb =
564 callback_factory_.NewCallback(&PnaclCoordinator::ObjectFileDidOpen);
565 obj_file_->Open(obj_cb, true);
567 // Meanwhile, a miss means we know we need to stream the bitcode, so stream
568 // the rest of it now. (Calling FinishStreaming means that the downloader
569 // will begin handing data to the coordinator, which is safe any time after
570 // the translate_thread_ object has been initialized).
571 pp::CompletionCallback finish_cb = callback_factory_.NewCallback(
572 &PnaclCoordinator::BitcodeStreamDidFinish);
573 streaming_downloader_->FinishStreaming(finish_cb);
577 void PnaclCoordinator::BitcodeStreamDidFinish(int32_t pp_error) {
578 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamDidFinish (pp_error=%"
579 NACL_PRId32 ")\n", pp_error));
580 if (pp_error != PP_OK) {
581 // Defer reporting the error and cleanup until after the translation
582 // thread returns, because it may be accessing the coordinator's
583 // objects or writing to the files.
584 translate_finish_error_ = pp_error;
585 if (pp_error == PP_ERROR_ABORTED) {
586 error_info_.SetReport(ERROR_PNACL_PEXE_FETCH_ABORTED,
587 "PnaclCoordinator: pexe load failed (aborted).");
589 if (pp_error == PP_ERROR_NOACCESS) {
590 error_info_.SetReport(ERROR_PNACL_PEXE_FETCH_NOACCESS,
591 "PnaclCoordinator: pexe load failed (no access).");
593 nacl::stringstream ss;
594 ss << "PnaclCoordinator: pexe load failed (pp_error=" << pp_error << ").";
595 error_info_.SetReport(ERROR_PNACL_PEXE_FETCH_OTHER, ss.str());
597 translate_thread_->AbortSubprocesses();
599 // Compare download completion pct (100% now), to compile completion pct.
600 HistogramRatio("NaCl.Perf.PNaClLoadTime.PctCompiledWhenFullyDownloaded",
601 pexe_bytes_compiled_, pexe_size_);
605 void PnaclCoordinator::BitcodeStreamGotData(int32_t pp_error,
606 FileStreamData data) {
607 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamGotData (pp_error=%"
608 NACL_PRId32 ", data=%p)\n", pp_error, data ? &(*data)[0] : 0));
609 DCHECK(translate_thread_.get());
611 translate_thread_->PutBytes(data, pp_error);
612 // If pp_error > 0, then it represents the number of bytes received.
613 if (data && pp_error > 0) {
614 pexe_size_ += pp_error;
618 StreamCallback PnaclCoordinator::GetCallback() {
619 return callback_factory_.NewCallbackWithOutput(
620 &PnaclCoordinator::BitcodeStreamGotData);
623 void PnaclCoordinator::BitcodeGotCompiled(int32_t pp_error,
624 int64_t bytes_compiled) {
625 pexe_bytes_compiled_ += bytes_compiled;
626 // If we don't know the expected total yet, ask.
627 if (!ExpectedProgressKnown()) {
628 int64_t amount_downloaded; // dummy variable.
629 streaming_downloader_->GetDownloadProgress(&amount_downloaded,
630 &expected_pexe_size_);
632 // Hold off reporting the last few bytes of progress, since we don't know
633 // when they are actually completely compiled. "bytes_compiled" only means
634 // that bytes were sent to the compiler.
635 if (ExpectedProgressKnown()) {
636 if (!ShouldDelayProgressEvent()) {
637 plugin_->EnqueueProgressEvent(plugin::Plugin::kProgressEventProgress,
639 plugin::Plugin::LENGTH_IS_COMPUTABLE,
640 pexe_bytes_compiled_,
641 expected_pexe_size_);
644 plugin_->EnqueueProgressEvent(plugin::Plugin::kProgressEventProgress,
646 plugin::Plugin::LENGTH_IS_NOT_COMPUTABLE,
647 pexe_bytes_compiled_,
648 expected_pexe_size_);
652 pp::CompletionCallback PnaclCoordinator::GetCompileProgressCallback(
653 int64_t bytes_compiled) {
654 return callback_factory_.NewCallback(&PnaclCoordinator::BitcodeGotCompiled,
658 void PnaclCoordinator::GetCurrentProgress(int64_t* bytes_loaded,
659 int64_t* bytes_total) {
660 *bytes_loaded = pexe_bytes_compiled_;
661 *bytes_total = expected_pexe_size_;
664 void PnaclCoordinator::ObjectFileDidOpen(int32_t pp_error) {
665 PLUGIN_PRINTF(("PnaclCoordinator::ObjectFileDidOpen (pp_error=%"
666 NACL_PRId32 ")\n", pp_error));
667 if (pp_error != PP_OK) {
668 ReportPpapiError(ERROR_PNACL_CREATE_TEMP,
670 "Failed to open scratch object file.");
673 // Open the nexe file for connecting ld and sel_ldr.
674 // Start translation when done with this last step of setup!
675 pp::CompletionCallback cb =
676 callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate);
677 temp_nexe_file_->Open(cb, true);
680 void PnaclCoordinator::RunTranslate(int32_t pp_error) {
681 PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%"
682 NACL_PRId32 ")\n", pp_error));
683 // Invoke llc followed by ld off the main thread. This allows use of
684 // blocking RPCs that would otherwise block the JavaScript main thread.
685 pp::CompletionCallback report_translate_finished =
686 callback_factory_.NewCallback(&PnaclCoordinator::TranslateFinished);
688 CHECK(translate_thread_ != NULL);
689 translate_thread_->RunTranslate(report_translate_finished,
692 temp_nexe_file_.get(),
700 } // namespace plugin