Chromium Code Reviews| Index: ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h |
| =================================================================== |
| --- ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h (revision 114253) |
| +++ ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h (working copy) |
| @@ -12,169 +12,288 @@ |
| #include "native_client/src/include/nacl_macros.h" |
| #include "native_client/src/include/nacl_string.h" |
| #include "native_client/src/shared/platform/nacl_sync_checked.h" |
| +#include "native_client/src/shared/platform/nacl_sync_raii.h" |
| #include "native_client/src/shared/platform/nacl_threads.h" |
| #include "native_client/src/shared/srpc/nacl_srpc.h" |
| +#include "native_client/src/trusted/desc/nacl_desc_rng.h" |
| #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" |
| #include "native_client/src/trusted/plugin/delayed_callback.h" |
| #include "native_client/src/trusted/plugin/nacl_subprocess.h" |
| #include "native_client/src/trusted/plugin/plugin_error.h" |
| #include "native_client/src/trusted/plugin/pnacl_resources.h" |
| +#include "ppapi/c/pp_file_info.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" |
| struct NaClMutex; |
| +struct PPB_FileIOTrusted; |
| namespace plugin { |
| class Plugin; |
| class PnaclCoordinator; |
| -struct PnaclTranslationUnit { |
| - PnaclTranslationUnit(PnaclCoordinator* coord) |
| - : coordinator(coord), |
| - obj_len(-1), |
| - is_shared_library(false), |
| - soname(""), |
| - lib_dependencies("") { |
| - } |
| - // Punch hole in abstraction. |
| - PnaclCoordinator* coordinator; |
| +// Translation creates two temporary files. The first temporary file holds |
| +// the object file created by llc. The second holds the nexe produced by |
| +// the linker. Both of these temporary files are used to both write and |
| +// read according to the following matrix: |
| +// |
| +// PnaclCoordinator::obj_file_: |
| +// written by: llc (passed in explicitly through SRPC) |
| +// read by: ld (returned via lookup service from SRPC) |
| +// PnaclCoordinator::nexe_file_: |
| +// written by: lc (passed in explicitly through SRPC) |
| +// read by: sel_ldr (passed in explicitly to command channel) |
| +// |
| - // Borrowed reference which must outlive the thread. |
| - nacl::scoped_ptr<nacl::DescWrapper> pexe_wrapper; |
| +// PnaclFileDescPair represents a file used as a temporary between stages in |
| +// translation. It is created in the local temporary file system of the page |
| +// being processed. The name of the temporary file is a random 32-character |
| +// hex string. Because both reading and writing are necessary, two I/O objects |
| +// for the file are opened. |
| +class PnaclFileDescPair { |
| + public: |
| + PnaclFileDescPair(Plugin* plugin, |
| + pp::FileSystem* file_system, |
| + PnaclCoordinator* coordinator); |
| + ~PnaclFileDescPair(); |
| + // Opens a pair of file IO objects referring to a randomly named file in |
| + // file_system_. One IO is for writing the file and another for reading it. |
| + void Open(const pp::CompletionCallback& cb); |
| + // Accessors. |
| + // The nacl::DescWrapper* for the writeable version of the file. |
| + nacl::DescWrapper* write_wrapper() { return write_wrapper_.get(); } |
| + // The nacl::DescWrapper* for the read-only version of the file. |
| + nacl::DescWrapper* read_wrapper() { return read_wrapper_.get(); } |
| - // Object file produced by translator and consumed by the linker. |
| - nacl::scoped_ptr<nacl::DescWrapper> obj_wrapper; |
| - int32_t obj_len; |
| + private: |
| + NACL_DISALLOW_COPY_AND_ASSIGN(PnaclFileDescPair); |
| - // Information extracted from the pexe that is needed by the linker. |
| - bool is_shared_library; |
| - nacl::string soname; |
| - nacl::string lib_dependencies; |
| + // Gets the POSIX file descriptor for a resource. |
| + int32_t GetFD(int32_t pp_error, |
| + const pp::Resource& resource, |
| + bool is_writable); |
| + // Called when the writable file IO was opened. |
| + void WriteFileDidOpen(int32_t pp_error); |
| + // Called when the readable file IO was opened. |
| + void ReadFileDidOpen(int32_t pp_error); |
| - // The translated user nexe file. |
| - nacl::scoped_ptr<nacl::DescWrapper> nexe_wrapper; |
| + Plugin* plugin_; |
| + pp::FileSystem* file_system_; |
| + PnaclCoordinator* coordinator_; |
| + const PPB_FileIOTrusted* file_io_trusted_; |
| + pp::CompletionCallbackFactory<PnaclFileDescPair> callback_factory_; |
| + nacl::string filename_; |
| + // The PPAPI and wrapper state for the writeable file. |
| + nacl::scoped_ptr<pp::FileRef> write_ref_; |
| + nacl::scoped_ptr<pp::FileIO> write_io_; |
| + nacl::scoped_ptr<nacl::DescWrapper> write_wrapper_; |
| + // The PPAPI and wrapper state for the read-only file. |
| + nacl::scoped_ptr<pp::FileRef> read_ref_; |
| + nacl::scoped_ptr<pp::FileIO> read_io_; |
| + nacl::scoped_ptr<nacl::DescWrapper> read_wrapper_; |
| + // The callback invoked when both file I/O objects are created. |
| + pp::CompletionCallback done_callback_; |
| + // Random number generator used to create filenames. |
| + struct NaClDescRng rng_desc_; |
| +}; |
| - // Callbacks to run when tasks or completed or an error has occurred. |
| - pp::CompletionCallback translate_done_cb; |
| - pp::CompletionCallback link_done_cb; |
| +// A thread safe reference counting class Needed for CompletionCallbackFactory |
| +// in PnaclCoordinator. |
| +class PnaclRefCount { |
| + public: |
| + PnaclRefCount() : ref_(0) { NaClXMutexCtor(&mu_); } |
| + ~PnaclRefCount() { NaClMutexDtor(&mu_); } |
| + int32_t AddRef() { |
| + nacl::MutexLocker ml(&mu_); |
| + return ++ref_; |
| + } |
| + int32_t Release() { |
| + nacl::MutexLocker ml(&mu_); |
| + return --ref_; |
| + } |
| - ErrorInfo error_info; |
| + private: |
| + int32_t ref_; |
| + struct NaClMutex mu_; |
| }; |
| - |
| -typedef std::pair<nacl::string, pp::CompletionCallback> url_callback_pair; |
| - |
| -// A class that handles PNaCl client-side translation. |
| +// A class invoked by Plugin to handle PNaCl client-side translation. |
| // Usage: |
| -// (1) Initialize(); |
| -// (2) BitcodeToNative(bitcode, ..., finish_callback); |
| -// (3) After finish_callback runs, do: |
| -// fd = ReleaseTranslatedFD(); |
| -// (4) go ahead and load the nexe from "fd" |
| -// (5) delete |
| +// (1) Invoke the factory method, e.g., |
| +// PnaclCoordinator* coord = BitcodeToNative(plugin, |
| +// "http://foo.com/my.pexe", |
| +// 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_. |
| +// |
| +// It should be noted that at the moment we are not properly freeing the |
| +// PPAPI resources used for the temporary files used in translation. Until |
| +// that is fixed, (4) and (5) should be done in that order. |
| +// TODO(sehr): Fix freeing of temporary files. |
| class PnaclCoordinator { |
| public: |
| - PnaclCoordinator() |
| - : plugin_(NULL), |
| - translate_notify_callback_(pp::BlockUntilComplete()), |
| - llc_subprocess_(NULL), |
| - ld_subprocess_(NULL), |
| - subprocesses_should_die_(false) { |
| - NaClXMutexCtor(&subprocess_mu_); |
| - } |
| - |
| virtual ~PnaclCoordinator(); |
| - // Initialize() can only be called once during the lifetime of this instance. |
| - void Initialize(Plugin* instance); |
| + // The factory method for translations. |
| + static PnaclCoordinator* BitcodeToNative( |
| + Plugin* plugin, |
| + const nacl::string& pexe_url, |
| + const pp::CompletionCallback& translate_notify_callback); |
| - void BitcodeToNative(const nacl::string& pexe_url, |
| - const pp::CompletionCallback& finish_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(); |
| - } |
| + nacl::DescWrapper* ReleaseTranslatedFD() { return translated_fd_.release(); } |
| + // Looks up a file descriptor for an url that was already downloaded. |
| + // This is used for getting the descriptor for llc and ld nexes as well |
| + // as the libraries and object files used by the linker. |
| int32_t GetLoadedFileDesc(int32_t pp_error, |
| const nacl::string& url, |
| const nacl::string& component); |
| - // Run when faced with a PPAPI error condition. It brings control back to the |
| - // plugin by invoking the |translate_notify_callback_|. |
| - void PnaclPpapiError(int32_t pp_error); |
| // Run |translate_notify_callback_| with an error condition that is not |
| // PPAPI specific. |
| - void PnaclNonPpapiError(); |
| - // Wrapper for Plugin ReportLoadAbort. |
| - void ReportLoadAbort(); |
| - // Wrapper for Plugin ReportLoadError. |
| - void ReportLoadError(const ErrorInfo& error); |
| + void ReportNonPpapiError(const nacl::string& message); |
| + // Run when faced with a PPAPI error condition. Bring control back to the |
| + // plugin by invoking the |translate_notify_callback_|. |
| + void ReportPpapiError(int32_t pp_error, const nacl::string& message); |
| + void ReportPpapiError(int32_t pp_error); |
| - // Accessors for use by helper threads. |
| - nacl::string resource_base_url() const { return resource_base_url_; } |
| - Plugin* plugin() const { return plugin_; } |
| - nacl::string llc_url() const { return llc_url_; } |
| - NaClSubprocess* llc_subprocess() const { return llc_subprocess_; } |
| - bool StartLlcSubProcess(); |
| - nacl::string ld_url() const { return ld_url_; } |
| - NaClSubprocess* ld_subprocess() const { return ld_subprocess_; } |
| - bool StartLdSubProcess(); |
| - bool SubprocessesShouldDie(); |
| - void SetSubprocessesShouldDie(bool subprocesses_should_die); |
| - PnaclResources* resources() const { return resources_.get(); } |
| + private: |
| + NACL_DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator); |
| - protected: |
| + // BitcodeToNative is the factory method for PnaclCoordinators. |
| + // Therefore the constructor is private. |
| + PnaclCoordinator(Plugin* plugin, |
| + const nacl::string& pexe_url, |
| + const pp::CompletionCallback& translate_notify_callback, |
| + const nacl::string& resource_base_url); |
| - // Callbacks for when various files, etc. have been downloaded. |
| - void ResourcesDidLoad(int32_t pp_error, |
| - const nacl::string& url, |
| - PnaclTranslationUnit* translation_unit); |
| + // Callback for when llc and ld have been downloaded. |
| + // This is the first callback invoked in response to BitcodeToNative. |
| + void ResourcesDidLoad(int32_t pp_error); |
| - // Callbacks for compute-based translation steps. |
| - void RunTranslate(int32_t pp_error, |
| - const nacl::string& url, |
| - PnaclTranslationUnit* translation_unit); |
| - void RunLink(int32_t pp_error, PnaclTranslationUnit* translation_unit); |
| + // 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 when the obj_file_ temporary file I/O pair is created. |
| + void ObjectPairDidOpen(int32_t pp_error); |
| + // Invoked when the nexe_file_ temporary file I/O pair is created. |
| + void NexePairDidOpen(int32_t pp_error); |
| - // Pnacl translation completed normally. |
| - void PnaclDidFinish(int32_t pp_error, PnaclTranslationUnit* translation_unit); |
| + // 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); |
| + // Starts an individual llc or ld subprocess used for translation. |
| + NaClSubprocess* StartSubprocess(const nacl::string& url); |
| + // PnaclCoordinator creates a helper thread to allow translations to be |
| + // invoked via SRPC. This is the helper thread function for translation. |
| + static void WINAPI DoTranslateThread(void* arg); |
| + // Returns true if a the translate thread and subprocesses should stop. |
| + bool SubprocessesShouldDie(); |
| + // Signal the translate thread and subprocesses that they should stop. |
| + void SetSubprocessesShouldDie(bool subprocesses_should_die); |
| + // Signal that Pnacl translation completed normally. |
| + void PnaclDidFinish(int32_t pp_error); |
| + // Signal that Pnacl translation failed. |
|
jvoung - send to chromium...
2011/12/13 21:35:49
"from the translation thread" only?
sehr (please use chromium)
2011/12/14 16:34:20
Done.
|
| + void PnaclFailed(const nacl::string& error_string); |
| - private: |
| - NACL_DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator); |
| + // Support for file lookups needed for ld. |
| + // TODO(sehr): remove this when file lookup is through ReverseService. |
| + // Invoked on the main thread on behalf of the lookup service to start |
| + // loading a particular URL. |
| + void LoadOneFile(int32_t pp_error, |
| + const nacl::string& url, |
| + nacl::DescWrapper** wrapper, |
| + pp::CompletionCallback& done_cb); |
| + // Invoked by the renderer when the file was loaded. |
| + void DidLoadFile(int32_t pp_error, |
| + const nacl::string& full_url, |
| + nacl::DescWrapper** wrapper, |
| + pp::CompletionCallback& done_cb); |
| + // Signals the waiting lookup service to resume. |
| + void ResumeLookup(int32_t pp_error); |
| + // The plugin owning the nexe for which we are doing translation. |
| Plugin* plugin_; |
| + |
| pp::CompletionCallback translate_notify_callback_; |
| - pp::CompletionCallbackFactory<PnaclCoordinator> callback_factory_; |
| + // PnaclRefCount is only needed to support file lookups. |
| + // TODO(sehr): remove this when file lookup is through ReverseService. |
| + pp::CompletionCallbackFactory<PnaclCoordinator, |
| + PnaclRefCount> callback_factory_; |
| // URLs used to lookup downloaded resources. |
| nacl::string resource_base_url_; |
| - nacl::string llc_url_; |
| - nacl::string ld_url_; |
| // Helper subprocesses loaded by the plugin (deleted by the plugin). |
| - // We may want to do cleanup ourselves when we are in the |
| - // business of compiling multiple bitcode objects / libraries, and |
| - // if we truly cannot reuse existing loaded subprocesses. |
| + // A nacl sandbox running the llc nexe. |
| NaClSubprocess* llc_subprocess_; |
| + // A nacl sandbox running the ld nexe. |
| NaClSubprocess* ld_subprocess_; |
| + // True if the translation thread and subprocesses should exit. |
| bool subprocesses_should_die_; |
| + // Used to guard and publish subprocesses_should_die_. |
| struct NaClMutex subprocess_mu_; |
| // Nexe from the final native Link. |
| nacl::scoped_ptr<nacl::DescWrapper> translated_fd_; |
| - // Perhaps make this a single thread that invokes (S)RPCs followed by |
| - // callbacks based on a Queue of requests. A generic mechanism would make |
| - // it easier to add steps later (the mechanism could look like PostMessage?). |
| - nacl::scoped_ptr<PnaclTranslationUnit> translation_unit_; |
| + // The helper thread used to do translations via SRPC. |
| nacl::scoped_ptr<NaClThread> translate_thread_; |
| - nacl::scoped_ptr<NaClThread> link_thread_; |
| + // Translation creates local temporary files. |
| + nacl::scoped_ptr<pp::FileSystem> file_system_; |
| + // An auxiliary class that manages downloaded resources (llc and ld nexes). |
| + nacl::scoped_ptr<PnaclResources> resources_; |
| - // An auxiliary class that manages downloaded resources. |
| - nacl::scoped_ptr<PnaclResources> resources_; |
| + // The URL for the pexe file. |
| + nacl::string pexe_url_; |
| + // Borrowed reference which must outlive the thread. |
| + nacl::scoped_ptr<nacl::DescWrapper> pexe_wrapper_; |
| + // Object file, produced by the translator and consumed by the linker. |
| + nacl::scoped_ptr<PnaclFileDescPair> obj_file_; |
| + // Translated nexe file, produced by the linker and consumed by sel_ldr. |
| + nacl::scoped_ptr<PnaclFileDescPair> nexe_file_; |
| + // Callbacks to run when tasks or completed or an error has occurred. |
| + pp::CompletionCallback translate_done_cb_; |
| + |
| + // Used to report information when errors (PPAPI or otherwise) are reported. |
| + ErrorInfo error_info_; |
| + |
| + // Support for file lookups (obsolescent). |
| + // The SRPC file lookup service for ld. |
| + static void LookupInputFile(NaClSrpcRpc* rpc, |
| + NaClSrpcArg** inputs, |
| + NaClSrpcArg** outputs, |
| + NaClSrpcClosure* done); |
| + static NaClSrpcHandlerDesc lookup_methods[]; |
| + |
| + // Used by the SRPC file lookup service for ld. |
| + // Looks up url and returns the read-only file descriptor for it. |
| + // If url is the specially designated filename for the translated object |
| + // file, it returns obj_file_.read_wrapper(). Otherwise the lookup causes |
| + // the download of the requested resource via Plugin::StreamAsFile. |
| + struct NaClDesc* LookupDesc(const nacl::string& url); |
| + |
| + struct NaClMutex lookup_service_mu_; |
| + struct NaClCondVar lookup_service_cv_; |
| + bool lookup_is_complete_; |
| }; |
| //---------------------------------------------------------------------- |