diff options
author | dschuff@chromium.org <dschuff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-16 19:26:05 +0000 |
---|---|---|
committer | dschuff@chromium.org <dschuff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-16 19:26:05 +0000 |
commit | c1e3cefb7603bb0bac40cd8e73956e662504ee72 (patch) | |
tree | 0e949eaebd1a471d65970ad7d0c55c29e5fac057 /ppapi/native_client | |
parent | 52bf13415a1e4703d84aa703d2e125cd7c51b974 (diff) | |
download | chromium_src-c1e3cefb7603bb0bac40cd8e73956e662504ee72.zip chromium_src-c1e3cefb7603bb0bac40cd8e73956e662504ee72.tar.gz chromium_src-c1e3cefb7603bb0bac40cd8e73956e662504ee72.tar.bz2 |
Refactor Pnacl coordinator
Move compilation thread into its own class to make future multiple
implementations easier. Also split LocalTempFile into its own file to break
circular dependency.
R= sehr@google.com,jvoung@google.com,robertm@chromium.org
BUG=none
TEST=nacl_integration
Review URL: https://chromiumcodereview.appspot.com/10377157
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137481 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/native_client')
9 files changed, 689 insertions, 498 deletions
diff --git a/ppapi/native_client/src/trusted/plugin/local_temp_file.cc b/ppapi/native_client/src/trusted/plugin/local_temp_file.cc new file mode 100644 index 0000000..d22fbf8 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/local_temp_file.cc @@ -0,0 +1,242 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "native_client/src/trusted/plugin/local_temp_file.h" + +#include "native_client/src/include/portability_io.h" +#include "native_client/src/shared/platform/nacl_check.h" +#include "native_client/src/trusted/plugin/plugin.h" +#include "native_client/src/trusted/plugin/utility.h" + +#include "ppapi/c/ppb_file_io.h" +#include "ppapi/cpp/file_io.h" +#include "ppapi/cpp/file_ref.h" +#include "ppapi/cpp/file_system.h" + +////////////////////////////////////////////////////////////////////// +// Local temporary file access. +////////////////////////////////////////////////////////////////////// +namespace plugin { + +namespace { +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; +} + +// Some constants for LocalTempFile::GetFD readability. +const bool kReadOnly = false; +const bool kWriteable = true; +} // namespace + +uint32_t LocalTempFile::next_identifier = 0; + +LocalTempFile::LocalTempFile(Plugin* plugin, + pp::FileSystem* file_system, + const nacl::string &base_dir) + : plugin_(plugin), + file_system_(file_system), + base_dir_(base_dir) { + PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, " + "file_system=%p)\n", + static_cast<void*>(plugin), static_cast<void*>(file_system))); + Initialize(); +} + +LocalTempFile::LocalTempFile(Plugin* plugin, + pp::FileSystem* file_system, + const nacl::string &base_dir, + const nacl::string &filename) + : plugin_(plugin), + file_system_(file_system), + base_dir_(base_dir), + filename_(base_dir + "/" + filename) { + PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, " + "file_system=%p, filename=%s)\n", + static_cast<void*>(plugin), static_cast<void*>(file_system), + filename.c_str())); + file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); + Initialize(); +} + +void LocalTempFile::Initialize() { + callback_factory_.Initialize(this); + rng_desc_ = (struct NaClDescRng *) malloc(sizeof *rng_desc_); + CHECK(rng_desc_ != NULL); + CHECK(NaClDescRngCtor(rng_desc_)); + file_io_trusted_ = static_cast<const PPB_FileIOTrusted*>( + pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); + ++next_identifier; + SNPRINTF(reinterpret_cast<char *>(identifier_), sizeof identifier_, + "%"NACL_PRIu32, next_identifier); +} + +LocalTempFile::~LocalTempFile() { + PLUGIN_PRINTF(("LocalTempFile::~LocalTempFile\n")); + NaClDescUnref(reinterpret_cast<NaClDesc*>(rng_desc_)); +} + +void LocalTempFile::OpenWrite(const pp::CompletionCallback& cb) { + done_callback_ = cb; + // If we don't already have a filename, generate one. + if (filename_ == "") { + // Get a random temp file name. + filename_ = base_dir_ + "/" + Random32CharHexString(rng_desc_); + // Remember the ref used to open for writing and reading. + file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); + } + PLUGIN_PRINTF(("LocalTempFile::OpenWrite: %s\n", filename_.c_str())); + // Open the writeable file. + write_io_.reset(new pp::FileIO(plugin_)); + pp::CompletionCallback open_write_cb = + callback_factory_.NewCallback(&LocalTempFile::WriteFileDidOpen); + write_io_->Open(*file_ref_, + PP_FILEOPENFLAG_WRITE | + PP_FILEOPENFLAG_CREATE | + PP_FILEOPENFLAG_EXCLUSIVE, + open_write_cb); +} + +int32_t LocalTempFile::GetFD(int32_t pp_error, + const pp::Resource& resource, + bool is_writable) { + PLUGIN_PRINTF(("LocalTempFile::GetFD (pp_error=%"NACL_PRId32 + ", is_writable=%d)\n", pp_error, is_writable)); + if (pp_error != PP_OK) { + PLUGIN_PRINTF(("LocalTempFile::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(("LocalTempFile::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(("LocalTempFile::GetFD dup failed.\n")); + return -1; + } + return file_desc_ok_to_close; +} + +void LocalTempFile::WriteFileDidOpen(int32_t pp_error) { + PLUGIN_PRINTF(("LocalTempFile::WriteFileDidOpen (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error == PP_ERROR_FILEEXISTS) { + // Filenames clashed, retry. + filename_ = ""; + OpenWrite(done_callback_); + } + // Run the client's completion callback. + pp::Core* core = pp::Module::Get()->core(); + if (pp_error != PP_OK) { + core->CallOnMainThread(0, done_callback_, pp_error); + return; + } + // Remember the object temporary file descriptor. + int32_t fd = GetFD(pp_error, *write_io_, kWriteable); + if (fd < 0) { + core->CallOnMainThread(0, done_callback_, pp_error); + return; + } + // The descriptor for a writeable file needs to have quota management. + write_wrapper_.reset( + plugin_->wrapper_factory()->MakeFileDescQuota(fd, O_RDWR, identifier_)); + core->CallOnMainThread(0, done_callback_, PP_OK); +} + +void LocalTempFile::OpenRead(const pp::CompletionCallback& cb) { + PLUGIN_PRINTF(("LocalTempFile::OpenRead: %s\n", filename_.c_str())); + done_callback_ = cb; + // Open the read only file. + read_io_.reset(new pp::FileIO(plugin_)); + pp::CompletionCallback open_read_cb = + callback_factory_.NewCallback(&LocalTempFile::ReadFileDidOpen); + read_io_->Open(*file_ref_, PP_FILEOPENFLAG_READ, open_read_cb); +} + +void LocalTempFile::ReadFileDidOpen(int32_t pp_error) { + PLUGIN_PRINTF(("LocalTempFile::ReadFileDidOpen (pp_error=%" + NACL_PRId32")\n", pp_error)); + // Run the client's completion callback. + pp::Core* core = pp::Module::Get()->core(); + if (pp_error != PP_OK) { + core->CallOnMainThread(0, done_callback_, pp_error); + return; + } + // Remember the object temporary file descriptor. + int32_t fd = GetFD(pp_error, *read_io_, kReadOnly); + if (fd < 0) { + core->CallOnMainThread(0, done_callback_, PP_ERROR_FAILED); + return; + } + read_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); + core->CallOnMainThread(0, done_callback_, PP_OK); +} + +void LocalTempFile::Close(const pp::CompletionCallback& cb) { + PLUGIN_PRINTF(("LocalTempFile::Close: %s\n", filename_.c_str())); + // Close the open DescWrappers and FileIOs. + if (write_io_.get() != NULL) { + write_io_->Close(); + } + write_wrapper_.reset(NULL); + write_io_.reset(NULL); + if (read_io_.get() != NULL) { + read_io_->Close(); + } + read_wrapper_.reset(NULL); + read_io_.reset(NULL); + // Run the client's completion callback. + pp::Core* core = pp::Module::Get()->core(); + core->CallOnMainThread(0, cb, PP_OK); +} + +void LocalTempFile::Delete(const pp::CompletionCallback& cb) { + PLUGIN_PRINTF(("LocalTempFile::Delete: %s\n", filename_.c_str())); + file_ref_->Delete(cb); +} + +void LocalTempFile::Rename(const nacl::string& new_name, + const pp::CompletionCallback& cb) { + // Rename the temporary file. + filename_ = base_dir_ + "/" + new_name; + PLUGIN_PRINTF(("LocalTempFile::Rename %s to %s\n", + file_ref_->GetName().AsString().c_str(), + filename_.c_str())); + // Remember the old ref until the rename is complete. + old_ref_.reset(file_ref_.release()); + file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); + old_ref_->Rename(*file_ref_, cb); +} + +void LocalTempFile::FinishRename() { + // Now we can release the old ref. + old_ref_.reset(NULL); +} + +} // namespace plugin diff --git a/ppapi/native_client/src/trusted/plugin/local_temp_file.h b/ppapi/native_client/src/trusted/plugin/local_temp_file.h new file mode 100644 index 0000000..8b5078ed --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/local_temp_file.h @@ -0,0 +1,133 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_LOCAL_TEMP_FILE_H_ +#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_LOCAL_TEMP_FILE_H_ + +#include "native_client/src/include/nacl_macros.h" +#include "native_client/src/include/nacl_string.h" +#include "native_client/src/trusted/desc/nacl_desc_rng.h" +#include "native_client/src/trusted/desc/nacl_desc_wrapper.h" + +#include "ppapi/c/trusted/ppb_file_io_trusted.h" +#include "ppapi/utility/completion_callback_factory.h" + +namespace pp { +class CompletionCallback; +class FileIO; +class FileRef; +class FileSystem; +} + +namespace plugin { + +class Plugin; + +// 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: ld (passed in explicitly through SRPC) +// read by: sel_ldr (passed in explicitly to command channel) +// + +// LocalTempFile 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 LocalTempFile { + public: + // Create a LocalTempFile with a random name. + LocalTempFile(Plugin* plugin, + pp::FileSystem* file_system, + const nacl::string& base_dir); + // Create a LocalTempFile with a specific filename. + LocalTempFile(Plugin* plugin, + pp::FileSystem* file_system, + const nacl::string& base_dir, + const nacl::string& filename); + ~LocalTempFile(); + // Opens a writeable file IO object and descriptor referring to the file. + void OpenWrite(const pp::CompletionCallback& cb); + // Opens a read only file IO object and descriptor referring to the file. + void OpenRead(const pp::CompletionCallback& cb); + // Closes the open descriptors. + void Close(const pp::CompletionCallback& cb); + // Deletes the temporary file. + void Delete(const pp::CompletionCallback& cb); + // Renames the temporary file. + void Rename(const nacl::string& new_name, + const pp::CompletionCallback& cb); + void FinishRename(); + + // Accessors. + // The nacl::DescWrapper* for the writeable version of the file. + nacl::DescWrapper* write_wrapper() { return write_wrapper_.get(); } + nacl::DescWrapper* release_write_wrapper() { + return write_wrapper_.release(); + } + // The nacl::DescWrapper* for the read-only version of the file. + nacl::DescWrapper* read_wrapper() { return read_wrapper_.get(); } + nacl::DescWrapper* release_read_wrapper() { + return read_wrapper_.release(); + } + // For quota management. + const nacl::string identifier() const { + return nacl::string(reinterpret_cast<const char*>(identifier_)); + } + const pp::FileIO& write_file_io() const { return *write_io_; } + + private: + NACL_DISALLOW_COPY_AND_ASSIGN(LocalTempFile); + + void Initialize(); + + // 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); + // Completes the close operation after quota update. + void CloseContinuation(int32_t pp_error); + + Plugin* plugin_; + pp::FileSystem* file_system_; + const PPB_FileIOTrusted* file_io_trusted_; + pp::CompletionCallbackFactory<LocalTempFile> callback_factory_; + nacl::string base_dir_; + nacl::string filename_; + nacl::scoped_ptr<pp::FileRef> file_ref_; + // Temporarily holds the previous file ref during a rename operation. + nacl::scoped_ptr<pp::FileRef> old_ref_; + // The PPAPI and wrapper state for the writeable file. + 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::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_; + // An identifier string used for quota request processing. The quota + // interface needs a string that is unique per sel_ldr instance only, so + // the identifiers can be reused between runs of the translator, start-ups of + // the browser, etc. + uint8_t identifier_[16]; + // A counter to dole out unique identifiers. + static uint32_t next_identifier; +}; + +} // namespace plugin + +#endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_LOCAL_TEMP_FILE_H_ diff --git a/ppapi/native_client/src/trusted/plugin/plugin.gypi b/ppapi/native_client/src/trusted/plugin/plugin.gypi index df9154f..3815daa 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.gypi +++ b/ppapi/native_client/src/trusted/plugin/plugin.gypi @@ -8,12 +8,14 @@ 'common_sources': [ 'file_downloader.cc', 'json_manifest.cc', + 'local_temp_file.cc', 'module_ppapi.cc', 'nacl_subprocess.cc', 'nexe_arch.cc', 'plugin.cc', 'pnacl_coordinator.cc', 'pnacl_resources.cc', + 'pnacl_translate_thread.cc', 'scriptable_plugin.cc', 'sel_ldr_launcher_chrome.cc', 'service_runtime.cc', diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc index c8d332c..0bc2178 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc @@ -9,260 +9,23 @@ #include "native_client/src/include/portability_io.h" #include "native_client/src/shared/platform/nacl_check.h" -#include "native_client/src/shared/platform/nacl_sync_raii.h" -#include "native_client/src/trusted/desc/nacl_desc_wrapper.h" +#include "native_client/src/trusted/plugin/local_temp_file.h" #include "native_client/src/trusted/plugin/manifest.h" -#include "native_client/src/trusted/plugin/nacl_subprocess.h" -#include "native_client/src/trusted/plugin/nexe_arch.h" #include "native_client/src/trusted/plugin/plugin.h" #include "native_client/src/trusted/plugin/plugin_error.h" +#include "native_client/src/trusted/plugin/pnacl_translate_thread.h" #include "native_client/src/trusted/plugin/service_runtime.h" -#include "native_client/src/trusted/plugin/srpc_params.h" -#include "native_client/src/trusted/plugin/utility.h" #include "native_client/src/trusted/service_runtime/include/sys/stat.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/ppb_file_io.h" #include "ppapi/cpp/file_io.h" -namespace plugin { - -class Plugin; - namespace { - -const char kLlcUrl[] = "llc"; -const char kLdUrl[] = "ld"; const char kPnaclTempDir[] = "/.pnacl"; - -nacl::string ExtensionUrl() { - // TODO(sehr,jvoung): Find a better way to express the URL for the pnacl - // extension than a constant string here. - const nacl::string kPnaclExtensionOrigin = - "chrome-extension://gcodniebolpnpaiggndmcmmfpldlknih/"; - return kPnaclExtensionOrigin + GetSandboxISA() + "/"; -} - -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; -} - -// Some constants for PnaclFileDescPair::GetFD readability. -const bool kReadOnly = false; -const bool kWriteable = true; -} // namespace - -////////////////////////////////////////////////////////////////////// -// Local temporary file access. -////////////////////////////////////////////////////////////////////// - -uint32_t LocalTempFile::next_identifier = 0; - -LocalTempFile::LocalTempFile(Plugin* plugin, - pp::FileSystem* file_system) - : plugin_(plugin), - file_system_(file_system) { - PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, " - "file_system=%p)\n", - static_cast<void*>(plugin), static_cast<void*>(file_system))); - Initialize(); -} - -LocalTempFile::LocalTempFile(Plugin* plugin, - pp::FileSystem* file_system, - const nacl::string &filename) - : plugin_(plugin), - file_system_(file_system), - filename_(nacl::string(kPnaclTempDir) + "/" + filename) { - PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, " - "file_system=%p, filename=%s)\n", - static_cast<void*>(plugin), static_cast<void*>(file_system), - filename.c_str())); - file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); - Initialize(); -} - -void LocalTempFile::Initialize() { - callback_factory_.Initialize(this); - rng_desc_ = (struct NaClDescRng *) malloc(sizeof *rng_desc_); - CHECK(rng_desc_ != NULL); - CHECK(NaClDescRngCtor(rng_desc_)); - file_io_trusted_ = static_cast<const PPB_FileIOTrusted*>( - pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); - ++next_identifier; - SNPRINTF(reinterpret_cast<char *>(identifier_), sizeof identifier_, - "%"NACL_PRIu32, next_identifier); -} - -LocalTempFile::~LocalTempFile() { - PLUGIN_PRINTF(("LocalTempFile::~LocalTempFile\n")); - NaClDescUnref(reinterpret_cast<NaClDesc*>(rng_desc_)); -} - -void LocalTempFile::OpenWrite(const pp::CompletionCallback& cb) { - done_callback_ = cb; - // If we don't already have a filename, generate one. - if (filename_ == "") { - // Get a random temp file name. - filename_ = - nacl::string(kPnaclTempDir) + "/" + Random32CharHexString(rng_desc_); - // Remember the ref used to open for writing and reading. - file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); - } - PLUGIN_PRINTF(("LocalTempFile::OpenWrite: %s\n", filename_.c_str())); - // Open the writeable file. - write_io_.reset(new pp::FileIO(plugin_)); - pp::CompletionCallback open_write_cb = - callback_factory_.NewCallback(&LocalTempFile::WriteFileDidOpen); - write_io_->Open(*file_ref_, - PP_FILEOPENFLAG_WRITE | - PP_FILEOPENFLAG_CREATE | - PP_FILEOPENFLAG_EXCLUSIVE, - open_write_cb); -} - -int32_t LocalTempFile::GetFD(int32_t pp_error, - const pp::Resource& resource, - bool is_writable) { - PLUGIN_PRINTF(("LocalTempFile::GetFD (pp_error=%"NACL_PRId32 - ", is_writable=%d)\n", pp_error, is_writable)); - if (pp_error != PP_OK) { - PLUGIN_PRINTF(("LocalTempFile::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(("LocalTempFile::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(("LocalTempFile::GetFD dup failed.\n")); - return -1; - } - return file_desc_ok_to_close; -} - -void LocalTempFile::WriteFileDidOpen(int32_t pp_error) { - PLUGIN_PRINTF(("LocalTempFile::WriteFileDidOpen (pp_error=%" - NACL_PRId32")\n", pp_error)); - if (pp_error == PP_ERROR_FILEEXISTS) { - // Filenames clashed, retry. - filename_ = ""; - OpenWrite(done_callback_); - } - // Run the client's completion callback. - pp::Core* core = pp::Module::Get()->core(); - if (pp_error != PP_OK) { - core->CallOnMainThread(0, done_callback_, pp_error); - return; - } - // Remember the object temporary file descriptor. - int32_t fd = GetFD(pp_error, *write_io_, kWriteable); - if (fd < 0) { - core->CallOnMainThread(0, done_callback_, pp_error); - return; - } - // The descriptor for a writeable file needs to have quota management. - write_wrapper_.reset( - plugin_->wrapper_factory()->MakeFileDescQuota(fd, O_RDWR, identifier_)); - core->CallOnMainThread(0, done_callback_, PP_OK); -} - -void LocalTempFile::OpenRead(const pp::CompletionCallback& cb) { - PLUGIN_PRINTF(("LocalTempFile::OpenRead: %s\n", filename_.c_str())); - done_callback_ = cb; - // Open the read only file. - read_io_.reset(new pp::FileIO(plugin_)); - pp::CompletionCallback open_read_cb = - callback_factory_.NewCallback(&LocalTempFile::ReadFileDidOpen); - read_io_->Open(*file_ref_, PP_FILEOPENFLAG_READ, open_read_cb); -} - -void LocalTempFile::ReadFileDidOpen(int32_t pp_error) { - PLUGIN_PRINTF(("LocalTempFile::ReadFileDidOpen (pp_error=%" - NACL_PRId32")\n", pp_error)); - // Run the client's completion callback. - pp::Core* core = pp::Module::Get()->core(); - if (pp_error != PP_OK) { - core->CallOnMainThread(0, done_callback_, pp_error); - return; - } - // Remember the object temporary file descriptor. - int32_t fd = GetFD(pp_error, *read_io_, kReadOnly); - if (fd < 0) { - core->CallOnMainThread(0, done_callback_, PP_ERROR_FAILED); - return; - } - read_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); - core->CallOnMainThread(0, done_callback_, PP_OK); -} - -void LocalTempFile::Close(const pp::CompletionCallback& cb) { - PLUGIN_PRINTF(("LocalTempFile::Close: %s\n", filename_.c_str())); - // Close the open DescWrappers and FileIOs. - if (write_io_.get() != NULL) { - write_io_->Close(); - } - write_wrapper_.reset(NULL); - write_io_.reset(NULL); - if (read_io_.get() != NULL) { - read_io_->Close(); - } - read_wrapper_.reset(NULL); - read_io_.reset(NULL); - // Run the client's completion callback. - pp::Core* core = pp::Module::Get()->core(); - core->CallOnMainThread(0, cb, PP_OK); -} - -void LocalTempFile::Delete(const pp::CompletionCallback& cb) { - PLUGIN_PRINTF(("LocalTempFile::Delete: %s\n", filename_.c_str())); - file_ref_->Delete(cb); -} - -void LocalTempFile::Rename(const nacl::string& new_name, - const pp::CompletionCallback& cb) { - // Rename the temporary file. - filename_ = nacl::string(kPnaclTempDir) + "/" + new_name; - PLUGIN_PRINTF(("LocalTempFile::Rename %s to %s\n", - file_ref_->GetName().AsString().c_str(), - filename_.c_str())); - // Remember the old ref until the rename is complete. - old_ref_.reset(file_ref_.release()); - file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); - old_ref_->Rename(*file_ref_, cb); -} - -void LocalTempFile::FinishRename() { - // Now we can release the old ref. - old_ref_.reset(NULL); } +namespace plugin { ////////////////////////////////////////////////////////////////////// // Pnacl-specific manifest support. @@ -271,7 +34,7 @@ class ExtensionManifest : public Manifest { public: explicit ExtensionManifest(const pp::URLUtil_Dev* url_util) : url_util_(url_util), - manifest_base_url_(ExtensionUrl()) { } + manifest_base_url_(PnaclUrls::GetExtensionUrl()) { } virtual ~ExtensionManifest() { } virtual bool GetProgramURL(nacl::string* full_url, @@ -416,8 +179,8 @@ PnaclCoordinator* PnaclCoordinator::BitcodeToNative( reinterpret_cast<const void*>(coordinator->manifest_.get()))); // Load llc and ld. std::vector<nacl::string> resource_urls; - resource_urls.push_back(kLlcUrl); - resource_urls.push_back(kLdUrl); + resource_urls.push_back(PnaclUrls::GetLlcUrl()); + resource_urls.push_back(PnaclUrls::GetLdUrl()); pp::CompletionCallback resources_cb = coordinator->callback_factory_.NewCallback( &PnaclCoordinator::ResourcesDidLoad); @@ -459,7 +222,6 @@ PnaclCoordinator::PnaclCoordinator( const pp::CompletionCallback& translate_notify_callback) : plugin_(plugin), translate_notify_callback_(translate_notify_callback), - subprocesses_should_die_(false), file_system_(new pp::FileSystem(plugin, PP_FILESYSTEMTYPE_LOCALTEMPORARY)), manifest_(new ExtensionManifest(plugin->url_util())), pexe_url_(pexe_url), @@ -468,7 +230,6 @@ PnaclCoordinator::PnaclCoordinator( PLUGIN_PRINTF(("PnaclCoordinator::PnaclCoordinator (this=%p, plugin=%p)\n", static_cast<void*>(this), static_cast<void*>(plugin))); callback_factory_.Initialize(this); - NaClXMutexCtor(&subprocess_mu_); ld_manifest_.reset(new PnaclLDManifest(plugin_->manifest(), manifest_.get())); } @@ -481,9 +242,8 @@ PnaclCoordinator::~PnaclCoordinator() { // will have been destroyed. This will result in the cancellation of // translation_complete_callback_, so no notification will be delivered. if (translate_thread_.get() != NULL) { - SetSubprocessesShouldDie(true); + translate_thread_->SetSubprocessesShouldDie(true); } - NaClMutexDtor(&subprocess_mu_); } void PnaclCoordinator::ReportNonPpapiError(const nacl::string& message) { @@ -521,6 +281,7 @@ void PnaclCoordinator::ReportPpapiError(int32_t pp_error) { } } +// Signal that Pnacl translation completed normally. void PnaclCoordinator::TranslateFinished(int32_t pp_error) { PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%" NACL_PRId32")\n", pp_error)); @@ -627,15 +388,6 @@ void PnaclCoordinator::NexeFileWasDeleted(int32_t pp_error) { ReportPpapiError(translate_finish_error_); } -void PnaclCoordinator::TranslateFailed(const nacl::string& error_string) { - PLUGIN_PRINTF(("PnaclCoordinator::TranslateFailed (error_string='%s')\n", - error_string.c_str())); - pp::Core* core = pp::Module::Get()->core(); - error_info_.SetReport(ERROR_UNKNOWN, - nacl::string("PnaclCoordinator: ") + error_string); - core->CallOnMainThread(0, report_translate_finished_, PP_ERROR_FAILED); -} - void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) { PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%" NACL_PRId32")\n", pp_error)); @@ -659,7 +411,8 @@ void PnaclCoordinator::FileSystemDidOpen(int32_t pp_error) { ReportPpapiError(pp_error, "file system didn't open."); return; } - dir_ref_.reset(new pp::FileRef(*file_system_, kPnaclTempDir)); + dir_ref_.reset(new pp::FileRef(*file_system_, + kPnaclTempDir)); dir_io_.reset(new pp::FileIO(plugin_)); // Attempt to create the directory. pp::CompletionCallback cb = @@ -677,6 +430,7 @@ void PnaclCoordinator::DirectoryWasCreated(int32_t pp_error) { } if (cache_identity_ != "") { nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), + nacl::string(kPnaclTempDir), cache_identity_)); pp::CompletionCallback cb = callback_factory_.NewCallback(&PnaclCoordinator::CachedFileDidOpen); @@ -714,7 +468,8 @@ void PnaclCoordinator::BitcodeFileDidOpen(int32_t pp_error) { } pexe_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); - obj_file_.reset(new LocalTempFile(plugin_, file_system_.get())); + obj_file_.reset(new LocalTempFile(plugin_, file_system_.get(), + nacl::string(kPnaclTempDir))); pp::CompletionCallback cb = callback_factory_.NewCallback(&PnaclCoordinator::ObjectWriteDidOpen); obj_file_->OpenWrite(cb); @@ -741,7 +496,8 @@ void PnaclCoordinator::ObjectReadDidOpen(int32_t pp_error) { } // Create the nexe file for connecting ld and sel_ldr. // Start translation when done with this last step of setup! - nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get())); + nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), + nacl::string(kPnaclTempDir))); pp::CompletionCallback cb = callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate); nexe_file_->OpenWrite(cb); @@ -752,121 +508,22 @@ void PnaclCoordinator::RunTranslate(int32_t pp_error) { NACL_PRId32")\n", pp_error)); // Invoke llc followed by ld off the main thread. This allows use of // blocking RPCs that would otherwise block the JavaScript main thread. - report_translate_finished_ = + pp::CompletionCallback report_translate_finished = callback_factory_.NewCallback(&PnaclCoordinator::TranslateFinished); - translate_thread_.reset(new NaClThread); + translate_thread_.reset(new PnaclTranslateThread()); if (translate_thread_ == NULL) { - ReportNonPpapiError("could not allocate thread struct."); + ReportNonPpapiError("could not allocate translation thread."); return; } - const int32_t kArbitraryStackSize = 128 * 1024; - if (!NaClThreadCreateJoinable(translate_thread_.get(), - DoTranslateThread, - this, - kArbitraryStackSize)) { - ReportNonPpapiError("could not create thread."); - } -} - -NaClSubprocess* PnaclCoordinator::StartSubprocess( - const nacl::string& url_for_nexe, - const Manifest* manifest) { - PLUGIN_PRINTF(("PnaclCoordinator::StartSubprocess (url_for_nexe=%s)\n", - url_for_nexe.c_str())); - nacl::DescWrapper* wrapper = resources_->WrapperForUrl(url_for_nexe); - nacl::scoped_ptr<NaClSubprocess> subprocess( - plugin_->LoadHelperNaClModule(wrapper, manifest, &error_info_)); - if (subprocess.get() == NULL) { - PLUGIN_PRINTF(( - "PnaclCoordinator::StartSubprocess: subprocess creation failed\n")); - return NULL; - } - return subprocess.release(); -} - -// 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); - - nacl::scoped_ptr<NaClSubprocess> llc_subprocess( - coordinator->StartSubprocess(kLlcUrl, coordinator->manifest_.get())); - if (llc_subprocess == NULL) { - coordinator->TranslateFailed("Compile process could not be created."); - return; - } - // Run LLC. - SrpcParams params; - nacl::DescWrapper* llc_out_file = coordinator->obj_file_->write_wrapper(); - PluginReverseInterface* llc_reverse = - llc_subprocess->service_runtime()->rev_interface(); - llc_reverse->AddQuotaManagedFile(coordinator->obj_file_->identifier(), - coordinator->obj_file_->write_file_io()); - if (!llc_subprocess->InvokeSrpcMethod("RunWithDefaultCommandLine", - "hh", - ¶ms, - coordinator->pexe_wrapper_->desc(), - llc_out_file->desc())) { - coordinator->TranslateFailed("compile failed."); - return; - } - // 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())); - // Shut down the llc subprocess. - llc_subprocess.reset(NULL); - if (coordinator->SubprocessesShouldDie()) { - coordinator->TranslateFailed("stopped by coordinator."); - return; - } - nacl::scoped_ptr<NaClSubprocess> ld_subprocess( - coordinator->StartSubprocess(kLdUrl, coordinator->ld_manifest_.get())); - if (ld_subprocess == NULL) { - coordinator->TranslateFailed("Link process could not be created."); - return; - } - // Run LD. - nacl::DescWrapper* ld_in_file = coordinator->obj_file_->read_wrapper(); - nacl::DescWrapper* ld_out_file = coordinator->nexe_file_->write_wrapper(); - PluginReverseInterface* ld_reverse = - ld_subprocess->service_runtime()->rev_interface(); - ld_reverse->AddQuotaManagedFile(coordinator->nexe_file_->identifier(), - coordinator->nexe_file_->write_file_io()); - if (!ld_subprocess->InvokeSrpcMethod("RunWithDefaultCommandLine", - "hhiCC", - ¶ms, - ld_in_file->desc(), - ld_out_file->desc(), - is_shared_library, - soname.c_str(), - lib_dependencies.c_str())) { - coordinator->TranslateFailed("link failed."); - return; - } - PLUGIN_PRINTF(("PnaclCoordinator: link (coordinator=%p) succeeded\n", arg)); - // Shut down the ld subprocess. - ld_subprocess.reset(NULL); - if (coordinator->SubprocessesShouldDie()) { - coordinator->TranslateFailed("stopped by coordinator."); - return; - } - pp::Core* core = pp::Module::Get()->core(); - core->CallOnMainThread(0, coordinator->report_translate_finished_, PP_OK); -} - -bool PnaclCoordinator::SubprocessesShouldDie() { - nacl::MutexLocker ml(&subprocess_mu_); - return subprocesses_should_die_; -} - -void PnaclCoordinator::SetSubprocessesShouldDie(bool subprocesses_should_die) { - nacl::MutexLocker ml(&subprocess_mu_); - subprocesses_should_die_ = subprocesses_should_die; + translate_thread_->RunTranslate(report_translate_finished, + manifest_.get(), + ld_manifest_.get(), + obj_file_.get(), + nexe_file_.get(), + pexe_wrapper_.get(), + &error_info_, + resources_.get(), + plugin_); } } // 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 5643a6d..96f8cbd 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h @@ -11,13 +11,13 @@ #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/local_temp_file.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" @@ -29,114 +29,13 @@ #include "ppapi/cpp/file_ref.h" #include "ppapi/cpp/file_system.h" -struct NaClMutex; namespace plugin { class Manifest; class Plugin; class PnaclCoordinator; - -// 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: ld (passed in explicitly through SRPC) -// read by: sel_ldr (passed in explicitly to command channel) -// - -// LocalTempFile 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 LocalTempFile { - public: - // Create a LocalTempFile with a random name. - LocalTempFile(Plugin* plugin, - pp::FileSystem* file_system); - // Create a LocalTempFile with a specific filename. - LocalTempFile(Plugin* plugin, - pp::FileSystem* file_system, - const nacl::string& filename); - ~LocalTempFile(); - // Opens a writeable file IO object and descriptor referring to the file. - void OpenWrite(const pp::CompletionCallback& cb); - // Opens a read only file IO object and descriptor referring to the file. - void OpenRead(const pp::CompletionCallback& cb); - // Closes the open descriptors. - void Close(const pp::CompletionCallback& cb); - // Deletes the temporary file. - void Delete(const pp::CompletionCallback& cb); - // Renames the temporary file. - void Rename(const nacl::string& new_name, - const pp::CompletionCallback& cb); - void FinishRename(); - - // Accessors. - // The nacl::DescWrapper* for the writeable version of the file. - nacl::DescWrapper* write_wrapper() { return write_wrapper_.get(); } - nacl::DescWrapper* release_write_wrapper() { - return write_wrapper_.release(); - } - // The nacl::DescWrapper* for the read-only version of the file. - nacl::DescWrapper* read_wrapper() { return read_wrapper_.get(); } - nacl::DescWrapper* release_read_wrapper() { - return read_wrapper_.release(); - } - // For quota management. - const nacl::string identifier() const { - return nacl::string(reinterpret_cast<const char*>(identifier_)); - } - const pp::FileIO& write_file_io() const { return *write_io_; } - - private: - NACL_DISALLOW_COPY_AND_ASSIGN(LocalTempFile); - - void Initialize(); - - // 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); - // Completes the close operation after quota update. - void CloseContinuation(int32_t pp_error); - - Plugin* plugin_; - pp::FileSystem* file_system_; - const PPB_FileIOTrusted* file_io_trusted_; - pp::CompletionCallbackFactory<LocalTempFile> callback_factory_; - nacl::string filename_; - nacl::scoped_ptr<pp::FileRef> file_ref_; - // Temporarily holds the previous file ref during a rename operation. - nacl::scoped_ptr<pp::FileRef> old_ref_; - // The PPAPI and wrapper state for the writeable file. - 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::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_; - // An identifier string used for quota request processing. The quota - // interface needs a string that is unique per sel_ldr instance only, so - // the identifiers can be reused between runs of the translator, start-ups of - // the browser, etc. - uint8_t identifier_[16]; - // A counter to dole out unique identifiers. - static uint32_t next_identifier; -}; +class PnaclTranslateThread; // A thread safe reference counting class Needed for CompletionCallbackFactory // in PnaclCoordinator. @@ -284,25 +183,12 @@ class PnaclCoordinator { // 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, - const Manifest* manifest); - // 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); // Keeps track of the pp_error upon entry to TranslateFinished, // for inspection after cleanup. int32_t translate_finish_error_; - // Signal that Pnacl translation failed, from the translation thread only. - void TranslateFailed(const nacl::string& error_string); - // The plugin owning the nexe for which we are doing translation. Plugin* plugin_; @@ -312,16 +198,11 @@ class PnaclCoordinator { pp::CompletionCallbackFactory<PnaclCoordinator, PnaclRefCount> callback_factory_; - // True if the translation thread and related 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_; // The helper thread used to do translations via SRPC. - nacl::scoped_ptr<NaClThread> translate_thread_; + nacl::scoped_ptr<PnaclTranslateThread> translate_thread_; // Translation creates local temporary files. nacl::scoped_ptr<pp::FileSystem> file_system_; // The manifest used by resource loading and llc's reverse service to look up @@ -352,8 +233,6 @@ class PnaclCoordinator { nacl::scoped_ptr<LocalTempFile> obj_file_; // Translated nexe file, produced by the linker and consumed by sel_ldr. nacl::scoped_ptr<LocalTempFile> nexe_file_; - // Callback to run when tasks are completed or an error has occurred. - pp::CompletionCallback report_translate_finished_; // Used to report information when errors (PPAPI or otherwise) are reported. ErrorInfo error_info_; diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc index 0053251..e720f86 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc @@ -16,6 +16,11 @@ namespace plugin { +const char PnaclUrls::kExtensionOrigin[] = + "chrome-extension://gcodniebolpnpaiggndmcmmfpldlknih/"; +const char PnaclUrls::kLlcUrl[] = "llc"; +const char PnaclUrls::kLdUrl[] = "ld"; + PnaclResources::~PnaclResources() { for (std::map<nacl::string, nacl::DescWrapper*>::iterator i = resource_wrappers_.begin(), e = resource_wrappers_.end(); diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.h b/ppapi/native_client/src/trusted/plugin/pnacl_resources.h index 2d8b356..5f1ca97 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_resources.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,6 +13,7 @@ #include "native_client/src/shared/srpc/nacl_srpc.h" #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" #include "native_client/src/trusted/plugin/delayed_callback.h" +#include "native_client/src/trusted/plugin/nexe_arch.h" #include "native_client/src/trusted/plugin/plugin_error.h" #include "ppapi/utility/completion_callback_factory.h" @@ -22,6 +23,18 @@ class Manifest; class Plugin; class PnaclCoordinator; +class PnaclUrls { + public: + static nacl::string GetExtensionUrl() { + return nacl::string(kExtensionOrigin) + GetSandboxISA() + "/"; + } + static const nacl::string GetLlcUrl() { return nacl::string(kLlcUrl); } + static const nacl::string GetLdUrl() { return nacl::string(kLdUrl); } + private: + static const char kExtensionOrigin[]; + static const char kLlcUrl[]; + static const char kLdUrl[]; +}; // Loads a list of remote resources, providing a way to get file descriptors for // thse resources. All URLs in relative to resource_base_url_. diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc new file mode 100644 index 0000000..84960b7 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc @@ -0,0 +1,177 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "native_client/src/trusted/plugin/pnacl_translate_thread.h" + +#include "native_client/src/trusted/desc/nacl_desc_wrapper.h" +#include "native_client/src/trusted/plugin/plugin.h" +#include "native_client/src/trusted/plugin/pnacl_resources.h" +#include "native_client/src/trusted/plugin/srpc_params.h" +#include "native_client/src/trusted/plugin/utility.h" + +namespace plugin { + +PnaclTranslateThread::PnaclTranslateThread() : subprocesses_should_die_(false), + manifest_(NULL), + obj_file_(NULL), + nexe_file_(NULL), + pexe_wrapper_(NULL), + error_info_(NULL), + resources_(NULL), + plugin_(NULL) { + NaClXMutexCtor(&subprocess_mu_); +} + +void PnaclTranslateThread::RunTranslate(pp::CompletionCallback finish_callback, + const Manifest* manifest, + const Manifest* ld_manifest, + LocalTempFile* obj_file, + LocalTempFile* nexe_file, + nacl::DescWrapper* pexe_wrapper, + ErrorInfo* error_info, + PnaclResources* resources, + Plugin* plugin) { + PLUGIN_PRINTF(("PnaclTranslateThread::RunTranslate)\n")); + manifest_ = manifest; + ld_manifest_ = ld_manifest; + obj_file_ = obj_file; + nexe_file_ = nexe_file; + pexe_wrapper_ = pexe_wrapper; + error_info_ = error_info; + resources_ = resources; + plugin_ = plugin; + + // Invoke llc followed by ld off the main thread. This allows use of + // blocking RPCs that would otherwise block the JavaScript main thread. + report_translate_finished_ = finish_callback; + translate_thread_.reset(new NaClThread); + if (translate_thread_ == NULL) { + TranslateFailed("could not allocate thread struct."); + return; + } + const int32_t kArbitraryStackSize = 128 * 1024; + if (!NaClThreadCreateJoinable(translate_thread_.get(), + DoTranslateThread, + this, + kArbitraryStackSize)) { + TranslateFailed("could not create thread."); + } +} + +NaClSubprocess* PnaclTranslateThread::StartSubprocess( + const nacl::string& url_for_nexe, + const Manifest* manifest) { + PLUGIN_PRINTF(("PnaclTranslateThread::StartSubprocess (url_for_nexe=%s)\n", + url_for_nexe.c_str())); + nacl::DescWrapper* wrapper = resources_->WrapperForUrl(url_for_nexe); + nacl::scoped_ptr<NaClSubprocess> subprocess( + plugin_->LoadHelperNaClModule(wrapper, manifest, error_info_)); + if (subprocess.get() == NULL) { + PLUGIN_PRINTF(( + "PnaclTranslateThread::StartSubprocess: subprocess creation failed\n")); + return NULL; + } + return subprocess.release(); +} + +void WINAPI PnaclTranslateThread::DoTranslateThread(void* arg) { + PnaclTranslateThread* translator = + reinterpret_cast<PnaclTranslateThread*>(arg); + nacl::scoped_ptr<NaClSubprocess> llc_subprocess( + translator->StartSubprocess(PnaclUrls::GetLlcUrl(), + translator->manifest_)); + if (llc_subprocess == NULL) { + translator->TranslateFailed("Compile process could not be created."); + return; + } + // Run LLC. + SrpcParams params; + nacl::DescWrapper* llc_out_file = translator->obj_file_->write_wrapper(); + PluginReverseInterface* llc_reverse = + llc_subprocess->service_runtime()->rev_interface(); + llc_reverse->AddQuotaManagedFile(translator->obj_file_->identifier(), + translator->obj_file_->write_file_io()); + if (!llc_subprocess->InvokeSrpcMethod("RunWithDefaultCommandLine", + "hh", + ¶ms, + translator->pexe_wrapper_->desc(), + llc_out_file->desc())) { + translator->TranslateFailed("compile failed."); + return; + } + // 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 (translator=%p) succeeded" + " is_shared_library=%d, soname='%s', lib_dependencies='%s')\n", + arg, is_shared_library, soname.c_str(), + lib_dependencies.c_str())); + // Shut down the llc subprocess. + llc_subprocess.reset(NULL); + if (translator->SubprocessesShouldDie()) { + translator->TranslateFailed("stopped by coordinator."); + return; + } + nacl::scoped_ptr<NaClSubprocess> ld_subprocess( + translator->StartSubprocess(PnaclUrls::GetLdUrl(), + translator->ld_manifest_)); + if (ld_subprocess == NULL) { + translator->TranslateFailed("Link process could not be created."); + return; + } + // Run LD. + nacl::DescWrapper* ld_in_file = translator->obj_file_->read_wrapper(); + nacl::DescWrapper* ld_out_file = translator->nexe_file_->write_wrapper(); + PluginReverseInterface* ld_reverse = + ld_subprocess->service_runtime()->rev_interface(); + ld_reverse->AddQuotaManagedFile(translator->nexe_file_->identifier(), + translator->nexe_file_->write_file_io()); + if (!ld_subprocess->InvokeSrpcMethod("RunWithDefaultCommandLine", + "hhiCC", + ¶ms, + ld_in_file->desc(), + ld_out_file->desc(), + is_shared_library, + soname.c_str(), + lib_dependencies.c_str())) { + translator->TranslateFailed("link failed."); + return; + } + PLUGIN_PRINTF(("PnaclCoordinator: link (translator=%p) succeeded\n", arg)); + // Shut down the ld subprocess. + ld_subprocess.reset(NULL); + if (translator->SubprocessesShouldDie()) { + translator->TranslateFailed("stopped by coordinator."); + return; + } + pp::Core* core = pp::Module::Get()->core(); + core->CallOnMainThread(0, translator->report_translate_finished_, PP_OK); +} + +void PnaclTranslateThread::TranslateFailed(const nacl::string& error_string) { + PLUGIN_PRINTF(("PnaclTranslateThread::TranslateFailed (error_string='%s')\n", + error_string.c_str())); + pp::Core* core = pp::Module::Get()->core(); + error_info_->SetReport(ERROR_UNKNOWN, + nacl::string("PnaclCoordinator: ") + error_string); + core->CallOnMainThread(0, report_translate_finished_, PP_ERROR_FAILED); +} + +bool PnaclTranslateThread::SubprocessesShouldDie() { + nacl::MutexLocker ml(&subprocess_mu_); + return subprocesses_should_die_; +} + +void PnaclTranslateThread::SetSubprocessesShouldDie( + bool subprocesses_should_die) { + nacl::MutexLocker ml(&subprocess_mu_); + subprocesses_should_die_ = subprocesses_should_die; +} + +PnaclTranslateThread::~PnaclTranslateThread() { + NaClMutexDtor(&subprocess_mu_); +} + +} // namespace plugin diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h new file mode 100644 index 0000000..0ab5a42 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h @@ -0,0 +1,83 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_TRANSLATE_THREAD_H_ +#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_TRANSLATE_THREAD_H_ + +#include "native_client/src/include/nacl_macros.h" +#include "native_client/src/include/nacl_scoped_ptr.h" +#include "native_client/src/include/nacl_string.h" +#include "native_client/src/shared/platform/nacl_threads.h" +#include "native_client/src/shared/platform/nacl_sync_checked.h" + +#include "ppapi/cpp/completion_callback.h" + +namespace nacl { +class DescWrapper; +} + + +namespace plugin { + +class ErrorInfo; +class LocalTempFile; +class Manifest; +class NaClSubprocess; +class Plugin; +class PnaclResources; + +class PnaclTranslateThread { + public: + PnaclTranslateThread(); + virtual ~PnaclTranslateThread(); + // TODO(jvoung/dschuff): handle surfaway issues when coordinator/plugin + // goes away. This data may have to be refcounted not touched in that case. + void RunTranslate(pp::CompletionCallback finish_callback, + const Manifest* manifest, + const Manifest* ld_manifest, + LocalTempFile* obj_file, + LocalTempFile* nexe_file, + nacl::DescWrapper* pexe_wrapper, + ErrorInfo* error_info, + PnaclResources* resources, + Plugin* plugin); + bool SubprocessesShouldDie(); + // Signal the translate thread and subprocesses that they should stop. + void SetSubprocessesShouldDie(bool subprocesses_should_die); + + private: + NACL_DISALLOW_COPY_AND_ASSIGN(PnaclTranslateThread); + + // Starts an individual llc or ld subprocess used for translation. + NaClSubprocess* StartSubprocess(const nacl::string& url, + const Manifest* manifest); + // 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); + // Signal that Pnacl translation failed, from the translation thread only. + void TranslateFailed(const nacl::string& error_string); + // Returns true if a the translate thread and subprocesses should stop. + + // Callback to run when tasks are completed or an error has occurred. + pp::CompletionCallback report_translate_finished_; + // True if the translation thread and related subprocesses should exit. + bool subprocesses_should_die_; + // Used to guard and publish subprocesses_should_die_. + struct NaClMutex subprocess_mu_; + + nacl::scoped_ptr<NaClThread> translate_thread_; + + // Data about the translation files, owned by the coordinator + const Manifest* manifest_; + const Manifest* ld_manifest_; + LocalTempFile* obj_file_; + LocalTempFile* nexe_file_; + nacl::DescWrapper* pexe_wrapper_; + ErrorInfo *error_info_; + PnaclResources* resources_; + Plugin* plugin_; +}; + +} +#endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_TRANSLATE_THREAD_H_ |