blob: 1cd430cfc73c153d2ca92fc756762f3882905b75 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_
#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_
#include <set>
#include <map>
#include <vector>
#include "native_client/src/include/nacl_macros.h"
#include "native_client/src/include/nacl_string.h"
#include "native_client/src/shared/platform/nacl_sync_raii.h"
#include "native_client/src/shared/srpc/nacl_srpc.h"
#include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
#include "ppapi/c/pp_file_info.h"
#include "ppapi/c/trusted/ppb_file_io_trusted.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/file_io.h"
#include "ppapi/cpp/file_ref.h"
#include "ppapi/cpp/file_system.h"
#include "ppapi/native_client/src/trusted/plugin/callback_source.h"
#include "ppapi/native_client/src/trusted/plugin/file_downloader.h"
#include "ppapi/native_client/src/trusted/plugin/local_temp_file.h"
#include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h"
#include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
#include "ppapi/native_client/src/trusted/plugin/pnacl_options.h"
#include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h"
namespace plugin {
class Manifest;
class Plugin;
class PnaclCoordinator;
class PnaclTranslateThread;
class TempFile;
// A class invoked by Plugin to handle PNaCl client-side translation.
// Usage:
// (1) Invoke the factory method, e.g.,
// PnaclCoordinator* coord = BitcodeToNative(plugin,
// "http://foo.com/my.pexe",
// pnacl_options,
// TranslateNotifyCallback);
// (2) TranslateNotifyCallback gets invoked when translation is complete.
// If the translation was successful, the pp_error argument is PP_OK.
// Other values indicate errors.
// (3) After finish_callback runs, get the file descriptor of the translated
// nexe, e.g.,
// fd = coord->ReleaseTranslatedFD();
// (4) Load the nexe from "fd".
// (5) delete coord.
//
// Translation proceeds in two steps:
// (1) llc translates the bitcode in pexe_url_ to an object in obj_file_.
// (2) ld links the object code in obj_file_ and produces a nexe in nexe_file_.
//
// The coordinator proceeds through several states. They are
// LOAD_TRANSLATOR_BINARIES
// Complete when ResourcesDidLoad is invoked.
// OPEN_BITCODE_STREAM
// Complete when BitcodeStreamDidOpen is invoked
// GET_NEXE_FD
// Get an FD which contains the cached nexe, or is writeable for
// translation output. Complete when NexeFdDidOpen is called.
//
// If there was a cache hit, go to OPEN_NEXE_FOR_SEL_LDR, otherwise,
// continue streaming the bitcode, and:
// OPEN_TMP_FOR_LLC_TO_LD_COMMUNICATION
// Complete when ObjectFileDidOpen is invoked.
// OPEN_NEXE_FD_FOR_WRITING
// Complete when RunTranslate is invoked.
// START_LD_AND_LLC_SUBPROCESS_AND_INITIATE_TRANSLATION
// Complete when RunTranslate returns.
// TRANSLATION_COMPLETE
// Complete when TranslateFinished is invoked.
//
// If cache is enabled:
// TODO: notify browser of finished translation (and re-open read-only?)
//
// OPEN_NEXE_FOR_SEL_LDR
// Complete when NexeReadDidOpen is invoked.
class PnaclCoordinator: public CallbackSource<FileStreamData> {
public:
virtual ~PnaclCoordinator();
// The factory method for translations.
static PnaclCoordinator* BitcodeToNative(
Plugin* plugin,
const nacl::string& pexe_url,
const PnaclOptions& pnacl_options,
const pp::CompletionCallback& translate_notify_callback);
// Call this to take ownership of the FD of the translated nexe after
// BitcodeToNative has completed (and the finish_callback called).
nacl::DescWrapper* ReleaseTranslatedFD() { return translated_fd_.release(); }
// Run |translate_notify_callback_| with an error condition that is not
// PPAPI specific. Also set ErrorInfo report.
void ReportNonPpapiError(PluginErrorCode err, const nacl::string& message);
// Run when faced with a PPAPI error condition. Bring control back to the
// plugin by invoking the |translate_notify_callback_|.
// Also set ErrorInfo report.
void ReportPpapiError(PluginErrorCode err,
int32_t pp_error, const nacl::string& message);
// Bring control back to the plugin by invoking the
// |translate_notify_callback_|. This does not set the ErrorInfo report,
// it is assumed that it was already set.
void ExitWithError();
// Implement FileDownloader's template of the CallbackSource interface.
// This method returns a callback which will be called by the FileDownloader
// to stream the bitcode data as it arrives. The callback
// (BitcodeStreamGotData) passes it to llc over SRPC.
StreamCallback GetCallback();
// Return a callback that should be notified when |bytes_compiled| bytes
// have been compiled.
pp::CompletionCallback GetCompileProgressCallback(int64_t bytes_compiled);
// Get the last known load progress.
void GetCurrentProgress(int64_t* bytes_loaded, int64_t* bytes_total);
// Return true if the total progress to report (w/ progress events) is known.
bool ExpectedProgressKnown() { return expected_pexe_size_ != -1; }
// Return true if we should delay the progress event reporting.
// This delay approximates:
// - the size of the buffer of bytes sent but not-yet-compiled by LLC.
// - the linking time.
bool ShouldDelayProgressEvent() {
const uint32_t kProgressEventSlopPct = 5;
return ((expected_pexe_size_ - pexe_bytes_compiled_) * 100 /
expected_pexe_size_) < kProgressEventSlopPct;
}
private:
NACL_DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator);
// BitcodeToNative is the factory method for PnaclCoordinators.
// Therefore the constructor is private.
PnaclCoordinator(Plugin* plugin,
const nacl::string& pexe_url,
const PnaclOptions& pnacl_options,
const pp::CompletionCallback& translate_notify_callback);
// Callback for when the resource info JSON file has been read.
void ResourceInfoWasRead(int32_t pp_error);
// Callback for when llc and ld have been downloaded.
void ResourcesDidLoad(int32_t pp_error);
// Callbacks for temporary file related stages.
// They are invoked from ResourcesDidLoad and proceed in declaration order.
// Invoked when the temporary file system is successfully opened in PPAPI.
void FileSystemDidOpen(int32_t pp_error);
// Invoked after we are sure the PNaCl temporary directory exists.
void DirectoryWasCreated(int32_t pp_error);
// Invoke to issue a GET request for bitcode.
void OpenBitcodeStream();
// Invoked when we've started an URL fetch for the pexe to check for
// caching metadata.
void BitcodeStreamDidOpen(int32_t pp_error);
// Invoked when we've gotten a temp FD for the nexe, either with the nexe
// data, or a writeable fd to save to.
void NexeFdDidOpen(int32_t pp_error);
// Invoked after we have checked the PNaCl cache for a translated version.
void CachedFileDidOpen(int32_t pp_error);
// Invoked when a pexe data chunk arrives (when using streaming translation)
void BitcodeStreamGotData(int32_t pp_error, FileStreamData data);
// Invoked when a pexe data chunk is compiled.
void BitcodeGotCompiled(int32_t pp_error, int64_t bytes_compiled);
// Invoked when the pexe download finishes (using streaming translation)
void BitcodeStreamDidFinish(int32_t pp_error);
// Invoked when the write descriptor for obj_file_ is created.
void ObjectFileDidOpen(int32_t pp_error);
// Once llc and ld nexes have been loaded and the two temporary files have
// been created, this starts the translation. Translation starts two
// subprocesses, one for llc and one for ld.
void RunTranslate(int32_t pp_error);
// Invoked when translation is finished.
void TranslateFinished(int32_t pp_error);
// If the cache is enabled, open a cache file for write, then copy
// the nexe data from temp_nexe_file_ to> cached_nexe_file_.
// Once the copy is done, we commit it to the cache by renaming the
// cache file to the final name.
void CachedNexeOpenedForWrite(int32_t pp_error);
void DidCopyNexeToCachePartial(int32_t pp_error, int32_t num_read_prev,
int64_t cur_offset);
void NexeWasCopiedToCache(int32_t pp_error);
// If the copy of the nexe to the not-yet-committed-to-cache file
// failed after partial writes, we attempt to delete the partially written
// file. This callback is invoked when the delete is completed.
void CorruptCacheFileWasDeleted(int32_t delete_pp_error,
int32_t orig_pp_error);
// Invoked when the nexe_file_ temporary has been renamed to the nexe name.
void NexeFileWasRenamed(int32_t pp_error);
// Invoked when the read descriptor for nexe_file_ is created.
void NexeReadDidOpen(int32_t pp_error);
// Keeps track of the pp_error upon entry to TranslateFinished,
// for inspection after cleanup.
int32_t translate_finish_error_;
// The plugin owning the nexe for which we are doing translation.
Plugin* plugin_;
pp::CompletionCallback translate_notify_callback_;
// Threadsafety is required to support file lookups.
pp::CompletionCallbackFactory<PnaclCoordinator,
pp::ThreadSafeThreadTraits> callback_factory_;
// Nexe from the final native Link.
nacl::scoped_ptr<nacl::DescWrapper> translated_fd_;
// Translation creates local temporary files.
nacl::scoped_ptr<pp::FileSystem> file_system_;
// The manifest used by resource loading and ld + llc's reverse service
// to look up objects and libraries.
nacl::scoped_ptr<const Manifest> manifest_;
// An auxiliary class that manages downloaded resources (llc and ld nexes).
nacl::scoped_ptr<PnaclResources> resources_;
// State used for querying the temporary directory.
nacl::scoped_ptr<pp::FileRef> dir_ref_;
// The URL for the pexe file.
nacl::string pexe_url_;
// Options for translation.
PnaclOptions pnacl_options_;
// Object file, produced by the translator and consumed by the linker.
nacl::scoped_ptr<TempFile> obj_file_;
// Translated nexe file, produced by the linker.
nacl::scoped_ptr<TempFile> temp_nexe_file_;
// Cached nexe file, consumed by sel_ldr. This will be NULL if we do
// not have a writeable cache file. That is currently the case when
// off_the_record_ is true.
nacl::scoped_ptr<LocalTempFile> cached_nexe_file_;
// True if the new cache flow is enabled. Currently set by an environment
// variable on construction. TODO(dschuff): remove old cache stuff.
bool use_new_cache_;
// Passed to the browser, which sets it to true if there is a translation
// cache hit.
PP_Bool is_cache_hit_;
// Passed to the browser, which sets it to the handle for the nexe file
// (either the translated nexe from the cache, or a temp file to write to).
PP_FileHandle nexe_handle_;
// Downloader for streaming translation
nacl::scoped_ptr<FileDownloader> streaming_downloader_;
// Used to report information when errors (PPAPI or otherwise) are reported.
ErrorInfo error_info_;
// True if an error was already reported, and translate_notify_callback_
// was already run/consumed.
bool error_already_reported_;
// True if compilation is off_the_record.
bool off_the_record_;
// State for timing and size information for UMA stats.
int64_t pnacl_init_time_;
int64_t pexe_size_; // Count as we stream -- will converge to pexe size.
int64_t pexe_bytes_compiled_; // Count as we compile.
int64_t expected_pexe_size_; // Expected download total (-1 if unknown).
// The helper thread used to do translations via SRPC.
// Keep this last in declaration order to ensure the other variables
// haven't been destroyed yet when its destructor runs.
nacl::scoped_ptr<PnaclTranslateThread> translate_thread_;
};
//----------------------------------------------------------------------
} // namespace plugin;
#endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_