diff options
author | sehr@google.com <sehr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-14 19:32:07 +0000 |
---|---|---|
committer | sehr@google.com <sehr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-14 19:32:07 +0000 |
commit | f097e958541109321056e8abc6d30d897ee5c713 (patch) | |
tree | dcb36bb561fab8b7d313835d50d3466dfb187bb0 | |
parent | 88e31385ab21d4c197e81961e1dd9e16b1793bdb (diff) | |
download | chromium_src-f097e958541109321056e8abc6d30d897ee5c713.zip chromium_src-f097e958541109321056e8abc6d30d897ee5c713.tar.gz chromium_src-f097e958541109321056e8abc6d30d897ee5c713.tar.bz2 |
This CL moves all command line processing out of the coordinator. Key other features required by this change:
1) object and nexe are now passed by ppapi temporary files
2) native library and .o loading is done purely on demand
3) the command lines baked into llc and ld are used exclusively
One minor change that fit with the CL is that the coordinator now creates only one helper thread that runs both llc and ld.
BUG= http://code.google.com/p/nativeclient/issues/detail?id=2440
TEST=none
Review URL: http://codereview.chromium.org/8786005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114473 0039d316-1c4b-4281-b951-d872f2087c98
8 files changed, 756 insertions, 691 deletions
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.cc b/ppapi/native_client/src/trusted/plugin/plugin.cc index ce4ff181..5e23758 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.cc +++ b/ppapi/native_client/src/trusted/plugin/plugin.cc @@ -1000,9 +1000,8 @@ Plugin::Plugin(PP_Instance pp_instance) PLUGIN_PRINTF(("Plugin::Plugin (this=%p, pp_instance=%" NACL_PRId32")\n", static_cast<void*>(this), pp_instance)); NaClSrpcModuleInit(); - nexe_downloader_.Initialize(this); - pnacl_.Initialize(this); callback_factory_.Initialize(this); + nexe_downloader_.Initialize(this); } @@ -1305,7 +1304,7 @@ void Plugin::BitcodeDidTranslate(int32_t pp_error) { // Inform JavaScript that we successfully translated the bitcode to a nexe. EnqueueProgressEvent(kProgressEventProgress); nacl::scoped_ptr<nacl::DescWrapper> - wrapper(pnacl_.ReleaseTranslatedFD()); + wrapper(pnacl_coordinator_.get()->ReleaseTranslatedFD()); ErrorInfo error_info; bool was_successful = LoadNaClModule( wrapper.get(), &error_info, @@ -1621,7 +1620,10 @@ void Plugin::ProcessNaClManifest(const nacl::string& manifest_json) { pp::CompletionCallback translate_callback = callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate); // Will always call the callback on success or failure. - pnacl_.BitcodeToNative(program_url, translate_callback); + pnacl_coordinator_.reset( + PnaclCoordinator::BitcodeToNative(this, + program_url, + translate_callback)); return; } else { pp::CompletionCallback open_callback = diff --git a/ppapi/native_client/src/trusted/plugin/plugin.h b/ppapi/native_client/src/trusted/plugin/plugin.h index 090b4bf..91b0115 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.h +++ b/ppapi/native_client/src/trusted/plugin/plugin.h @@ -488,7 +488,7 @@ class Plugin : public pp::InstancePrivate { FileDownloader nexe_downloader_; pp::CompletionCallbackFactory<Plugin> callback_factory_; - PnaclCoordinator pnacl_; + nacl::scoped_ptr<PnaclCoordinator> pnacl_coordinator_; // The manifest dictionary. Used for looking up resources to be loaded. nacl::scoped_ptr<Manifest> manifest_; diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc index 85b6851..53e98af 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc @@ -17,622 +17,589 @@ #include "native_client/src/trusted/plugin/plugin.h" #include "native_client/src/trusted/plugin/plugin_error.h" #include "native_client/src/trusted/plugin/pnacl_srpc_lib.h" -#include "native_client/src/trusted/plugin/scriptable_handle.h" #include "native_client/src/trusted/plugin/utility.h" #include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_file_io.h" +#include "ppapi/cpp/file_io.h" -namespace { +namespace plugin { -typedef std::vector<nacl::string> string_vector; -int32_t kArbitraryStackSize = 128 << 10; +class Plugin; -} // namespace +namespace { -namespace plugin { +const char kLlcUrl[] = "llc"; +const char kLdUrl[] = "ld"; -class Plugin; +nacl::string ResourceBaseUrl() { + return nacl::string("pnacl_support/") + GetSandboxISA() + "/"; +} -void PnaclCoordinator::Initialize(Plugin* plugin) { - PLUGIN_PRINTF(("PnaclCoordinator::Initialize (this=%p)\n", - static_cast<void*>(this))); - CHECK(plugin != NULL); - CHECK(plugin_ == NULL); // Can only initialize once. - plugin_ = plugin; - callback_factory_.Initialize(this); - resources_.reset(new PnaclResources(plugin, this)); - resources_->Initialize(); +nacl::string Random32CharHexString(struct NaClDescRng* rng) { + struct NaClDesc* desc = reinterpret_cast<struct NaClDesc*>(rng); + const struct NaClDescVtbl* vtbl = + reinterpret_cast<const struct NaClDescVtbl*>(desc->base.vtbl); + + nacl::string hex_string; + const int32_t kTempFileNameWords = 4; + for (int32_t i = 0; i < kTempFileNameWords; ++i) { + int32_t num; + CHECK(sizeof num == vtbl->Read(desc, + reinterpret_cast<char*>(&num), + sizeof num)); + char frag[16]; + SNPRINTF(frag, sizeof frag, "%08x", num); + hex_string += nacl::string(frag); + } + return hex_string; } -PnaclCoordinator::~PnaclCoordinator() { - PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n", - static_cast<void*>(this))); +// Some constants for PnaclFileDescPair::GetFD readability. +const bool kReadOnly = false; +const bool kWriteable = true; - // Join helper threads which will block the page from refreshing while a - // translation is happening. - if (translate_thread_.get() != NULL || link_thread_.get() != NULL) { - SetSubprocessesShouldDie(true); - } - if (translate_thread_.get() != NULL) { - NaClThreadJoin(translate_thread_.get()); - } - if (link_thread_.get() != NULL) { - NaClThreadJoin(link_thread_.get()); - } +} // namespace + +////////////////////////////////////////////////////////////////////// +PnaclFileDescPair::PnaclFileDescPair(Plugin* plugin, + pp::FileSystem* file_system, + PnaclCoordinator* coordinator) + : plugin_(plugin), + file_system_(file_system), + coordinator_(coordinator) { + PLUGIN_PRINTF(("PnaclFileDescPair::PnaclFileDescPair (plugin=%p, " + "file_system=%p, coordinator=%p)\n", + static_cast<void*>(plugin), static_cast<void*>(file_system), + static_cast<void*>(coordinator))); + callback_factory_.Initialize(this); + CHECK(NaClDescRngCtor(&rng_desc_)); + file_io_trusted_ = static_cast<const PPB_FileIOTrusted*>( + pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); + // Get a random temp file name. + filename_ = "/" + Random32CharHexString(&rng_desc_); } -void PnaclCoordinator::ReportLoadAbort() { - plugin_->ReportLoadAbort(); +PnaclFileDescPair::~PnaclFileDescPair() { + PLUGIN_PRINTF(("PnaclFileDescPair::~PnaclFileDescPair\n")); + NaClDescUnref(reinterpret_cast<NaClDesc*>(&rng_desc_)); } -void PnaclCoordinator::ReportLoadError(const ErrorInfo& error) { - plugin_->ReportLoadError(error); +void PnaclFileDescPair::Open(const pp::CompletionCallback& cb) { + PLUGIN_PRINTF(("PnaclFileDescPair::Open\n")); + done_callback_ = cb; + + write_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); + write_io_.reset(new pp::FileIO(plugin_)); + read_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); + read_io_.reset(new pp::FileIO(plugin_)); + + pp::CompletionCallback open_write_cb = + callback_factory_.NewCallback(&PnaclFileDescPair::WriteFileDidOpen); + // Open the writeable file. + write_io_->Open(*write_ref_, + PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE, + open_write_cb); } -void PnaclCoordinator::PnaclPpapiError(int32_t pp_error) { - // Attempt to free all the intermediate callbacks we ever created. - callback_factory_.CancelAll(); - translate_notify_callback_.Run(pp_error); +int32_t PnaclFileDescPair::GetFD(int32_t pp_error, + const pp::Resource& resource, + bool is_writable) { + PLUGIN_PRINTF(("PnaclFileDescPair::GetFD (pp_error=%"NACL_PRId32 + ", is_writable=%d)\n", pp_error, is_writable)); + if (pp_error != PP_OK) { + PLUGIN_PRINTF(("PnaclFileDescPair::GetFD pp_error != PP_OK\n")); + return -1; + } + int32_t file_desc = + file_io_trusted_->GetOSFileDescriptor(resource.pp_resource()); +#if NACL_WINDOWS + // Convert the Windows HANDLE from Pepper to a POSIX file descriptor. + int32_t open_flags = ((is_writable ? _O_RDWR : _O_RDONLY) | _O_BINARY); + int32_t posix_desc = _open_osfhandle(file_desc, open_flags); + if (posix_desc == -1) { + // Close the Windows HANDLE if it can't be converted. + CloseHandle(reinterpret_cast<HANDLE>(file_desc)); + PLUGIN_PRINTF(("PnaclFileDescPair::GetFD _open_osfhandle failed.\n")); + return NACL_NO_FILE_DESC; + } + file_desc = posix_desc; +#endif + int32_t file_desc_ok_to_close = DUP(file_desc); + if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { + PLUGIN_PRINTF(("PnaclFileDescPair::GetFD dup failed.\n")); + return -1; + } + return file_desc_ok_to_close; } -void PnaclCoordinator::PnaclNonPpapiError() { - PnaclPpapiError(PP_ERROR_FAILED); +void PnaclFileDescPair::WriteFileDidOpen(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclFileDescPair::WriteFileDidOpen (pp_error=%" + NACL_PRId32")\n", pp_error)); + // Remember the object temporary file descriptor. + int32_t fd = GetFD(pp_error, *write_io_, kWriteable); + if (fd < 0) { + coordinator_->ReportNonPpapiError("could not open write temp file\n"); + return; + } + write_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDWR)); + pp::CompletionCallback open_read_cb = + callback_factory_.NewCallback(&PnaclFileDescPair::ReadFileDidOpen); + // Open the read only file. + read_io_->Open(*read_ref_, PP_FILEOPENFLAG_READ, open_read_cb); } -void PnaclCoordinator::PnaclDidFinish(int32_t pp_error, - PnaclTranslationUnit* translation_unit) { - PLUGIN_PRINTF(("PnaclCoordinator::PnaclDidFinish (pp_error=%" +void PnaclFileDescPair::ReadFileDidOpen(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclFileDescPair::ReadFileDidOpen (pp_error=%" NACL_PRId32")\n", pp_error)); - if (pp_error != PP_OK) { - ReportLoadError(translation_unit->error_info); - PnaclPpapiError(pp_error); + // Remember the object temporary file descriptor. + int32_t fd = GetFD(pp_error, *read_io_, kReadOnly); + if (fd < 0) { + coordinator_->ReportNonPpapiError("could not open read temp file\n"); 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); + read_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); + // Run the client's completion callback. + pp::Core* core = pp::Module::Get()->core(); + core->CallOnMainThread(0, done_callback_, PP_OK); } ////////////////////////////////////////////////////////////////////// +PnaclCoordinator* PnaclCoordinator::BitcodeToNative( + Plugin* plugin, + const nacl::string& pexe_url, + const pp::CompletionCallback& translate_notify_callback) { + PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (plugin=%p, pexe=%s)\n", + static_cast<void*>(plugin), pexe_url.c_str())); + PnaclCoordinator* coordinator = + new PnaclCoordinator(plugin, + pexe_url, + translate_notify_callback, + ResourceBaseUrl()); + // Load llc and ld. + std::vector<nacl::string> resource_urls; + resource_urls.push_back(kLlcUrl); + resource_urls.push_back(kLdUrl); + pp::CompletionCallback resources_cb = + coordinator->callback_factory_.NewCallback( + &PnaclCoordinator::ResourcesDidLoad); + coordinator->resources_.reset( + new PnaclResources(plugin, + coordinator, + coordinator->resource_base_url_, + resource_urls, + resources_cb)); + CHECK(coordinator->resources_ != NULL); + coordinator->resources_->StartDownloads(); + // ResourcesDidLoad will be invoked when all resources have been received. + return coordinator; +} int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error, const nacl::string& url, const nacl::string& component) { + PLUGIN_PRINTF(("PnaclCoordinator::GetLoadedFileDesc (pp_error=%" + NACL_PRId32", url=%s, component=%s)\n", pp_error, + url.c_str(), component.c_str())); + PLUGIN_PRINTF(("PnaclCoordinator::GetLoadedFileDesc (pp_error=%d\n")); ErrorInfo error_info; int32_t file_desc = plugin_->GetPOSIXFileDesc(url); if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) { if (pp_error == PP_ERROR_ABORTED) { - ReportLoadAbort(); + plugin_->ReportLoadAbort(); } else { - // TODO(jvoung): Make a generic load error, or just use ERROR_UNKNOWN? - error_info.SetReport(ERROR_UNKNOWN, - "PNaCl " + component + " load failed."); - ReportLoadError(error_info); + ReportPpapiError(pp_error, component + " load failed.\n"); } return -1; } int32_t file_desc_ok_to_close = DUP(file_desc); if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { - // TODO(jvoung): Make a generic load error, or just use ERROR_UNKNOWN? - error_info.SetReport(ERROR_UNKNOWN, - "PNaCl " + component + " load failed: " - "could not dup fd."); - ReportLoadError(error_info); + ReportPpapiError(PP_ERROR_FAILED, component + " could not dup fd.\n"); return -1; } return file_desc_ok_to_close; } -bool PnaclCoordinator::StartLlcSubProcess() { - ErrorInfo error_info; - 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"); - ReportLoadError(error_info); - PnaclNonPpapiError(); - return NULL; - } - llc_subprocess_ = plugin_->nacl_subprocess(llc_id); - return (llc_subprocess_ != NULL); +PnaclCoordinator::PnaclCoordinator( + Plugin* plugin, + const nacl::string& pexe_url, + const pp::CompletionCallback& translate_notify_callback, + const nacl::string& resource_base_url) + : plugin_(plugin), + translate_notify_callback_(translate_notify_callback), + resource_base_url_(resource_base_url), + llc_subprocess_(NULL), + ld_subprocess_(NULL), + subprocesses_should_die_(false), + file_system_(new pp::FileSystem(plugin, PP_FILESYSTEMTYPE_LOCALTEMPORARY)), + pexe_url_(pexe_url) { + PLUGIN_PRINTF(("PnaclCoordinator::PnaclCoordinator (this=%p, plugin=%p)\n", + static_cast<void*>(this), static_cast<void*>(plugin))); + callback_factory_.Initialize(this); + NaClXMutexCtor(&subprocess_mu_); + // Initialize the file lookup related members. + NaClXMutexCtor(&lookup_service_mu_); + NaClXCondVarCtor(&lookup_service_cv_); + // Open the temporary file system. + CHECK(file_system_ != NULL); } -bool PnaclCoordinator::StartLdSubProcess() { - ErrorInfo error_info; - 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"); - ReportLoadError(error_info); - PnaclNonPpapiError(); - return NULL; +PnaclCoordinator::~PnaclCoordinator() { + PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n", + static_cast<void*>(this))); + // Join helper thread which will block the page from refreshing while a + // translation is happening. + if (translate_thread_.get() != NULL) { + SetSubprocessesShouldDie(true); + NaClThreadJoin(translate_thread_.get()); } - ld_subprocess_ = plugin_->nacl_subprocess(ld_id); - return (ld_subprocess_ != NULL); + NaClCondVarDtor(&lookup_service_cv_); + NaClMutexDtor(&lookup_service_mu_); + NaClMutexDtor(&subprocess_mu_); } -bool PnaclCoordinator::SubprocessesShouldDie() { - nacl::MutexLocker ml(&subprocess_mu_); - return subprocesses_should_die_; +void PnaclCoordinator::ReportNonPpapiError(const nacl::string& message) { + error_info_.SetReport(ERROR_UNKNOWN, + nacl::string("PnaclCoordinator: ") + message); + ReportPpapiError(PP_ERROR_FAILED); } -void PnaclCoordinator::SetSubprocessesShouldDie(bool subprocesses_should_die) { - nacl::MutexLocker ml(&subprocess_mu_); - subprocesses_should_die_ = subprocesses_should_die; +void PnaclCoordinator::ReportPpapiError(int32_t pp_error, + const nacl::string& message) { + error_info_.SetReport(ERROR_UNKNOWN, + nacl::string("PnaclCoordinator: ") + message); + ReportPpapiError(pp_error); } -////////////////////////////////////////////////////////////////////// -// First few callbacks. +void PnaclCoordinator::ReportPpapiError(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclCoordinator::ReportPpappiError (pp_error=%" + NACL_PRId32", error_code=%d, message=%s)\n", + pp_error, error_info_.error_code(), + error_info_.message().c_str())); + plugin_->ReportLoadError(error_info_); + // Free all the intermediate callbacks we ever created. + callback_factory_.CancelAll(); + translate_notify_callback_.Run(pp_error); +} -////////////////////////////////////////////////////////////////////// +void PnaclCoordinator::TranslateFinished(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error != PP_OK) { + ReportPpapiError(pp_error); + return; + } + // Transfer ownership of the nexe wrapper to the coordinator. + // TODO(sehr): need to release the translation unit here while transferring. + translated_fd_.reset(nexe_file_->read_wrapper()); + plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); + translate_notify_callback_.Run(pp_error); +} -namespace { -void AbortTranslateThread(PnaclTranslationUnit* translation_unit, - const nacl::string& error_string) { +void PnaclCoordinator::TranslateFailed(const nacl::string& error_string) { + PLUGIN_PRINTF(("PnaclCoordinator::TranslateFailed (error_string=%" + NACL_PRId32")\n", error_string.c_str())); pp::Core* core = pp::Module::Get()->core(); - translation_unit->error_info.SetReport(ERROR_UNKNOWN, error_string); - core->CallOnMainThread(0, translation_unit->translate_done_cb, - PP_ERROR_FAILED); + error_info_.SetReport(ERROR_UNKNOWN, + nacl::string("PnaclCoordinator: ") + error_string); + core->CallOnMainThread(0, translate_done_cb_, PP_ERROR_FAILED); NaClThreadExit(1); } -void WINAPI DoTranslateThread(void* arg) { - PnaclTranslationUnit* p = reinterpret_cast<PnaclTranslationUnit*>(arg); - PnaclCoordinator* coordinator = p->coordinator; - NaClSubprocess* llc_subprocess = coordinator->llc_subprocess(); - Plugin* plugin = coordinator->plugin(); - BrowserInterface* browser = plugin->browser_interface(); - - // Set up LLC flags first. - // TODO(jvoung): Bake these into the llc nexe? - // May also want to improve scriptability, but the only thing we need - // probably is PIC vs non-PIC and micro-arch specification. - const char* llc_args_x8632[] = { "-march=x86", - "-mcpu=pentium4", - "-mtriple=i686-none-nacl-gnu", - "-asm-verbose=false", - "-filetype=obj" }; - const char* llc_args_x8664[] = { "-march=x86-64", - "-mcpu=core2", - "-mtriple=x86_64-none-nacl-gnu", - "-asm-verbose=false", - "-filetype=obj" }; - const char* llc_args_arm[] = { "-march=arm", - "-mcpu=cortex-a8", - "-mtriple=armv7a-none-nacl-gnueabi", - "-asm-verbose=false", - "-filetype=obj", - "-arm-reserve-r9", - "-sfi-disable-cp", - "-arm_static_tls", - "-sfi-store", - "-sfi-load", - "-sfi-stack", - "-sfi-branch", - "-sfi-data", - "-no-inline-jumptables" }; - - nacl::string sandbox_isa = GetSandboxISA(); - const char** llc_args; - size_t num_args; - - if (sandbox_isa.compare("x86-32") == 0) { - llc_args = llc_args_x8632; - num_args = NACL_ARRAY_SIZE(llc_args_x8632); - } else if (sandbox_isa.compare("x86-64") == 0) { - llc_args = llc_args_x8664; - num_args = NACL_ARRAY_SIZE(llc_args_x8664); - } else if (sandbox_isa.compare("arm") == 0) { - llc_args = llc_args_arm; - num_args = NACL_ARRAY_SIZE(llc_args_arm); - } else { - AbortTranslateThread(p, - "PnaclCoordinator compiler unhandled ISA " + - sandbox_isa + "."); +void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error != PP_OK) { + ReportPpapiError(pp_error, "resources failed to load\n"); return; } + // Open the local temporary file system to create the temporary files + // for the object and nexe. + pp::CompletionCallback cb = + callback_factory_.NewCallback(&PnaclCoordinator::FileSystemDidOpen); + if (!file_system_->Open(0, cb)) { + ReportNonPpapiError("failed to open file system.\n"); + } +} - for (uint32_t i = 0; i < num_args; i++) { - if (coordinator->SubprocessesShouldDie()) { - NaClThreadExit(1); - } - SrpcParams dummy_params; - if (!PnaclSrpcLib::InvokeSrpcMethod(browser, - llc_subprocess, - "AddArg", - "C", - &dummy_params, - llc_args[i])) { - AbortTranslateThread(p, - "PnaclCoordinator compiler AddArg(" + - nacl::string(llc_args[i]) + ") failed."); - } +void PnaclCoordinator::FileSystemDidOpen(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclCoordinator::FileSystemDidOpen (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error != PP_OK) { + ReportPpapiError(pp_error, "file system didn't open.\n"); + return; } + // Create the object file pair for connecting llc and ld. + obj_file_.reset(new PnaclFileDescPair(plugin_, file_system_.get(), this)); + pp::CompletionCallback cb = + callback_factory_.NewCallback(&PnaclCoordinator::ObjectPairDidOpen); + obj_file_->Open(cb); +} - if (coordinator->SubprocessesShouldDie()) { - NaClThreadExit(1); +void PnaclCoordinator::ObjectPairDidOpen(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclCoordinator::ObjectPairDidOpen (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error != PP_OK) { + ReportPpapiError(pp_error); + return; } - SrpcParams params; - if (!PnaclSrpcLib::InvokeSrpcMethod(browser, - llc_subprocess, - "Translate", - "h", - ¶ms, - p->pexe_wrapper->desc())) { - AbortTranslateThread(p, - "PnaclCoordinator compile failed."); - } else { - // Grab the outparams. - p->obj_wrapper.reset( - plugin->wrapper_factory()->MakeGeneric(params.outs()[0]->u.hval)); - p->obj_len = params.outs()[1]->u.ival; - p->is_shared_library = params.outs()[2]->u.ival != 0; - p->soname = params.outs()[3]->arrays.str; - p->lib_dependencies = params.outs()[4]->arrays.str; - PLUGIN_PRINTF(("PnaclCoordinator::Translate SRPC succeeded (bytes=%" - NACL_PRId32", is_shared_library=%d, soname='%s', " - "lib_dependencies='%s')\n", p->obj_len, - p->is_shared_library, p->soname.c_str(), - p->lib_dependencies.c_str())); + // Create the nexe file pair for connecting ld and sel_ldr. + nexe_file_.reset(new PnaclFileDescPair(plugin_, file_system_.get(), this)); + pp::CompletionCallback cb = + callback_factory_.NewCallback(&PnaclCoordinator::NexePairDidOpen); + nexe_file_->Open(cb); +} + +void PnaclCoordinator::NexePairDidOpen(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclCoordinator::NexePairDidOpen (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error != PP_OK) { + ReportPpapiError(pp_error); + return; } - if (coordinator->SubprocessesShouldDie()) { - NaClThreadExit(1); + // Load the pexe file and get the translation started. + pp::CompletionCallback cb = + callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate); + + if (!plugin_->StreamAsFile(pexe_url_, cb.pp_completion_callback())) { + ReportNonPpapiError(nacl::string("failed to download ") + pexe_url_ + "\n"); } - pp::Core* core = pp::Module::Get()->core(); - core->CallOnMainThread(0, p->translate_done_cb, PP_OK); - NaClThreadExit(0); } -} // namespace - -void PnaclCoordinator::RunTranslate(int32_t pp_error, - const nacl::string& pexe_url, - PnaclTranslationUnit* translation_unit) { +void PnaclCoordinator::RunTranslate(int32_t pp_error) { PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%" NACL_PRId32")\n", pp_error)); - // pp_error is checked by GetLoadedFileDesc. - int32_t fd = GetLoadedFileDesc(pp_error, pexe_url, "pexe"); + int32_t fd = GetLoadedFileDesc(pp_error, pexe_url_, "pexe"); if (fd < 0) { - PnaclPpapiError(pp_error); return; } - 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(); + pexe_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); + // It would really be nice if we could create subprocesses from other than + // the main thread. Until we can, we create them both up front. + // TODO(sehr): allow creation of subrpocesses from other threads. + llc_subprocess_ = StartSubprocess(kLlcUrl); + if (llc_subprocess_ == NULL) { + ReportPpapiError(PP_ERROR_FAILED); + return; + } + ld_subprocess_ = StartSubprocess(kLdUrl); + if (ld_subprocess_ == NULL) { + ReportPpapiError(PP_ERROR_FAILED); return; } - // Invoke llvm asynchronously. - // RunLink runs on the main thread when llvm is done. - translation_unit->translate_done_cb = - callback_factory_.NewCallback(&PnaclCoordinator::RunLink, - translation_unit); + // Invoke llc followed by ld off the main thread. This allows use of + // blocking RPCs that would otherwise block the JavaScript main thread. + translate_done_cb_ = + callback_factory_.NewCallback(&PnaclCoordinator::TranslateFinished); translate_thread_.reset(new NaClThread); if (translate_thread_ == NULL) { - ErrorInfo error_info; - error_info.SetReport(ERROR_UNKNOWN, - "Could not allocate DoTranslateThread()\n"); - ReportLoadError(error_info); - PnaclNonPpapiError(); + ReportNonPpapiError("could not allocate thread struct\n"); return; } + const int32_t kArbitraryStackSize = 128 * 1024; if (!NaClThreadCreateJoinable(translate_thread_.get(), DoTranslateThread, - translation_unit, + this, kArbitraryStackSize)) { - ErrorInfo error_info; - error_info.SetReport(ERROR_UNKNOWN, - "Could not create a translator thread.\n"); - ReportLoadError(error_info); - PnaclNonPpapiError(); + ReportNonPpapiError("could not create thread\n"); } } -////////////////////////////////////////////////////////////////////// -// Helper functions for loading native libs. -// Done here to avoid hacking on the manifest parser further... - -namespace { - -// Fake filename for the object file generated by llvm. -nacl::string GeneratedObjectFileName() { - return nacl::string("___PNACL_GENERATED"); -} - -nacl::string ResourceBaseUrl() { - nacl::string sandbox_isa = GetSandboxISA(); - nacl::string base_url = "pnacl_support/" + sandbox_isa + "/"; - return base_url; -} - -string_vector LinkResources(const nacl::string& sandbox_isa, - bool withGenerated) { - string_vector results; - // NOTE: order of items == link order. - if (sandbox_isa.compare("x86-64") == 0) { - results.push_back("libpnacl_irt_shim.a"); - } - results.push_back("crtbegin.o"); - if (withGenerated) { - results.push_back(GeneratedObjectFileName()); - } - results.push_back("libcrt_platform.a"); - results.push_back("libgcc.a"); - results.push_back("libgcc_eh.a"); - results.push_back("crtend.o"); - return results; -} - -} // namespace - -////////////////////////////////////////////////////////////////////// -// Final link callbacks. - -namespace { - -void AbortLinkThread(PnaclTranslationUnit* translation_unit, - const nacl::string& error_string) { - ErrorInfo error_info; - pp::Core* core = pp::Module::Get()->core(); - translation_unit->error_info.SetReport(ERROR_UNKNOWN, error_string); - core->CallOnMainThread(0, translation_unit->link_done_cb, PP_ERROR_FAILED); - NaClThreadExit(1); +NaClSubprocess* PnaclCoordinator::StartSubprocess( + const nacl::string& url_for_nexe) { + PLUGIN_PRINTF(("PnaclCoordinator::StartSubprocess (url_for_nexe=%s)\n", + url_for_nexe.c_str())); + nacl::DescWrapper* wrapper = resources_->WrapperForUrl(url_for_nexe); + NaClSubprocessId id = plugin_->LoadHelperNaClModule(wrapper, &error_info_); + if (kInvalidNaClSubprocessId == id) { + PLUGIN_PRINTF(( + "PnaclCoordinator::StartSubprocess: invalid subprocess id\n")); + return NULL; + } + return plugin_->nacl_subprocess(id); } -void WINAPI DoLinkThread(void* arg) { - PnaclTranslationUnit* p = reinterpret_cast<PnaclTranslationUnit*>(arg); - PnaclCoordinator* coordinator = p->coordinator; - NaClSubprocess* ld_subprocess = coordinator->ld_subprocess(); - Plugin* plugin = coordinator->plugin(); +// TODO(sehr): the thread body should be in a class by itself with a delegate +// class for interfacing with the rest of the coordinator. +void WINAPI PnaclCoordinator::DoTranslateThread(void* arg) { + PnaclCoordinator* coordinator = reinterpret_cast<PnaclCoordinator*>(arg); + Plugin* plugin = coordinator->plugin_; BrowserInterface* browser_interface = plugin->browser_interface(); - // Set up command line arguments (flags then files). - - //// Flags. - // TODO(jvoung): Be able to handle the dynamic linking flags too, - // and don't hardcode so much here. - string_vector flags; - nacl::string sandbox_isa = GetSandboxISA(); - flags.push_back("-nostdlib"); - flags.push_back("-m"); - if (sandbox_isa.compare("x86-32") == 0) { - flags.push_back("elf_nacl"); - } else if (sandbox_isa.compare("x86-64") == 0) { - flags.push_back("elf64_nacl"); - flags.push_back("-entry=_pnacl_wrapper_start"); - } else if (sandbox_isa.compare("arm") == 0) { - flags.push_back("armelf_nacl"); - } else { - AbortLinkThread(p, - "PnaclCoordinator linker unhandled ISA " + - sandbox_isa + "."); - } - - for (string_vector::iterator i = flags.begin(), e = flags.end(); - i != e; ++i) { - const nacl::string& flag = *i; - if (coordinator->SubprocessesShouldDie()) { - NaClThreadExit(1); - } - SrpcParams dummy_params; - if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, - ld_subprocess, - "AddArg", - "C", - &dummy_params, - flag.c_str())) { - AbortLinkThread(p, - "PnaclCoordinator linker AddArg(" + flag + - ") failed."); - } - } - - //// Files. - string_vector files = LinkResources(sandbox_isa, true); - PnaclResources* resources = coordinator->resources(); - for (string_vector::iterator i = files.begin(), e = files.end(); - i != e; ++i) { - const nacl::string& link_file = *i; - if (coordinator->SubprocessesShouldDie()) { - NaClThreadExit(1); - } - // Add as argument. - SrpcParams dummy_params; - if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, - ld_subprocess, - "AddArg", - "C", - &dummy_params, - link_file.c_str())) { - AbortLinkThread(p, - "PnaclCoordinator linker AddArg(" + - link_file + ") failed."); - } - // Also map the file name to descriptor. - if (i->compare(GeneratedObjectFileName()) == 0) { - SrpcParams dummy_params2; - if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, - ld_subprocess, - "AddFileWithSize", - "Chi", - &dummy_params2, - link_file.c_str(), - p->obj_wrapper->desc(), - p->obj_len)) { - AbortLinkThread(p, - "PnaclCoordinator linker AddFileWithSize" - "(" + link_file + ") failed."); - } - } 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(), - link_file_desc)) { - AbortLinkThread(p, - "PnaclCoordinator linker AddFile(" + link_file + - ") failed."); - } - } - } - + // Run LLC. + SrpcParams params; + nacl::DescWrapper* llc_out_file = coordinator->obj_file_->write_wrapper(); + if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, + coordinator->llc_subprocess_, + "RunWithDefaultCommandLine", + "hh", + ¶ms, + coordinator->pexe_wrapper_->desc(), + llc_out_file->desc())) { + coordinator->TranslateFailed("compile failed."); + } + // LLC returns values that are used to determine how linking is done. + int is_shared_library = (params.outs()[0]->u.ival != 0); + nacl::string soname = params.outs()[1]->arrays.str; + nacl::string lib_dependencies = params.outs()[2]->arrays.str; + PLUGIN_PRINTF(("PnaclCoordinator: compile (coordinator=%p) succeeded" + " is_shared_library=%d, soname='%s', lib_dependencies='%s')\n", + arg, is_shared_library, soname.c_str(), + lib_dependencies.c_str())); if (coordinator->SubprocessesShouldDie()) { + PLUGIN_PRINTF(( + "PnaclCoordinator::DoTranslateThread: killed by coordinator.\n")); NaClThreadExit(1); } - - // Finally, do the Link! - SrpcParams params; + // Set up the lookup service for filename to handle resolution. + NaClSrpcService* service = + reinterpret_cast<NaClSrpcService*>(calloc(1, sizeof(*service))); + if (NULL == service) { + coordinator->TranslateFailed("lookup service alloc failed."); + } + if (!NaClSrpcServiceHandlerCtor(service, lookup_methods)) { + free(service); + coordinator->TranslateFailed("lookup service constructor failed."); + } + char* service_string = const_cast<char*>(service->service_string); + NaClSubprocess* ld_subprocess = coordinator->ld_subprocess_; + ld_subprocess->srpc_client()->AttachService(service, coordinator); + nacl::DescWrapper* ld_out_file = coordinator->nexe_file_->write_wrapper(); if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, ld_subprocess, - "Link", - "", - ¶ms)) { - AbortLinkThread(p, "PnaclCoordinator link failed."); - } else { - // Grab the outparams. - p->nexe_wrapper.reset( - plugin->wrapper_factory()->MakeGeneric(params.outs()[0]->u.hval)); - int32_t nexe_size = params.outs()[1]->u.ival; // only for debug. - PLUGIN_PRINTF(("PnaclCoordinator::InvokeLink succeeded (bytes=%" - NACL_PRId32")\n", nexe_size)); - } + "RunWithDefaultCommandLine", + "ChiCC", + ¶ms, + service_string, + ld_out_file->desc(), + is_shared_library, + soname.c_str(), + lib_dependencies.c_str())) { + coordinator->TranslateFailed("link failed."); + } + PLUGIN_PRINTF(("PnaclCoordinator: link (coordinator=%p) succeeded\n", arg)); if (coordinator->SubprocessesShouldDie()) { + PLUGIN_PRINTF(( + "PnaclCoordinator::DoTranslateThread: killed by coordinator.\n")); NaClThreadExit(1); } pp::Core* core = pp::Module::Get()->core(); - core->CallOnMainThread(0, p->link_done_cb, PP_OK); + core->CallOnMainThread(0, coordinator->translate_done_cb_, PP_OK); NaClThreadExit(0); } -} // namespace +bool PnaclCoordinator::SubprocessesShouldDie() { + nacl::MutexLocker ml(&subprocess_mu_); + return subprocesses_should_die_; +} -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; - } - plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); - if (!StartLdSubProcess()) { - ErrorInfo error_info; - error_info.SetReport(ERROR_UNKNOWN, - "Could not start linker subprocess\n"); - ReportLoadError(error_info); - PnaclNonPpapiError(); - return; +void PnaclCoordinator::SetSubprocessesShouldDie(bool subprocesses_should_die) { + nacl::MutexLocker ml(&subprocess_mu_); + subprocesses_should_die_ = subprocesses_should_die; +} + +void PnaclCoordinator::LoadOneFile(int32_t pp_error, + const nacl::string& url, + nacl::DescWrapper** wrapper, + pp::CompletionCallback& done_cb) { + PLUGIN_PRINTF(("PnaclCoordinator::LoadOneFile (pp_error=%" + NACL_PRId32", url=%s)\n", pp_error, url.c_str())); + const nacl::string& full_url = resource_base_url_ + url; + pp::CompletionCallback callback = + callback_factory_.NewCallback(&PnaclCoordinator::DidLoadFile, + full_url, + wrapper, + done_cb); + if (!plugin_->StreamAsFile(full_url, callback.pp_completion_callback())) { + ReportNonPpapiError(nacl::string("failed to load ") + url + "\n"); } +} - // Invoke ld asynchronously. - // When ld has completed, PnaclDidFinish is run on the main thread. - translation_unit->link_done_cb = - callback_factory_.NewCallback(&PnaclCoordinator::PnaclDidFinish, - translation_unit); - link_thread_.reset(new NaClThread); - if (link_thread_ == NULL) { - ErrorInfo error_info; - error_info.SetReport(ERROR_UNKNOWN, - "Could not allocate DoLinkThread()\n"); - ReportLoadError(error_info); - PnaclNonPpapiError(); +void PnaclCoordinator::DidLoadFile(int32_t pp_error, + const nacl::string& full_url, + nacl::DescWrapper** wrapper, + pp::CompletionCallback& done_cb) { + PLUGIN_PRINTF(("PnaclCoordinator::DidLoadFile (pp_error=%" + NACL_PRId32", url=%s)\n", pp_error, full_url.c_str())); + int32_t fd = GetLoadedFileDesc(pp_error, full_url, "resource"); + if (fd < 0) { + PLUGIN_PRINTF(( + "PnaclCoordinator::DidLoadFile: GetLoadedFileDesc returned bad fd.\n")); 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(); - } + *wrapper = plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); + done_cb.Run(PP_OK); } -////////////////////////////////////////////////////////////////////// +void PnaclCoordinator::ResumeLookup(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclCoordinator::ResumeLookup (pp_error=%" + NACL_PRId32", url=%s)\n", pp_error)); + UNREFERENCED_PARAMETER(pp_error); + nacl::MutexLocker ml(&lookup_service_mu_); + lookup_is_complete_ = true; + NaClXCondVarBroadcast(&lookup_service_cv_); +} -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: " + - pexe_url + "\n"); - ReportLoadError(error_info); - PnaclNonPpapiError(); - } +// Lookup service called by translator nexes. +// TODO(sehr): replace this lookup by ReverseService. +void PnaclCoordinator::LookupInputFile(NaClSrpcRpc* rpc, + NaClSrpcArg** inputs, + NaClSrpcArg** outputs, + NaClSrpcClosure* done) { + PLUGIN_PRINTF(("PnaclCoordinator::LookupInputFile (url=%s)\n", + inputs[0]->arrays.str)); + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + const char* file_name = inputs[0]->arrays.str; + PnaclCoordinator* coordinator = reinterpret_cast<PnaclCoordinator*>( + rpc->channel->server_instance_data); + outputs[0]->u.hval = coordinator->LookupDesc(file_name); + rpc->result = NACL_SRPC_RESULT_OK; } -void PnaclCoordinator::BitcodeToNative( - const nacl::string& pexe_url, - const pp::CompletionCallback& finish_callback) { - PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (pexe=%s)\n", - pexe_url.c_str())); - // The base URL for finding all the resources will be obtained from the - // PNaCl manifest file. - // Also, the llc and ld pathnames should be read from the manifest. - // TODO(sehr): change to use the manifest file when ready. - resource_base_url_ = ResourceBaseUrl(); - llc_url_ = "llc"; - ld_url_ = "ld"; - translate_notify_callback_ = finish_callback; - - // Steps: - // (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. - - translation_unit_.reset(new PnaclTranslationUnit(this)); - - // When resources loading completes, this causes the pexe download. - pp::CompletionCallback resources_cb = - callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad, - pexe_url, - translation_unit_.get()); - 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) { - resources_->AddResourceUrl(*i); - } - resources_->RunWhenAllLoaded(resources_cb); - resources_->StartDownloads(); +NaClSrpcHandlerDesc PnaclCoordinator::lookup_methods[] = { + { "LookupInputFile:s:h", LookupInputFile }, + { NULL, NULL } +}; + +struct NaClDesc* PnaclCoordinator::LookupDesc(const nacl::string& url) { + PLUGIN_PRINTF(("PnaclCoordinator::LookupDesc (url=%s)\n", url.c_str())); + // This filename is part of the contract with the linker. It is a + // fake filename for the object file generated by llc and consumed by ld. + // TODO(sehr): Pass the FD in, and move lookup for this file to the linker. + const nacl::string kGeneratedObjectFileName = "___PNACL_GENERATED"; + if (url == kGeneratedObjectFileName) { + return obj_file_->read_wrapper()->desc(); + } + nacl::DescWrapper* wrapper; + // Create the callback used to report when lookup is done. + pp::CompletionCallback resume_cb = + callback_factory_.NewCallback(&PnaclCoordinator::ResumeLookup); + // Run the lookup request on the main thread. + lookup_is_complete_ = false; + pp::CompletionCallback load_cb = + callback_factory_.NewCallback(&PnaclCoordinator::LoadOneFile, + url, &wrapper, resume_cb); + pp::Core* core = pp::Module::Get()->core(); + core->CallOnMainThread(0, load_cb, PP_OK); + // Wait for completion (timeout every 10ms to check for process end). + const int32_t kTenMilliseconds = 10 * 1000 * 1000; + NACL_TIMESPEC_T reltime; + reltime.tv_sec = 0; + reltime.tv_nsec = kTenMilliseconds; + NaClXMutexLock(&lookup_service_mu_); + while (!lookup_is_complete_) { + // Check for termination. + if (SubprocessesShouldDie()) { + NaClXMutexUnlock(&lookup_service_mu_); + NaClThreadExit(0); + } + NaClXCondVarTimedWaitRelative(&lookup_service_cv_, + &lookup_service_mu_, + &reltime); + } + NaClXMutexUnlock(&lookup_service_mu_); + return wrapper->desc(); } } // 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 3a0a83a..15557ca 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h @@ -12,169 +12,304 @@ #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; - - // Borrowed reference which must outlive the thread. - nacl::scoped_ptr<nacl::DescWrapper> pexe_wrapper; - - // Object file produced by translator and consumed by the linker. - nacl::scoped_ptr<nacl::DescWrapper> obj_wrapper; - int32_t obj_len; - - // Information extracted from the pexe that is needed by the linker. - bool is_shared_library; - nacl::string soname; - nacl::string lib_dependencies; +// 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) +// + +// 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(); } - // The translated user nexe file. - nacl::scoped_ptr<nacl::DescWrapper> nexe_wrapper; + private: + NACL_DISALLOW_COPY_AND_ASSIGN(PnaclFileDescPair); - // Callbacks to run when tasks or completed or an error has occurred. - pp::CompletionCallback translate_done_cb; - pp::CompletionCallback link_done_cb; + // 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); - ErrorInfo error_info; + 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_; }; +// 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_; + } -typedef std::pair<nacl::string, pp::CompletionCallback> url_callback_pair; + private: + int32_t ref_; + struct NaClMutex mu_; +}; -// 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_. +// +// The coordinator proceeds through several states. They are +// LOAD_TRANSLATOR_BINARIES +// Complete when ResourcesDidLoad is invoked. +// OPEN_LOCAL_FILE_SYSTEM +// Complete when FileSystemDidOpen is invoked. +// OPEN_TMP_FOP_LLC_TO_LD_COMMUNICATION +// Complete when ObjectPairDidOpen is invoked. +// OPEN_TMP_FOR_LD_TO_SEL_LDR_COMMUNICATION +// Complete when NexePairDidOpen is invoked. +// PREPARE_PEXE_FOR_STREAMING +// Complete when RunTranslate is invoked. +// START_LD_AND_LLC_SUBPROCESS_AND_INITIATE_TRANSLATION +// Complete when RunTranslate returns. +// TRANSLATION_COMPLETE +// Complete when TranslateFinished is invoked. +// +// 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); - - void BitcodeToNative(const nacl::string& pexe_url, - const pp::CompletionCallback& finish_callback); + // The factory method for translations. + static PnaclCoordinator* BitcodeToNative( + Plugin* plugin, + const nacl::string& pexe_url, + 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(); - } + 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); - - // 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(); } - - protected: - - // Callbacks for when various files, etc. have been downloaded. - 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, - const nacl::string& url, - PnaclTranslationUnit* translation_unit); - void RunLink(int32_t pp_error, PnaclTranslationUnit* translation_unit); - - // Pnacl translation completed normally. - void PnaclDidFinish(int32_t pp_error, PnaclTranslationUnit* translation_unit); + 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); 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 pp::CompletionCallback& translate_notify_callback, + const nacl::string& resource_base_url); + + // 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 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); + + // 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 TranslateFinished(int32_t pp_error); + // Signal that Pnacl translation failed, from the translation thread only. + void TranslateFailed(const nacl::string& error_string); + + // 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_; - - // An auxiliary class that manages downloaded resources. + // 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_; + + // 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_; }; //---------------------------------------------------------------------- diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc index 97059db..0a86d5a 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc @@ -32,57 +32,29 @@ PnaclResources::~PnaclResources() { 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); + PLUGIN_PRINTF(("PnaclResources::StartDownloads\n")); // 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)); - - // All resource URLs are relative to the coordinator's resource_base_url(). - nacl::string resource_base_url = coordinator_->resource_base_url(); + 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& full_url = resource_base_url + resource_urls_[i]; + const nacl::string& full_url = resource_base_url_ + resource_urls_[i]; pp::CompletionCallback ready_callback = callback_factory_.NewCallback(&PnaclResources::ResourceReady, resource_urls_[i], full_url); if (!plugin_->StreamAsFile(full_url, ready_callback.pp_completion_callback())) { - ErrorInfo error_info; - error_info.SetReport(ERROR_UNKNOWN, - "PnaclCoordinator: Failed to download file: " + - resource_urls_[i] + "\n"); - coordinator_->ReportLoadError(error_info); - coordinator_->PnaclNonPpapiError(); + coordinator_->ReportNonPpapiError( + nacl::string("failed to download ") + resource_urls_[i] + "\n"); break; } } - resource_urls_.clear(); } void PnaclResources::ResourceReady(int32_t pp_error, @@ -95,7 +67,8 @@ void PnaclResources::ResourceReady(int32_t pp_error, full_url, "resource " + url); if (fd < 0) { - coordinator_->PnaclPpapiError(pp_error); + coordinator_->ReportPpapiError(pp_error, + "PnaclResources::ResourceReady failed.\n"); } else { resource_wrappers_[url] = plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); @@ -103,24 +76,4 @@ void PnaclResources::ResourceReady(int32_t pp_error, } } -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 index d23d4d5..d0d94d6 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_resources.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.h @@ -22,33 +22,34 @@ namespace plugin { class Plugin; class PnaclCoordinator; + +// Loads a list of remote resources, providing a way to get file descriptors for +// thse resources. All URLs in relative to resource_base_url_. class PnaclResources { public: - PnaclResources(Plugin* plugin, PnaclCoordinator* coordinator) + PnaclResources(Plugin* plugin, + PnaclCoordinator* coordinator, + const nacl::string& resource_base_url, + const std::vector<nacl::string>& resource_urls, + const pp::CompletionCallback& all_loaded_callback) : plugin_(plugin), coordinator_(coordinator), - all_loaded_(true), - client_callback_is_valid_(false) - { } + resource_urls_(resource_urls), + all_loaded_callback_(all_loaded_callback), + resource_base_url_(resource_base_url) { + callback_factory_.Initialize(this); + } virtual ~PnaclResources(); - void Initialize(); - - // URLs are all relative to the coordinator's resource_base_url(). - + // Start fetching the URLs. After construction, this is the first step. + void StartDownloads(); // Get the wrapper for the downloaded resource. + // Only valid after all_loaded_callback_ has been run. 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); @@ -56,25 +57,24 @@ class PnaclResources { void ResourceReady(int32_t pp_error, const nacl::string& url, const nacl::string& full_url); - // Callback invoked when all resources have been loaded. - void AllLoaded(int32_t pp_error); + // The plugin requesting the resource loading. Plugin* plugin_; + // The coordinator responsible for reporting errors, etc. PnaclCoordinator* coordinator_; + // The base url for looking up resources. + nacl::string resource_base_url_; + // The list of resource URLs (relative to resource_base_url_) to load. std::vector<nacl::string> resource_urls_; + // Callback to be invoked when all resources can be guaranteed available. + pp::CompletionCallback all_loaded_callback_; + // The descriptor wrappers for the downloaded URLs. Only valid + // once all_loaded_callback_ has been invoked. std::map<nacl::string, nacl::DescWrapper*> resource_wrappers_; + // Because we may be loading multiple resources, we need a callback that + // is invoked each time a resource arrives, and finally invokes + // all_loaded_callback_ when done. 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_; }; diff --git a/ppapi/native_client/src/trusted/plugin/srpc_client.cc b/ppapi/native_client/src/trusted/plugin/srpc_client.cc index 6ba8d57..83728df 100644 --- a/ppapi/native_client/src/trusted/plugin/srpc_client.cc +++ b/ppapi/native_client/src/trusted/plugin/srpc_client.cc @@ -165,4 +165,9 @@ bool SrpcClient::Invoke(uintptr_t method_id, return true; } +void SrpcClient::AttachService(NaClSrpcService* service, void* instance_data) { + srpc_channel_.server = service; + srpc_channel_.server_instance_data = instance_data; +} + } // namespace plugin diff --git a/ppapi/native_client/src/trusted/plugin/srpc_client.h b/ppapi/native_client/src/trusted/plugin/srpc_client.h index 545f608..0e72c68 100644 --- a/ppapi/native_client/src/trusted/plugin/srpc_client.h +++ b/ppapi/native_client/src/trusted/plugin/srpc_client.h @@ -48,6 +48,9 @@ class SrpcClient { bool Invoke(uintptr_t method_id, SrpcParams* params); bool InitParams(uintptr_t method_id, SrpcParams* params); + // Attach a service for reverse-direction (from .nexe) RPCs. + void AttachService(NaClSrpcService* service, void* instance_data); + private: NACL_DISALLOW_COPY_AND_ASSIGN(SrpcClient); SrpcClient(); |