| Index: ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
|
| ===================================================================
|
| --- ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc (revision 114253)
|
| +++ ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc (working copy)
|
| @@ -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 {
|
| -
|
| -typedef std::vector<nacl::string> string_vector;
|
| -int32_t kArbitraryStackSize = 128 << 10;
|
| -
|
| -} // namespace
|
| -
|
| namespace plugin {
|
|
|
| class Plugin;
|
|
|
| -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();
|
| +namespace {
|
| +
|
| +const char kLlcUrl[] = "llc";
|
| +const char kLdUrl[] = "ld";
|
| +
|
| +nacl::string ResourceBaseUrl() {
|
| + return nacl::string("pnacl_support/") + GetSandboxISA() + "/";
|
| }
|
|
|
| -PnaclCoordinator::~PnaclCoordinator() {
|
| - PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n",
|
| - static_cast<void*>(this)));
|
| +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);
|
|
|
| - // 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);
|
| + 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);
|
| }
|
| - if (translate_thread_.get() != NULL) {
|
| - NaClThreadJoin(translate_thread_.get());
|
| - }
|
| - if (link_thread_.get() != NULL) {
|
| - NaClThreadJoin(link_thread_.get());
|
| - }
|
| + return hex_string;
|
| }
|
|
|
| -void PnaclCoordinator::ReportLoadAbort() {
|
| - plugin_->ReportLoadAbort();
|
| +// Some constants for PnaclFileDescPair::GetFD readability.
|
| +const bool kReadOnly = false;
|
| +const bool kWriteable = true;
|
| +
|
| +} // 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::ReportLoadError(const ErrorInfo& error) {
|
| - plugin_->ReportLoadError(error);
|
| +PnaclFileDescPair::~PnaclFileDescPair() {
|
| + PLUGIN_PRINTF(("PnaclFileDescPair::~PnaclFileDescPair\n"));
|
| + NaClDescUnref(reinterpret_cast<NaClDesc*>(&rng_desc_));
|
| }
|
|
|
| -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);
|
| +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::PnaclNonPpapiError() {
|
| - PnaclPpapiError(PP_ERROR_FAILED);
|
| +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::PnaclDidFinish(int32_t pp_error,
|
| - PnaclTranslationUnit* translation_unit) {
|
| - PLUGIN_PRINTF(("PnaclCoordinator::PnaclDidFinish (pp_error=%"
|
| +void PnaclFileDescPair::WriteFileDidOpen(int32_t pp_error) {
|
| + PLUGIN_PRINTF(("PnaclFileDescPair::WriteFileDidOpen (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, *write_io_, kWriteable);
|
| + if (fd < 0) {
|
| + coordinator_->ReportNonPpapiError("could not open write 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);
|
| + 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 PnaclFileDescPair::ReadFileDidOpen(int32_t pp_error) {
|
| + PLUGIN_PRINTF(("PnaclFileDescPair::ReadFileDidOpen (pp_error=%"
|
| + NACL_PRId32")\n", 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;
|
| + }
|
| + 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();
|
| +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");
|
| + }
|
| +}
|
|
|
| - // 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" };
|
| +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);
|
| +}
|
|
|
| - 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::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;
|
| }
|
| + // 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);
|
| +}
|
|
|
| - 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::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;
|
| }
|
| + // Load the pexe file and get the translation started.
|
| + pp::CompletionCallback cb =
|
| + callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate);
|
|
|
| - if (coordinator->SubprocessesShouldDie()) {
|
| - NaClThreadExit(1);
|
| + if (!plugin_->StreamAsFile(pexe_url_, cb.pp_completion_callback())) {
|
| + ReportNonPpapiError(nacl::string("failed to download ") + pexe_url_ + "\n");
|
| }
|
| - 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()));
|
| - }
|
| - if (coordinator->SubprocessesShouldDie()) {
|
| - NaClThreadExit(1);
|
| - }
|
| - 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;
|
| }
|
| - // 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);
|
| + ld_subprocess_ = StartSubprocess(kLdUrl);
|
| + if (ld_subprocess_ == NULL) {
|
| + ReportPpapiError(PP_ERROR_FAILED);
|
| + return;
|
| + }
|
| + // 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");
|
| +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;
|
| }
|
| - 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;
|
| + return plugin_->nacl_subprocess(id);
|
| }
|
|
|
| -} // 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);
|
| -}
|
| -
|
| -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 + ".");
|
| + // 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.");
|
| }
|
| -
|
| - 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.");
|
| - }
|
| - }
|
| - }
|
| -
|
| + // 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;
|
| +}
|
|
|
| - // 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();
|
| - return;
|
| +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");
|
| }
|
| - 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();
|
| - }
|
| }
|
|
|
| -//////////////////////////////////////////////////////////////////////
|
| -
|
| -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);
|
| +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;
|
| }
|
| - pp::CompletionCallback cb =
|
| - callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate,
|
| - pexe_url,
|
| - translation);
|
| + *wrapper = plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY);
|
| + done_cb.Run(PP_OK);
|
| +}
|
|
|
| - 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();
|
| - }
|
| +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::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;
|
| +// 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;
|
| +}
|
|
|
| - // 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.
|
| +NaClSrpcHandlerDesc PnaclCoordinator::lookup_methods[] = {
|
| + { "LookupInputFile:s:h", LookupInputFile },
|
| + { NULL, NULL }
|
| +};
|
|
|
| - // 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);
|
| +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();
|
| }
|
| - resources_->RunWhenAllLoaded(resources_cb);
|
| - resources_->StartDownloads();
|
| + 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
|
|
|