diff options
author | sehr@google.com <sehr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-10 01:31:37 +0000 |
---|---|---|
committer | sehr@google.com <sehr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-10 01:31:37 +0000 |
commit | 063b841e1b7462f9af20d8a5e1613c0effe97a72 (patch) | |
tree | ba6da251d9264d3bfec6e125c909ca11bec0f7fe | |
parent | 4585ed7d8bf3417c6470a44b03d8a007dbc24974 (diff) | |
download | chromium_src-063b841e1b7462f9af20d8a5e1613c0effe97a72.zip chromium_src-063b841e1b7462f9af20d8a5e1613c0effe97a72.tar.gz chromium_src-063b841e1b7462f9af20d8a5e1613c0effe97a72.tar.bz2 |
Refactor the pnacl coordinator to load resources all at once, then load
the pexe. This will allow separating these tasks more cleanly, and also
makes the translation of individual pexes/psos more cleanly separated from
the common portions.
BUG= http://code.google.com/p/nativeclient/issues/detail?id=2409
TEST= run_pnacl_example_browser_test
Review URL: http://codereview.chromium.org/8490018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109359 0039d316-1c4b-4281-b951-d872f2087c98
6 files changed, 362 insertions, 385 deletions
diff --git a/ppapi/native_client/src/trusted/plugin/build.scons b/ppapi/native_client/src/trusted/plugin/build.scons index 40828d8..15c6f71 100644 --- a/ppapi/native_client/src/trusted/plugin/build.scons +++ b/ppapi/native_client/src/trusted/plugin/build.scons @@ -67,6 +67,7 @@ common_inputs = [ 'nexe_arch.cc', 'plugin.cc', 'pnacl_coordinator.cc', + 'pnacl_resources.cc', 'pnacl_srpc_lib.cc', 'scriptable_handle.cc', 'service_runtime.cc', diff --git a/ppapi/native_client/src/trusted/plugin/plugin.gypi b/ppapi/native_client/src/trusted/plugin/plugin.gypi index 4aa6900..94cc158 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.gypi +++ b/ppapi/native_client/src/trusted/plugin/plugin.gypi @@ -16,6 +16,7 @@ 'nexe_arch.cc', 'plugin.cc', 'pnacl_coordinator.cc', + 'pnacl_resources.cc', 'pnacl_srpc_lib.cc', 'scriptable_handle.cc', 'service_runtime.cc', diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc index a402aed..9a947fa 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc @@ -9,6 +9,7 @@ #include "native_client/src/include/portability_io.h" #include "native_client/src/shared/platform/nacl_check.h" +#include "native_client/src/shared/platform/nacl_sync_raii.h" #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" #include "native_client/src/trusted/plugin/browser_interface.h" #include "native_client/src/trusted/plugin/nacl_subprocess.h" @@ -32,11 +33,6 @@ namespace plugin { class Plugin; -void PnaclResources::AddFDForUrl(const nacl::string& url, int32_t fd) { - resource_wrappers_[url] = - plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); -} - void PnaclCoordinator::Initialize(Plugin* plugin) { PLUGIN_PRINTF(("PnaclCoordinator::Initialize (this=%p)\n", static_cast<void*>(this))); @@ -44,7 +40,8 @@ void PnaclCoordinator::Initialize(Plugin* plugin) { CHECK(plugin_ == NULL); // Can only initialize once. plugin_ = plugin; callback_factory_.Initialize(this); - resources_.reset(new PnaclResources(plugin)); + resources_.reset(new PnaclResources(plugin, this)); + resources_->Initialize(); } PnaclCoordinator::~PnaclCoordinator() { @@ -62,9 +59,6 @@ PnaclCoordinator::~PnaclCoordinator() { if (link_thread_.get() != NULL) { NaClThreadJoin(link_thread_.get()); } - - // Delete all delayed_callbacks. - delayed_callbacks.erase(delayed_callbacks.begin(), delayed_callbacks.end()); } void PnaclCoordinator::ReportLoadAbort() { @@ -87,22 +81,21 @@ void PnaclCoordinator::PnaclNonPpapiError() { void PnaclCoordinator::PnaclDidFinish(int32_t pp_error, PnaclTranslationUnit* translation_unit) { - UNREFERENCED_PARAMETER(translation_unit); PLUGIN_PRINTF(("PnaclCoordinator::PnaclDidFinish (pp_error=%" NACL_PRId32")\n", pp_error)); + if (pp_error != PP_OK) { + ReportLoadError(translation_unit->error_info); + PnaclPpapiError(pp_error); + return; + } + // Transfer ownership of the nexe wrapper to the coordinator. + translated_fd_.reset(translation_unit->nexe_wrapper.release()); + plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); translate_notify_callback_.Run(pp_error); } ////////////////////////////////////////////////////////////////////// -DelayedCallback* -PnaclCoordinator::MakeDelayedCallback(pp::CompletionCallback cb, - uint32_t num_deps) { - DelayedCallback* delayed_callback = new DelayedCallback(cb, num_deps); - delayed_callbacks.insert(delayed_callback); - return delayed_callback; -} - int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error, const nacl::string& url, const nacl::string& component) { @@ -131,108 +124,52 @@ int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error, return file_desc_ok_to_close; } -NaClSubprocessId PnaclCoordinator::HelperNexeDidLoad(int32_t fd, - ErrorInfo* error_info) { - // Inform JavaScript that we successfully loaded a helper nexe. - plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); - nacl::scoped_ptr<nacl::DescWrapper> - wrapper(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); - - return plugin_->LoadHelperNaClModule(wrapper.get(), error_info); -} - -////////////////////////////////////////////////////////////////////// -// First few callbacks. - -void PnaclCoordinator::LLCReady(int32_t pp_error, - const nacl::string& llc_url, - DelayedCallback* delayed_callback) { - // pp_error is checked by GetLoadedFileDesc. - int32_t file_desc_ok_to_close = GetLoadedFileDesc(pp_error, llc_url, "llc"); +bool PnaclCoordinator::StartLlcSubProcess() { ErrorInfo error_info; - if (file_desc_ok_to_close < 0) { - PnaclPpapiError(pp_error); - return; - } - NaClSubprocessId llc_id = - HelperNexeDidLoad(file_desc_ok_to_close, &error_info); - PLUGIN_PRINTF(("PnaclCoordinator::LLCReady (pp_error=%" - NACL_PRId32" nexe_id=%" - NACL_PRId32")\n", - pp_error, - llc_id)); + nacl::DescWrapper* wrapper = resources_->WrapperForUrl(llc_url_); + NaClSubprocessId llc_id = plugin_->LoadHelperNaClModule(wrapper, &error_info); + PLUGIN_PRINTF(("PnaclCoordinator::StartLlcSubProcess (nexe_id=%" + NACL_PRId32")\n", llc_id)); if (kInvalidNaClSubprocessId == llc_id) { - error_info.SetReport(ERROR_UNKNOWN, - "Could not load pnacl compiler nexe"); + error_info.SetReport(ERROR_UNKNOWN, "Could not load pnacl compiler nexe"); ReportLoadError(error_info); PnaclNonPpapiError(); - return; + return NULL; } - llc_subprocess_ = plugin_ ->nacl_subprocess(llc_id); - delayed_callback->RunIfTime(); + llc_subprocess_ = plugin_->nacl_subprocess(llc_id); + return (llc_subprocess_ != NULL); } -void PnaclCoordinator::LDReady(int32_t pp_error, - const nacl::string& ld_url, - DelayedCallback* delayed_callback) { - // pp_error is checked by GetLoadedFileDesc. - int32_t file_desc_ok_to_close = GetLoadedFileDesc(pp_error, ld_url, "ld"); +bool PnaclCoordinator::StartLdSubProcess() { ErrorInfo error_info; - if (file_desc_ok_to_close < 0) { - PnaclPpapiError(pp_error); - return; - } - NaClSubprocessId ld_id = - HelperNexeDidLoad(file_desc_ok_to_close, &error_info); - PLUGIN_PRINTF(("PnaclCoordinator::LDReady (pp_error=%" - NACL_PRId32" nexe_id=%" - NACL_PRId32")\n", - pp_error, - ld_id)); + nacl::DescWrapper* wrapper = resources_->WrapperForUrl(ld_url_); + NaClSubprocessId ld_id = plugin_->LoadHelperNaClModule(wrapper, &error_info); + PLUGIN_PRINTF(("PnaclCoordinator::StartLdSubProcess (nexe_id=%" + NACL_PRId32")\n", ld_id)); if (kInvalidNaClSubprocessId == ld_id) { - error_info.SetReport(ERROR_UNKNOWN, - "Could not load pnacl linker nexe"); + error_info.SetReport(ERROR_UNKNOWN, "Could not load pnacl linker nexe"); ReportLoadError(error_info); PnaclNonPpapiError(); - return; + return NULL; } - ld_subprocess_ = plugin_ ->nacl_subprocess(ld_id); - delayed_callback->RunIfTime(); + ld_subprocess_ = plugin_->nacl_subprocess(ld_id); + return (ld_subprocess_ != NULL); } -void PnaclCoordinator::LinkResourceReady(int32_t pp_error, - const nacl::string& url, - DelayedCallback* delayed_callback) { - PLUGIN_PRINTF(("PnaclCoordinator::LinkResourceReady (pp_error=%" - NACL_PRId32", url=%s)\n", pp_error, url.c_str())); - // pp_error is checked by GetLoadedFileDesc. - int32_t fd = GetLoadedFileDesc(pp_error, url, "linker resource " + url); - if (fd < 0) { - PnaclPpapiError(pp_error); - } else { - resources_->AddFDForUrl(url, fd); - delayed_callback->RunIfTime(); - } +bool PnaclCoordinator::SubprocessesShouldDie() { + nacl::MutexLocker ml(&subprocess_mu_); + return subprocesses_should_die_; } -void PnaclCoordinator::PexeReady(int32_t pp_error, - const nacl::string& pexe_url, - PnaclTranslationUnit* translation_unit, - DelayedCallback* delayed_callback) { - PLUGIN_PRINTF(("PnaclCoordinator::PexeReady (pp_error=%" - NACL_PRId32")\n", pp_error)); - // pp_error is checked by GetLoadedFileDesc. - int32_t fd = GetLoadedFileDesc(pp_error, pexe_url, "pexe"); - if (fd < 0) { - PnaclPpapiError(pp_error); - } else { - translation_unit->pexe_wrapper.reset( - plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); - delayed_callback->RunIfTime(); - } +void PnaclCoordinator::SetSubprocessesShouldDie(bool subprocesses_should_die) { + nacl::MutexLocker ml(&subprocess_mu_); + subprocesses_should_die_ = subprocesses_should_die; } ////////////////////////////////////////////////////////////////////// +// First few callbacks. + +////////////////////////////////////////////////////////////////////// namespace { void AbortTranslateThread(PnaclTranslationUnit* translation_unit, @@ -353,52 +290,50 @@ void WINAPI DoTranslateThread(void* arg) { } // namespace -void -PnaclCoordinator::RunTranslateDidFinish(int32_t pp_error, - PnaclTranslationUnit* translation_unit, - DelayedCallback* link_callback) { - PLUGIN_PRINTF(("PnaclCoordinator::RunTranslateDidFinish (pp_error=%" +void PnaclCoordinator::RunTranslate(int32_t pp_error, + const nacl::string& pexe_url, + PnaclTranslationUnit* translation_unit) { + PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%" NACL_PRId32")\n", pp_error)); - if (pp_error != PP_OK) { - ReportLoadError(translation_unit->error_info); + // pp_error is checked by GetLoadedFileDesc. + int32_t fd = GetLoadedFileDesc(pp_error, pexe_url, "pexe"); + if (fd < 0) { PnaclPpapiError(pp_error); return; } - plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); - link_callback->RunIfTime(); -} - -void PnaclCoordinator::RunTranslate(int32_t pp_error, - PnaclTranslationUnit* translation_unit, - DelayedCallback* delayed_link_callback) { - PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%" - NACL_PRId32")\n", pp_error)); - assert(PP_OK == pp_error); - + translation_unit->pexe_wrapper.reset( + plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); + if (!StartLlcSubProcess()) { + ErrorInfo error_info; + error_info.SetReport(ERROR_UNKNOWN, + "Could not start compiler subprocess\n"); + ReportLoadError(error_info); + PnaclNonPpapiError(); + return; + } // Invoke llvm asynchronously. - // RunTranslateDidFinish runs on the main thread when llvm is done. + // RunLink runs on the main thread when llvm is done. translation_unit->translate_done_cb = - callback_factory_.NewCallback(&PnaclCoordinator::RunTranslateDidFinish, - translation_unit, - delayed_link_callback); + callback_factory_.NewCallback(&PnaclCoordinator::RunLink, + translation_unit); translate_thread_.reset(new NaClThread); - if (translate_thread_ != NULL) { - if (!NaClThreadCreateJoinable(translate_thread_.get(), - DoTranslateThread, - translation_unit, - kArbitraryStackSize)) { - ErrorInfo error_info; - error_info.SetReport(ERROR_UNKNOWN, - "Could not create a translator thread.\n"); - ReportLoadError(error_info); - PnaclNonPpapiError(); - } - } else { + if (translate_thread_ == NULL) { ErrorInfo error_info; error_info.SetReport(ERROR_UNKNOWN, "Could not allocate DoTranslateThread()\n"); ReportLoadError(error_info); PnaclNonPpapiError(); + return; + } + if (!NaClThreadCreateJoinable(translate_thread_.get(), + DoTranslateThread, + translation_unit, + kArbitraryStackSize)) { + ErrorInfo error_info; + error_info.SetReport(ERROR_UNKNOWN, + "Could not create a translator thread.\n"); + ReportLoadError(error_info); + PnaclNonPpapiError(); } } @@ -531,13 +466,14 @@ void WINAPI DoLinkThread(void* arg) { } } else { SrpcParams dummy_params2; + NaClDesc* link_file_desc = resources->WrapperForUrl(link_file)->desc(); if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, ld_subprocess, "AddFile", "Ch", &dummy_params2, link_file.c_str(), - resources->DescForUrl(link_file))) { + link_file_desc)) { AbortLinkThread(p, "PnaclCoordinator linker AddFile(" + link_file + ") failed."); @@ -575,101 +511,76 @@ void WINAPI DoLinkThread(void* arg) { } // namespace -void PnaclCoordinator::RunLinkDidFinish( - int32_t pp_error, - PnaclTranslationUnit* translation_unit) { - PLUGIN_PRINTF(("PnaclCoordinator::RunLinkDidFinish (pp_error=%" +void PnaclCoordinator::RunLink(int32_t pp_error, + PnaclTranslationUnit* translation_unit) { + PLUGIN_PRINTF(("PnaclCoordinator::RunLink (pp_error=%" NACL_PRId32")\n", pp_error)); if (pp_error != PP_OK) { ReportLoadError(translation_unit->error_info); PnaclPpapiError(pp_error); return; } - // Transfer ownership of the nexe wrapper to the coordinator. - translated_fd_.reset(translation_unit->nexe_wrapper.release()); plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); - PnaclDidFinish(PP_OK, translation_unit); -} - -void PnaclCoordinator::RunLink(int32_t pp_error, - PnaclTranslationUnit* translation_unit) { - PLUGIN_PRINTF(("PnaclCoordinator::RunLink (pp_error=%" - NACL_PRId32")\n", pp_error)); - assert(PP_OK == pp_error); + if (!StartLdSubProcess()) { + ErrorInfo error_info; + error_info.SetReport(ERROR_UNKNOWN, + "Could not start linker subprocess\n"); + ReportLoadError(error_info); + PnaclNonPpapiError(); + return; + } // Invoke ld asynchronously. - // When ld has completed, RunLinkDidFinish is run on the main thread. + // When ld has completed, PnaclDidFinish is run on the main thread. translation_unit->link_done_cb = - callback_factory_.NewCallback(&PnaclCoordinator::RunLinkDidFinish, + callback_factory_.NewCallback(&PnaclCoordinator::PnaclDidFinish, translation_unit); link_thread_.reset(new NaClThread); - if (link_thread_ != NULL) { - if (!NaClThreadCreateJoinable(link_thread_.get(), - DoLinkThread, - translation_unit, - kArbitraryStackSize)) { - ErrorInfo error_info; - error_info.SetReport(ERROR_UNKNOWN, - "Could not create a linker thread.\n"); - ReportLoadError(error_info); - PnaclNonPpapiError(); - } - } else { + if (link_thread_ == NULL) { ErrorInfo error_info; error_info.SetReport(ERROR_UNKNOWN, "Could not allocate DoLinkThread()\n"); ReportLoadError(error_info); PnaclNonPpapiError(); + return; + } + if (!NaClThreadCreateJoinable(link_thread_.get(), + DoLinkThread, + translation_unit, + kArbitraryStackSize)) { + ErrorInfo error_info; + error_info.SetReport(ERROR_UNKNOWN, + "Could not create a linker thread.\n"); + ReportLoadError(error_info); + PnaclNonPpapiError(); } } ////////////////////////////////////////////////////////////////////// -bool PnaclCoordinator::ScheduleDownload(const nacl::string& url, - const pp::CompletionCallback& cb) { - if (!plugin_->StreamAsFile(url, cb.pp_completion_callback())) { +void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error, + const nacl::string& pexe_url, + PnaclTranslationUnit* translation) { + PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error != PP_OK) { + ReportLoadError(translation->error_info); + PnaclPpapiError(pp_error); + return; + } + pp::CompletionCallback cb = + callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate, + pexe_url, + translation); + + if (!plugin_->StreamAsFile(pexe_url, cb.pp_completion_callback())) { ErrorInfo error_info; error_info.SetReport(ERROR_UNKNOWN, "PnaclCoordinator: Failed to download file: " + - url + "\n"); + pexe_url + "\n"); ReportLoadError(error_info); PnaclNonPpapiError(); - return false; } - return true; -} - -void PnaclCoordinator::AddDownloadToDelayedCallback( - void (PnaclCoordinator::*handler)(int32_t, - const nacl::string&, - DelayedCallback*), - DelayedCallback* delayed_callback, - const nacl::string& url, - std::vector<url_callback_pair>& queue) { - // Queue up the URL download w/ a callback that invokes the delayed_callback. - queue.push_back(std::make_pair( - url, - callback_factory_.NewCallback(handler, url, delayed_callback))); - delayed_callback->IncrRequirements(1); -} - -void PnaclCoordinator::AddDownloadToDelayedCallback( - void (PnaclCoordinator::*handler)(int32_t, - const nacl::string&, - PnaclTranslationUnit*, - DelayedCallback*), - DelayedCallback* delayed_callback, - const nacl::string& url, - PnaclTranslationUnit* translation_unit, - std::vector<url_callback_pair>& queue) { - // Queue up the URL download w/ a callback that invokes the delayed_callback. - queue.push_back(std::make_pair( - url, - callback_factory_.NewCallback(handler, - url, - translation_unit, - delayed_callback))); - delayed_callback->IncrRequirements(1); } void PnaclCoordinator::BitcodeToNative( @@ -681,80 +592,38 @@ void PnaclCoordinator::BitcodeToNative( pexe_url.c_str(), llc_url.c_str(), ld_url.c_str())); + llc_url_ = llc_url; + ld_url_ = ld_url; translate_notify_callback_ = finish_callback; - string_vector link_resources = LinkResources(GetSandboxISA(), false); - - // TODO(sehr): revise to download llc, ld, and native libraries in one step. - // TODO(sehr): save these resources for possible multiple uses (e.g., psos). - // Steps: - // (1) Schedule downloads for llc, ld nexes, and native libraries. - // (2) When llc download and pexe has completed, run the translation. - // (3) When llc translation has finished, and ld, native libs are available, - // do the link. - // (4) When the link is done, we are done, call the finish_callback. + // (1) Schedule downloads for llc, ld nexes, and native libraries (resources). + // (2) When resources have been downloaded, download pexe. + // (3) When pexe download has completed, start translation. + // (4) When llc translation has finished do the link. + // (5) When the link is done, we are done, call the finish_callback. // Hand off the SHM file descriptor returned by link. // Set up async callbacks for these steps in reverse order. - // (3) Run link. - translation_unit_.reset(new PnaclTranslationUnit(this)); - pp::CompletionCallback run_link_callback = - callback_factory_.NewCallback(&PnaclCoordinator::RunLink, + // When resources loading completes, this causes the pexe download. + pp::CompletionCallback resources_cb = + callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad, + pexe_url, translation_unit_.get()); - DelayedCallback* delayed_link_callback = - MakeDelayedCallback(run_link_callback, 0); - - // (2) Run translation. - pp::CompletionCallback run_translate_callback = - callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate, - translation_unit_.get(), - delayed_link_callback); - // Linking depends on the compile finishing, so incr requirements by one. - delayed_link_callback->IncrRequirements(1); - - DelayedCallback* delayed_translate_callback = - MakeDelayedCallback(run_translate_callback, 0); - - // (1) Load nexes and assets using StreamAsFile(). This will kick off - // the whole process. - - // First, just collect the list of stuff to download. - std::vector<url_callback_pair> downloads; - - AddDownloadToDelayedCallback(&PnaclCoordinator::PexeReady, - delayed_translate_callback, - pexe_url, - translation_unit_.get(), - downloads); - AddDownloadToDelayedCallback(&PnaclCoordinator::LLCReady, - delayed_translate_callback, - llc_url, - downloads); - AddDownloadToDelayedCallback(&PnaclCoordinator::LDReady, - delayed_link_callback, - ld_url, - downloads); + resources_->AddResourceUrl(llc_url); + resources_->AddResourceUrl(ld_url); + string_vector link_resources = LinkResources(GetSandboxISA(), false); for (string_vector::iterator i = link_resources.begin(), e = link_resources.end(); i != e; ++i) { - AddDownloadToDelayedCallback(&PnaclCoordinator::LinkResourceReady, - delayed_link_callback, - *i, - downloads); - } - - // Finally, actually schedule the downloads. - for (size_t i = 0; i < downloads.size(); ++i) { - if (!ScheduleDownload(downloads[i].first, downloads[i].second)) { - break; // error should have been reported by ScheduleDownload. - } + resources_->AddResourceUrl(*i); } - downloads.clear(); + resources_->RunWhenAllLoaded(resources_cb); + resources_->StartDownloads(); } } // namespace plugin diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h index 8579b41..c8fecee 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h @@ -18,6 +18,7 @@ #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/cpp/completion_callback.h" @@ -27,43 +28,6 @@ namespace plugin { class Plugin; class PnaclCoordinator; -class PnaclResources; - -class PnaclResources { - public: - PnaclResources(Plugin* plugin) - : plugin_(plugin), - llc_desc_(kNaClSrpcInvalidImcDesc), - ld_desc_(kNaClSrpcInvalidImcDesc) { } - - ~PnaclResources() { - for (std::map<nacl::string, nacl::DescWrapper*>::iterator - i = resource_wrappers_.begin(), e = resource_wrappers_.end(); - i != e; - ++i) { - delete i->second; - } - resource_wrappers_.clear(); - } - - // The file descriptor for the llc nexe. - NaClSrpcImcDescType llc_desc() const { return llc_desc_; } - void set_llc_desc(NaClSrpcImcDescType llc_desc) { llc_desc_ = llc_desc; } - // The file descriptor for the ld nexe. - NaClSrpcImcDescType ld_desc() const { return ld_desc_; } - void set_ld_desc(NaClSrpcImcDescType ld_desc) { ld_desc_ = ld_desc; } - - NaClSrpcImcDescType DescForUrl(const nacl::string& url) { - return resource_wrappers_[url]->desc(); - } - void AddFDForUrl(const nacl::string& url, int32_t fd); - - private: - Plugin* plugin_; - NaClSrpcImcDescType llc_desc_; - NaClSrpcImcDescType ld_desc_; - std::map<nacl::string, nacl::DescWrapper*> resource_wrappers_; -}; struct PnaclTranslationUnit { PnaclTranslationUnit(PnaclCoordinator* coord) @@ -136,103 +100,51 @@ class PnaclCoordinator { return translated_fd_.release(); } + 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); + + + // Accessors for use by helper threads. 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 SubprocessesShouldDie() { - NaClXMutexLock(&subprocess_mu_); - bool retval = subprocesses_should_die_; - NaClXMutexUnlock(&subprocess_mu_); - return retval; - } - void SetSubprocessesShouldDie(bool subprocesses_should_die) { - NaClXMutexLock(&subprocess_mu_); - subprocesses_should_die_ = subprocesses_should_die; - NaClXMutexUnlock(&subprocess_mu_); - } + bool StartLdSubProcess(); + bool SubprocessesShouldDie(); + void SetSubprocessesShouldDie(bool subprocesses_should_die); PnaclResources* resources() const { return resources_.get(); } protected: - // Delay a callback until |num_dependencies| are met. - DelayedCallback* MakeDelayedCallback(pp::CompletionCallback cb, - uint32_t num_dependencies); - - // Helper functions for generating callbacks that will be run when a - // download of |url| has completed. The generated callback will - // run |handler|. The |handler| itself is given a pp_error code, - // the url of the download, and another callback in the - // form of the supplied |delayed_callback|. - void AddDownloadToDelayedCallback( - void (PnaclCoordinator::*handler)(int32_t, - const nacl::string&, - DelayedCallback*), - DelayedCallback* delayed_callback, - const nacl::string& url, - std::vector<url_callback_pair>& queue); - void AddDownloadToDelayedCallback( - void (PnaclCoordinator::*handler)(int32_t, - const nacl::string&, - PnaclTranslationUnit*, - DelayedCallback*), - DelayedCallback* delayed_callback, - const nacl::string& url, - PnaclTranslationUnit* translation_unit, - std::vector<url_callback_pair>& queue); - - bool ScheduleDownload(const nacl::string& url, - const pp::CompletionCallback& cb); - // Callbacks for when various files, etc. have been downloaded. - void PexeReady(int32_t pp_error, - const nacl::string& url, - PnaclTranslationUnit* translation_unit, - DelayedCallback* delayed_callback); - void LLCReady(int32_t pp_error, - const nacl::string& url, - DelayedCallback* delayed_callback); - void LDReady(int32_t pp_error, - const nacl::string& url, - DelayedCallback* delayed_callback); - void LinkResourceReady(int32_t pp_error, - const nacl::string& url, - DelayedCallback* delayed_callback); - - int32_t GetLoadedFileDesc(int32_t pp_error, - const nacl::string& url, - const nacl::string& component); - - // Helper for starting helper nexes after they are downloaded. - NaClSubprocessId HelperNexeDidLoad(int32_t fd, ErrorInfo* error_info); + void ResourcesDidLoad(int32_t pp_error, + const nacl::string& url, + PnaclTranslationUnit* translation_unit); // Callbacks for compute-based translation steps. void RunTranslate(int32_t pp_error, - PnaclTranslationUnit* translation_unit, - DelayedCallback* delayed_callback); - void RunTranslateDidFinish(int32_t pp_error, - PnaclTranslationUnit* translation_unit, - DelayedCallback* delayed_callback); + const nacl::string& url, + PnaclTranslationUnit* translation_unit); void RunLink(int32_t pp_error, PnaclTranslationUnit* translation_unit); - void RunLinkDidFinish(int32_t pp_error, - PnaclTranslationUnit* translation_unit); // Pnacl translation completed normally. void PnaclDidFinish(int32_t pp_error, PnaclTranslationUnit* translation_unit); - // 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); - private: NACL_DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator); @@ -240,12 +152,9 @@ class PnaclCoordinator { pp::CompletionCallback translate_notify_callback_; pp::CompletionCallbackFactory<PnaclCoordinator> callback_factory_; - // State for a single translation. - // TODO(jvoung): see if we can manage this state better, especially when we - // start having to translate multiple bitcode files for the same application - // (for DSOs). - - std::set<DelayedCallback*> delayed_callbacks; + // URLs used to lookup downloaded resources. + 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 diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc new file mode 100644 index 0000000..afc3431 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc @@ -0,0 +1,119 @@ +// Copyright (c) 2011 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. + +#include "native_client/src/trusted/plugin/pnacl_resources.h" + +#include <utility> +#include <vector> + +#include "native_client/src/include/portability_io.h" +#include "native_client/src/shared/platform/nacl_check.h" +#include "native_client/src/trusted/desc/nacl_desc_wrapper.h" +#include "native_client/src/trusted/plugin/browser_interface.h" +#include "native_client/src/trusted/plugin/plugin.h" +#include "native_client/src/trusted/plugin/plugin_error.h" +#include "native_client/src/trusted/plugin/pnacl_coordinator.h" +#include "native_client/src/trusted/plugin/utility.h" + +#include "ppapi/c/pp_errors.h" + +namespace plugin { + +class Plugin; + +PnaclResources::~PnaclResources() { + for (std::map<nacl::string, nacl::DescWrapper*>::iterator + i = resource_wrappers_.begin(), e = resource_wrappers_.end(); + i != e; + ++i) { + delete i->second; + } + resource_wrappers_.clear(); +} + +void PnaclResources::Initialize() { + callback_factory_.Initialize(this); +} + +void PnaclResources::AddResourceUrl(const nacl::string& url) { + // Use previously loaded resources if available. + if (resource_wrappers_.find(url) != resource_wrappers_.end()) { + return; + } + all_loaded_ = false; + resource_urls_.push_back(url); +} + +void PnaclResources::StartDownloads() { + // If there are no resources to be loaded, report all loaded to invoke + // client callbacks as needed. + if (all_loaded_) { + AllLoaded(PP_OK); + return; + } + pp::CompletionCallback all_loaded_callback = + callback_factory_.NewCallback(&PnaclResources::AllLoaded); + // Create a counter (barrier) callback to track when all of the resources + // are loaded. + uint32_t resource_count = static_cast<uint32_t>(resource_urls_.size()); + delayed_callback_.reset( + new DelayedCallback(all_loaded_callback, resource_count)); + + // Schedule the downloads. + CHECK(resource_urls_.size() > 0); + for (size_t i = 0; i < resource_urls_.size(); ++i) { + const nacl::string& url = resource_urls_[i]; + pp::CompletionCallback ready_callback = + callback_factory_.NewCallback(&PnaclResources::ResourceReady, url); + if (!plugin_->StreamAsFile(url, ready_callback.pp_completion_callback())) { + ErrorInfo error_info; + error_info.SetReport(ERROR_UNKNOWN, + "PnaclCoordinator: Failed to download file: " + + url + "\n"); + coordinator_->ReportLoadError(error_info); + coordinator_->PnaclNonPpapiError(); + break; + } + } + resource_urls_.clear(); +} + +void PnaclResources::ResourceReady(int32_t pp_error, + const nacl::string& url) { + PLUGIN_PRINTF(("PnaclResources::ResourceReady (pp_error=%" + NACL_PRId32", url=%s)\n", pp_error, url.c_str())); + // pp_error is checked by GetLoadedFileDesc. + int32_t fd = coordinator_->GetLoadedFileDesc(pp_error, + url, + "resource " + url); + if (fd < 0) { + coordinator_->PnaclPpapiError(pp_error); + } else { + resource_wrappers_[url] = + plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); + delayed_callback_->RunIfTime(); + } +} + +void PnaclResources::AllLoaded(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclResources::AllLoaded (pp_error=%"NACL_PRId32")\n", + pp_error)); + all_loaded_ = true; + // Run the client-specified callback if one was set. + if (client_callback_is_valid_) { + pp::Core* core = pp::Module::Get()->core(); + core->CallOnMainThread(0, client_callback_, PP_OK); + } +} + +void PnaclResources::RunWhenAllLoaded(pp::CompletionCallback& client_callback) { + if (all_loaded_) { + pp::Core* core = pp::Module::Get()->core(); + core->CallOnMainThread(0, client_callback, PP_OK); + } + client_callback_ = client_callback; + client_callback_is_valid_ = true; +} + +} // namespace plugin diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.h b/ppapi/native_client/src/trusted/plugin/pnacl_resources.h new file mode 100644 index 0000000..fa7edb0 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.h @@ -0,0 +1,78 @@ +// Copyright (c) 2011 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_RESOURCES_H_ +#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_RESOURCES_H_ + +#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/srpc/nacl_srpc.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/plugin_error.h" + +#include "ppapi/cpp/completion_callback.h" + +namespace plugin { + +class Plugin; +class PnaclCoordinator; + +class PnaclResources { + public: + PnaclResources(Plugin* plugin, PnaclCoordinator* coordinator) + : plugin_(plugin), + coordinator_(coordinator), + all_loaded_(true), + client_callback_is_valid_(false) + { } + + virtual ~PnaclResources(); + + void Initialize(); + + nacl::DescWrapper* WrapperForUrl(const nacl::string& url) { + return resource_wrappers_[url]; + } + + // Add an URL for download. + void AddResourceUrl(const nacl::string& url); + // Start fetching the URLs. + void StartDownloads(); + // Set the callback for what to do when all the resources are available. + void RunWhenAllLoaded(pp::CompletionCallback& client_callback); + + private: + NACL_DISALLOW_COPY_AND_ASSIGN(PnaclResources); + + // Callback invoked each time one resource has been loaded. + void ResourceReady(int32_t pp_error, const nacl::string& url); + // Callback invoked when all resources have been loaded. + void AllLoaded(int32_t pp_error); + + Plugin* plugin_; + PnaclCoordinator* coordinator_; + std::vector<nacl::string> resource_urls_; + std::map<nacl::string, nacl::DescWrapper*> resource_wrappers_; + nacl::scoped_ptr<DelayedCallback> delayed_callback_; + // Set once all resources have been loaded to indicate that future calls to + // RunWhenAllLoaded should immediately invoke the client callback. This + // simplifies the client while allowing resources to be used for subsequent + // translations. + bool all_loaded_; + // Callback to be invoked when all resources can be guaranteed available. + pp::CompletionCallback client_callback_; + // If RunWhenAllLoaded was called before all resources have been loaded, + // this indicates that the registered client callback should be used when + // the last resource arrives. + bool client_callback_is_valid_; + // Factory for ready callbacks, etc. + pp::CompletionCallbackFactory<PnaclResources> callback_factory_; +}; + +} // namespace plugin; +#endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_RESOURCES_H_ |