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_coordinator.h"
6
7 #include <utility>
8 #include <vector>
9
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"
14
15 #include "ppapi/c/pp_bool.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/c/private/ppb_uma_private.h"
18
19 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
20 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
21 #include "ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h"
22 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
23 #include "ppapi/native_client/src/trusted/plugin/temporary_file.h"
24
25 namespace plugin {
26
27 namespace {
28
29 const int32_t kSizeKBMin = 1;
30 const int32_t kSizeKBMax = 512*1024; // very large .pexe / .nexe.
31 const uint32_t kSizeKBBuckets = 100;
32
33 const int32_t kRatioMin = 10;
34 const int32_t kRatioMax = 10*100; // max of 10x difference.
35 const uint32_t kRatioBuckets = 100;
36
HistogramSizeKB(pp::UMAPrivate & uma,const nacl::string & name,int32_t kb)37 void HistogramSizeKB(pp::UMAPrivate& uma,
38 const nacl::string& name, int32_t kb) {
39 if (kb < 0) return;
40 uma.HistogramCustomCounts(name,
41 kb,
42 kSizeKBMin, kSizeKBMax,
43 kSizeKBBuckets);
44 }
45
HistogramRatio(pp::UMAPrivate & uma,const nacl::string & name,int64_t a,int64_t b)46 void HistogramRatio(pp::UMAPrivate& uma,
47 const nacl::string& name, int64_t a, int64_t b) {
48 if (a < 0 || b <= 0) return;
49 uma.HistogramCustomCounts(name,
50 100 * a / b,
51 kRatioMin, kRatioMax,
52 kRatioBuckets);
53 }
54
HistogramEnumerateTranslationCache(pp::UMAPrivate & uma,bool hit)55 void HistogramEnumerateTranslationCache(pp::UMAPrivate& uma, bool hit) {
56 uma.HistogramEnumeration("NaCl.Perf.PNaClCache.IsHit",
57 hit, 2);
58 }
59
GetArchitectureAttributes(Plugin * plugin)60 nacl::string GetArchitectureAttributes(Plugin* plugin) {
61 pp::Var attrs_var(pp::PASS_REF,
62 plugin->nacl_interface()->GetCpuFeatureAttrs());
63 return attrs_var.AsString();
64 }
65
66 } // namespace
67
68 // Out-of-line destructor to keep it from getting put in every .o where
69 // callback_source.h is included
70 template<>
~CallbackSource()71 CallbackSource<FileStreamData>::~CallbackSource() {}
72
BitcodeToNative(Plugin * plugin,const nacl::string & pexe_url,const PP_PNaClOptions & pnacl_options,const pp::CompletionCallback & translate_notify_callback)73 PnaclCoordinator* PnaclCoordinator::BitcodeToNative(
74 Plugin* plugin,
75 const nacl::string& pexe_url,
76 const PP_PNaClOptions& pnacl_options,
77 const pp::CompletionCallback& translate_notify_callback) {
78 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (plugin=%p, pexe=%s)\n",
79 static_cast<void*>(plugin), pexe_url.c_str()));
80 PnaclCoordinator* coordinator =
81 new PnaclCoordinator(plugin, pexe_url,
82 pnacl_options,
83 translate_notify_callback);
84
85 coordinator->pnacl_init_time_ = NaClGetTimeOfDayMicroseconds();
86 int cpus = plugin->nacl_interface()->GetNumberOfProcessors();
87 coordinator->split_module_count_ = std::min(4, std::max(1, cpus));
88
89 // First start a network request for the pexe, to tickle the component
90 // updater's On-Demand resource throttler, and to get Last-Modified/ETag
91 // cache information. We can cancel the request later if there's
92 // a bitcode->nexe cache hit.
93 coordinator->OpenBitcodeStream();
94 return coordinator;
95 }
96
PnaclCoordinator(Plugin * plugin,const nacl::string & pexe_url,const PP_PNaClOptions & pnacl_options,const pp::CompletionCallback & translate_notify_callback)97 PnaclCoordinator::PnaclCoordinator(
98 Plugin* plugin,
99 const nacl::string& pexe_url,
100 const PP_PNaClOptions& pnacl_options,
101 const pp::CompletionCallback& translate_notify_callback)
102 : translate_finish_error_(PP_OK),
103 plugin_(plugin),
104 translate_notify_callback_(translate_notify_callback),
105 translation_finished_reported_(false),
106 pexe_url_(pexe_url),
107 pnacl_options_(pnacl_options),
108 architecture_attributes_(GetArchitectureAttributes(plugin)),
109 split_module_count_(1),
110 is_cache_hit_(PP_FALSE),
111 error_already_reported_(false),
112 pnacl_init_time_(0),
113 pexe_size_(0),
114 pexe_bytes_compiled_(0),
115 expected_pexe_size_(-1) {
116 PLUGIN_PRINTF(("PnaclCoordinator::PnaclCoordinator (this=%p, plugin=%p)\n",
117 static_cast<void*>(this), static_cast<void*>(plugin)));
118 callback_factory_.Initialize(this);
119 }
120
~PnaclCoordinator()121 PnaclCoordinator::~PnaclCoordinator() {
122 PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p, "
123 "translate_thread=%p\n",
124 static_cast<void*>(this), translate_thread_.get()));
125 // Stopping the translate thread will cause the translate thread to try to
126 // run translation_complete_callback_ on the main thread. This destructor is
127 // running from the main thread, and by the time it exits, callback_factory_
128 // will have been destroyed. This will result in the cancellation of
129 // translation_complete_callback_, so no notification will be delivered.
130 if (translate_thread_.get() != NULL)
131 translate_thread_->AbortSubprocesses();
132 if (!translation_finished_reported_) {
133 plugin_->nacl_interface()->ReportTranslationFinished(
134 plugin_->pp_instance(),
135 PP_FALSE, 0, 0, 0, 0);
136 }
137 // Force deleting the translate_thread now. It must be deleted
138 // before any scoped_* fields hanging off of PnaclCoordinator
139 // since the thread may be accessing those fields.
140 // It will also be accessing obj_files_.
141 translate_thread_.reset(NULL);
142 for (size_t i = 0; i < obj_files_.size(); i++)
143 delete obj_files_[i];
144 }
145
TakeTranslatedFileHandle()146 PP_FileHandle PnaclCoordinator::TakeTranslatedFileHandle() {
147 DCHECK(temp_nexe_file_ != NULL);
148 return temp_nexe_file_->TakeFileHandle();
149 }
150
ReportNonPpapiError(PP_NaClError err_code,const nacl::string & message)151 void PnaclCoordinator::ReportNonPpapiError(PP_NaClError err_code,
152 const nacl::string& message) {
153 ErrorInfo error_info;
154 error_info.SetReport(err_code, message);
155 plugin_->ReportLoadError(error_info);
156 ExitWithError();
157 }
158
ReportPpapiError(PP_NaClError err_code,int32_t pp_error,const nacl::string & message)159 void PnaclCoordinator::ReportPpapiError(PP_NaClError err_code,
160 int32_t pp_error,
161 const nacl::string& message) {
162 nacl::stringstream ss;
163 ss << "PnaclCoordinator: " << message << " (pp_error=" << pp_error << ").";
164 ErrorInfo error_info;
165 error_info.SetReport(err_code, ss.str());
166 plugin_->ReportLoadError(error_info);
167 ExitWithError();
168 }
169
ExitWithError()170 void PnaclCoordinator::ExitWithError() {
171 PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError\n"));
172 // Free all the intermediate callbacks we ever created.
173 // Note: this doesn't *cancel* the callbacks from the factories attached
174 // to the various helper classes (e.g., pnacl_resources). Thus, those
175 // callbacks may still run asynchronously. We let those run but ignore
176 // any other errors they may generate so that they do not end up running
177 // translate_notify_callback_, which has already been freed.
178 callback_factory_.CancelAll();
179 if (!error_already_reported_) {
180 error_already_reported_ = true;
181 translation_finished_reported_ = true;
182 plugin_->nacl_interface()->ReportTranslationFinished(
183 plugin_->pp_instance(),
184 PP_FALSE, 0, 0, 0, 0);
185 translate_notify_callback_.Run(PP_ERROR_FAILED);
186 } else {
187 PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError an earlier error was "
188 "already reported -- Skipping.\n"));
189 }
190 }
191
192 // Signal that Pnacl translation completed normally.
TranslateFinished(int32_t pp_error)193 void PnaclCoordinator::TranslateFinished(int32_t pp_error) {
194 PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%"
195 NACL_PRId32 ")\n", pp_error));
196 // Bail out if there was an earlier error (e.g., pexe load failure),
197 // or if there is an error from the translation thread.
198 if (translate_finish_error_ != PP_OK || pp_error != PP_OK) {
199 plugin_->ReportLoadError(error_info_);
200 ExitWithError();
201 return;
202 }
203
204 // Send out one last progress event, to finish up the progress events
205 // that were delayed (see the delay inserted in BitcodeGotCompiled).
206 if (expected_pexe_size_ != -1) {
207 pexe_bytes_compiled_ = expected_pexe_size_;
208 GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
209 PP_NACL_EVENT_PROGRESS,
210 pexe_url_.c_str(),
211 PP_TRUE,
212 pexe_bytes_compiled_,
213 expected_pexe_size_);
214 }
215 struct nacl_abi_stat stbuf;
216 struct NaClDesc* desc = temp_nexe_file_->read_wrapper()->desc();
217 int stat_ret;
218 if (0 != (stat_ret = (*((struct NaClDescVtbl const *) desc->base.vtbl)->
219 Fstat)(desc, &stbuf))) {
220 PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished can't stat nexe.\n"));
221 } else {
222 size_t nexe_size = stbuf.nacl_abi_st_size;
223 HistogramSizeKB(plugin_->uma_interface(),
224 "NaCl.Perf.Size.PNaClTranslatedNexe",
225 static_cast<int64_t>(nexe_size / 1024));
226 HistogramRatio(plugin_->uma_interface(),
227 "NaCl.Perf.Size.PexeNexeSizePct", pexe_size_, nexe_size);
228 }
229 // The nexe is written to the temp_nexe_file_. We must Reset() the file
230 // pointer to be able to read it again from the beginning.
231 temp_nexe_file_->Reset();
232
233 int64_t total_time = NaClGetTimeOfDayMicroseconds() - pnacl_init_time_;
234 // Report to the browser that translation finished. The browser will take
235 // care of storing the nexe in the cache.
236 translation_finished_reported_ = true;
237 plugin_->nacl_interface()->ReportTranslationFinished(
238 plugin_->pp_instance(), PP_TRUE, pnacl_options_.opt_level,
239 pexe_size_, translate_thread_->GetCompileTime(), total_time);
240
241 NexeReadDidOpen(PP_OK);
242 }
243
NexeReadDidOpen(int32_t pp_error)244 void PnaclCoordinator::NexeReadDidOpen(int32_t pp_error) {
245 PLUGIN_PRINTF(("PnaclCoordinator::NexeReadDidOpen (pp_error=%"
246 NACL_PRId32 ")\n", pp_error));
247 if (pp_error != PP_OK) {
248 if (pp_error == PP_ERROR_FILENOTFOUND) {
249 ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_NOTFOUND,
250 pp_error,
251 "Failed to open translated nexe (not found).");
252 return;
253 }
254 if (pp_error == PP_ERROR_NOACCESS) {
255 ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_NOACCESS,
256 pp_error,
257 "Failed to open translated nexe (no access).");
258 return;
259 }
260 ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_OTHER,
261 pp_error,
262 "Failed to open translated nexe.");
263 return;
264 }
265
266 translate_notify_callback_.Run(pp_error);
267 }
268
OpenBitcodeStream()269 void PnaclCoordinator::OpenBitcodeStream() {
270 // Now open the pexe stream.
271 streaming_downloader_.reset(new FileDownloader(plugin_));
272 // Mark the request as requesting a PNaCl bitcode file,
273 // so that component updater can detect this user action.
274 streaming_downloader_->set_request_headers(
275 "Accept: application/x-pnacl, */*");
276
277 // Even though we haven't started downloading, create the translation
278 // thread object immediately. This ensures that any pieces of the file
279 // that get downloaded before the compilation thread is accepting
280 // SRPCs won't get dropped.
281 translate_thread_.reset(new PnaclTranslateThread());
282 if (translate_thread_ == NULL) {
283 ReportNonPpapiError(
284 PP_NACL_ERROR_PNACL_THREAD_CREATE,
285 "PnaclCoordinator: could not allocate translation thread.");
286 return;
287 }
288
289 pp::CompletionCallback cb =
290 callback_factory_.NewCallback(&PnaclCoordinator::BitcodeStreamDidOpen);
291 if (!streaming_downloader_->OpenStream(pexe_url_, cb, this)) {
292 ReportNonPpapiError(
293 PP_NACL_ERROR_PNACL_PEXE_FETCH_OTHER,
294 nacl::string("PnaclCoordinator: failed to open stream ") + pexe_url_);
295 return;
296 }
297 }
298
BitcodeStreamDidOpen(int32_t pp_error)299 void PnaclCoordinator::BitcodeStreamDidOpen(int32_t pp_error) {
300 if (pp_error != PP_OK) {
301 BitcodeStreamDidFinish(pp_error);
302 // We have not spun up the translation process yet, so we need to call
303 // TranslateFinished here.
304 TranslateFinished(pp_error);
305 return;
306 }
307
308 // The component updater's resource throttles + OnDemand update/install
309 // should block the URL request until the compiler is present. Now we
310 // can load the resources (e.g. llc and ld nexes).
311 resources_.reset(new PnaclResources(plugin_));
312 CHECK(resources_ != NULL);
313
314 // The first step of loading resources: read the resource info file.
315 pp::CompletionCallback resource_info_read_cb =
316 callback_factory_.NewCallback(&PnaclCoordinator::ResourceInfoWasRead);
317 resources_->ReadResourceInfo(resource_info_read_cb);
318 }
319
ResourceInfoWasRead(int32_t pp_error)320 void PnaclCoordinator::ResourceInfoWasRead(int32_t pp_error) {
321 PLUGIN_PRINTF(("PluginCoordinator::ResourceInfoWasRead (pp_error=%"
322 NACL_PRId32 ")\n", pp_error));
323 if (pp_error != PP_OK) {
324 ExitWithError();
325 return;
326 }
327 // Second step of loading resources: call StartLoad to load pnacl-llc
328 // and pnacl-ld, based on the filenames found in the resource info file.
329 pp::CompletionCallback resources_cb =
330 callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad);
331 resources_->StartLoad(resources_cb);
332 }
333
ResourcesDidLoad(int32_t pp_error)334 void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) {
335 PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%"
336 NACL_PRId32 ")\n", pp_error));
337 if (pp_error != PP_OK) {
338 ReportNonPpapiError(
339 PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
340 nacl::string("The Portable Native Client (pnacl) component is not "
341 "installed. Please consult chrome://components for more "
342 "information."));
343 return;
344 }
345
346 // Okay, now that we've started the HTTP request for the pexe
347 // and we've ensured that the PNaCl compiler + metadata is installed,
348 // get the cache key from the response headers and from the
349 // compiler's version metadata.
350 nacl::string headers = streaming_downloader_->GetResponseHeaders();
351
352 temp_nexe_file_.reset(new TempFile(plugin_));
353 pp::CompletionCallback cb =
354 callback_factory_.NewCallback(&PnaclCoordinator::NexeFdDidOpen);
355 int32_t nexe_fd_err =
356 plugin_->nacl_interface()->GetNexeFd(
357 plugin_->pp_instance(),
358 streaming_downloader_->full_url().c_str(),
359 // TODO(dschuff): Get this value from the pnacl json file after it
360 // rolls in from NaCl.
361 1,
362 pnacl_options_.opt_level,
363 headers.c_str(),
364 architecture_attributes_.c_str(), // Extra compile flags.
365 &is_cache_hit_,
366 temp_nexe_file_->internal_handle(),
367 cb.pp_completion_callback());
368 if (nexe_fd_err < PP_OK_COMPLETIONPENDING) {
369 ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP, nexe_fd_err,
370 nacl::string("Call to GetNexeFd failed"));
371 }
372 }
373
NexeFdDidOpen(int32_t pp_error)374 void PnaclCoordinator::NexeFdDidOpen(int32_t pp_error) {
375 PLUGIN_PRINTF(("PnaclCoordinator::NexeFdDidOpen (pp_error=%"
376 NACL_PRId32 ", hit=%d)\n", pp_error,
377 is_cache_hit_ == PP_TRUE));
378 if (pp_error < PP_OK) {
379 ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP, pp_error,
380 nacl::string("GetNexeFd failed"));
381 return;
382 }
383
384 if (*temp_nexe_file_->internal_handle() == PP_kInvalidFileHandle) {
385 ReportNonPpapiError(
386 PP_NACL_ERROR_PNACL_CREATE_TEMP,
387 nacl::string(
388 "PnaclCoordinator: Got bad temp file handle from GetNexeFd"));
389 return;
390 }
391 HistogramEnumerateTranslationCache(plugin_->uma_interface(), is_cache_hit_);
392
393 if (is_cache_hit_ == PP_TRUE) {
394 // Cache hit -- no need to stream the rest of the file.
395 streaming_downloader_.reset(NULL);
396 // Open it for reading as the cached nexe file.
397 NexeReadDidOpen(temp_nexe_file_->Open(false));
398 } else {
399 // Open an object file first so the translator can start writing to it
400 // during streaming translation.
401 for (int i = 0; i < split_module_count_; i++) {
402 nacl::scoped_ptr<TempFile> temp_file(new TempFile(plugin_));
403 int32_t pp_error = temp_file->Open(true);
404 if (pp_error != PP_OK) {
405 ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP,
406 pp_error,
407 "Failed to open scratch object file.");
408 return;
409 } else {
410 obj_files_.push_back(temp_file.release());
411 }
412 }
413 invalid_desc_wrapper_.reset(plugin_->wrapper_factory()->MakeInvalid());
414
415 // Meanwhile, a miss means we know we need to stream the bitcode, so stream
416 // the rest of it now. (Calling BeginStreaming means that the downloader
417 // will begin handing data to the coordinator, which is safe any time after
418 // the translate_thread_ object has been initialized).
419 pp::CompletionCallback finish_cb = callback_factory_.NewCallback(
420 &PnaclCoordinator::BitcodeStreamDidFinish);
421 streaming_downloader_->BeginStreaming(finish_cb);
422
423 // Open the nexe file for connecting ld and sel_ldr.
424 // Start translation when done with this last step of setup!
425 RunTranslate(temp_nexe_file_->Open(true));
426 }
427 }
428
BitcodeStreamDidFinish(int32_t pp_error)429 void PnaclCoordinator::BitcodeStreamDidFinish(int32_t pp_error) {
430 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamDidFinish (pp_error=%"
431 NACL_PRId32 ")\n", pp_error));
432 if (pp_error != PP_OK) {
433 // Defer reporting the error and cleanup until after the translation
434 // thread returns, because it may be accessing the coordinator's
435 // objects or writing to the files.
436 translate_finish_error_ = pp_error;
437 if (pp_error == PP_ERROR_ABORTED) {
438 error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_ABORTED,
439 "PnaclCoordinator: pexe load failed (aborted).");
440 }
441 if (pp_error == PP_ERROR_NOACCESS) {
442 error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_NOACCESS,
443 "PnaclCoordinator: pexe load failed (no access).");
444 } else {
445 nacl::stringstream ss;
446 ss << "PnaclCoordinator: pexe load failed (pp_error=" << pp_error << ").";
447 error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_OTHER, ss.str());
448 }
449 translate_thread_->AbortSubprocesses();
450 } else {
451 // Compare download completion pct (100% now), to compile completion pct.
452 HistogramRatio(plugin_->uma_interface(),
453 "NaCl.Perf.PNaClLoadTime.PctCompiledWhenFullyDownloaded",
454 pexe_bytes_compiled_, pexe_size_);
455 }
456 }
457
BitcodeStreamGotData(int32_t pp_error,FileStreamData data)458 void PnaclCoordinator::BitcodeStreamGotData(int32_t pp_error,
459 FileStreamData data) {
460 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamGotData (pp_error=%"
461 NACL_PRId32 ", data=%p)\n", pp_error, data ? &(*data)[0] : 0));
462 DCHECK(translate_thread_.get());
463
464 translate_thread_->PutBytes(data, pp_error);
465 // If pp_error > 0, then it represents the number of bytes received.
466 if (data && pp_error > 0)
467 pexe_size_ += pp_error;
468 }
469
GetCallback()470 StreamCallback PnaclCoordinator::GetCallback() {
471 return callback_factory_.NewCallbackWithOutput(
472 &PnaclCoordinator::BitcodeStreamGotData);
473 }
474
BitcodeGotCompiled(int32_t pp_error,int64_t bytes_compiled)475 void PnaclCoordinator::BitcodeGotCompiled(int32_t pp_error,
476 int64_t bytes_compiled) {
477 DCHECK(pp_error == PP_OK);
478 pexe_bytes_compiled_ += bytes_compiled;
479 // If we don't know the expected total yet, ask.
480 if (expected_pexe_size_ == -1) {
481 int64_t amount_downloaded; // dummy variable.
482 streaming_downloader_->GetDownloadProgress(&amount_downloaded,
483 &expected_pexe_size_);
484 }
485 // Hold off reporting the last few bytes of progress, since we don't know
486 // when they are actually completely compiled. "bytes_compiled" only means
487 // that bytes were sent to the compiler.
488 if (expected_pexe_size_ != -1) {
489 if (!ShouldDelayProgressEvent()) {
490 GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
491 PP_NACL_EVENT_PROGRESS,
492 pexe_url_.c_str(),
493 PP_TRUE,
494 pexe_bytes_compiled_,
495 expected_pexe_size_);
496 }
497 } else {
498 GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
499 PP_NACL_EVENT_PROGRESS,
500 pexe_url_.c_str(),
501 PP_FALSE,
502 pexe_bytes_compiled_,
503 expected_pexe_size_);
504 }
505 }
506
GetCompileProgressCallback(int64_t bytes_compiled)507 pp::CompletionCallback PnaclCoordinator::GetCompileProgressCallback(
508 int64_t bytes_compiled) {
509 return callback_factory_.NewCallback(&PnaclCoordinator::BitcodeGotCompiled,
510 bytes_compiled);
511 }
512
GetCurrentProgress(int64_t * bytes_loaded,int64_t * bytes_total)513 void PnaclCoordinator::GetCurrentProgress(int64_t* bytes_loaded,
514 int64_t* bytes_total) {
515 *bytes_loaded = pexe_bytes_compiled_;
516 *bytes_total = expected_pexe_size_;
517 }
518
RunTranslate(int32_t pp_error)519 void PnaclCoordinator::RunTranslate(int32_t pp_error) {
520 PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%"
521 NACL_PRId32 ")\n", pp_error));
522 // Invoke llc followed by ld off the main thread. This allows use of
523 // blocking RPCs that would otherwise block the JavaScript main thread.
524 pp::CompletionCallback report_translate_finished =
525 callback_factory_.NewCallback(&PnaclCoordinator::TranslateFinished);
526
527 CHECK(translate_thread_ != NULL);
528 translate_thread_->RunTranslate(report_translate_finished,
529 &obj_files_,
530 temp_nexe_file_.get(),
531 invalid_desc_wrapper_.get(),
532 &error_info_,
533 resources_.get(),
534 &pnacl_options_,
535 architecture_attributes_,
536 this,
537 plugin_);
538 }
539
540 } // namespace plugin
541