Index: ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
=================================================================== |
--- ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc (revision 113812) |
+++ ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc (working copy) |
@@ -17,22 +17,318 @@ |
#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 plugin { |
+ |
+class Plugin; |
+ |
namespace { |
-typedef std::vector<nacl::string> string_vector; |
-int32_t kArbitraryStackSize = 128 << 10; |
+const char kLlcUrl[] = "llc"; |
+const char kLdUrl[] = "ld"; |
+// Fake filename for the object file generated by llvm. |
+nacl::string ResourceBaseUrl() { |
+ return nacl::string("pnacl_support/") + GetSandboxISA() + "/"; |
+} |
+ |
+// Lookup service called by translator nexes. |
+// TODO(sehr): replace this lookup by ReverseService. |
+void LookupInputFile(NaClSrpcRpc* rpc, |
+ NaClSrpcArg** inputs, |
+ NaClSrpcArg** outputs, |
+ NaClSrpcClosure* done) { |
+ NaClSrpcClosureRunner runner(done); |
+ rpc->result = NACL_SRPC_RESULT_APP_ERROR; |
+ const char* file_name = inputs[0]->arrays.str; |
+ PnaclTranslationUnit* translation = reinterpret_cast<PnaclTranslationUnit*>( |
+ rpc->channel->server_instance_data); |
+ PnaclCoordinator* coordinator = translation->coordinator; |
+ PnaclResources* resources = coordinator->resources(); |
+ // This filename is part of the contract with the linker. |
+ // TODO(sehr): Pass the FD in, and move lookup for this file to the linker. |
+ const nacl::string kGeneratedObjectFileName = "___PNACL_GENERATED"; |
+ if (nacl::string(file_name) == kGeneratedObjectFileName) { |
+ outputs[0]->u.hval = translation->obj_file->read_wrapper()->desc(); |
+ } else { |
+ nacl::DescWrapper* wrapper = translation->LookupDesc(inputs[0]->arrays.str); |
+ outputs[0]->u.hval = wrapper->desc(); |
+ } |
+ rpc->result = NACL_SRPC_RESULT_OK; |
+} |
+ |
+NaClSrpcHandlerDesc lookup_methods[] = { |
+ { "LookupInputFile:s:h", LookupInputFile }, |
+ { NULL, NULL } |
+}; |
+ |
+void AbortTranslateThread(PnaclTranslationUnit* translation_unit, |
+ const nacl::string& error_string) { |
+ 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); |
+ NaClThreadExit(1); |
+} |
+ |
+void WINAPI DoTranslateThread(void* arg) { |
+ PnaclTranslationUnit* trans = reinterpret_cast<PnaclTranslationUnit*>(arg); |
+ PnaclCoordinator* coordinator = trans->coordinator; |
+ NaClSubprocess* llc_subprocess = coordinator->llc_subprocess(); |
+ Plugin* plugin = coordinator->plugin(); |
+ BrowserInterface* browser_interface = plugin->browser_interface(); |
+ |
+ // Run LLC. |
+ SrpcParams params; |
+ nacl::DescWrapper* llc_out_file = trans->obj_file->write_wrapper(); |
+ if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, |
+ llc_subprocess, |
+ "RunWithDefaultCommandLine", |
+ "hh", |
+ ¶ms, |
+ trans->pexe_wrapper->desc(), |
+ llc_out_file->desc())) { |
+ AbortTranslateThread(trans, "PnaclCoordinator compile failed."); |
+ } |
+ // LLC returns values that are used to determine how linking is cone. |
+ 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 (trans=%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()) { |
+ NaClThreadExit(1); |
+ } |
+ // Set up the lookup service for filename to handle resolution. |
+ NaClSrpcService* service = |
+ reinterpret_cast<NaClSrpcService*>(calloc(1, sizeof(*service))); |
+ if (NULL == service) { |
+ AbortTranslateThread(trans, |
+ "PnaclCoordinator: lookup service alloc failed."); |
+ } |
+ if (!NaClSrpcServiceHandlerCtor(service, lookup_methods)) { |
+ free(service); |
+ AbortTranslateThread(trans, |
+ "PnaclCoordinator: lookup service ctor failed."); |
+ } |
+ char* service_string = const_cast<char*>(service->service_string); |
+ NaClSubprocess* ld_subprocess = coordinator->ld_subprocess(); |
+ ld_subprocess->srpc_client()->AttachService(service, trans); |
+ nacl::DescWrapper* ld_out_file = trans->nexe_file->write_wrapper(); |
+ if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, |
+ ld_subprocess, |
+ "RunWithDefaultCommandLine", |
+ "ChiCC", |
+ ¶ms, |
+ service_string, |
+ ld_out_file->desc(), |
+ is_shared_library, |
+ soname.c_str(), |
+ lib_dependencies.c_str())) { |
+ AbortTranslateThread(trans, "PnaclCoordinator link failed."); |
+ } |
+ PLUGIN_PRINTF(("PnaclCoordinator Link(trans=%p) succeeded", arg)); |
+ if (coordinator->SubprocessesShouldDie()) { |
+ NaClThreadExit(1); |
+ } |
+ pp::Core* core = pp::Module::Get()->core(); |
+ core->CallOnMainThread(0, trans->translate_done_cb, PP_OK); |
+ NaClThreadExit(0); |
+} |
+ |
} // namespace |
-namespace plugin { |
+////////////////////////////////////////////////////////////////////// |
+PnaclFileDescPair::PnaclFileDescPair(pp::FileSystem* file_system, |
+ PnaclCoordinator* coordinator) |
+ : file_system_(file_system), |
+ coordinator_(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. |
+ struct NaClDesc* desc = reinterpret_cast<struct NaClDesc*>(&rng_desc_); |
+ const struct NaClDescVtbl* vtbl = |
+ reinterpret_cast<const struct NaClDescVtbl*>(desc->base.vtbl); |
+ // Filename consists of a slash then 32 random characters. |
+ filename_ = "/"; |
+ 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); |
+ filename_ += nacl::string(frag); |
+ } |
+} |
-class Plugin; |
+PnaclFileDescPair::~PnaclFileDescPair() { |
+ NaClDescUnref(reinterpret_cast<NaClDesc*>(&rng_desc_)); |
+} |
+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(coordinator_->plugin())); |
+ read_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
+ read_io_.reset(new pp::FileIO(coordinator_->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); |
+} |
+ |
+int32_t PnaclFileDescPair::GetFD(int32_t pp_error, |
+ const pp::Resource& resource, |
+ const nacl::string& component) { |
+ if (pp_error != PP_OK) { |
+ coordinator_->ReportPpapiError(pp_error, |
+ nacl::string("PnaclFileDescPair: Open ") + |
+ component + " failed\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 posix_desc = _open_osfhandle(file_desc, _O_RDWR | _O_BINARY); |
+ if (posix_desc == -1) { |
+ // Close the Windows HANDLE if it can't be converted. |
+ CloseHandle(reinterpret_cast<HANDLE>(file_desc)); |
+ 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) { |
+ coordinator_->ReportPpapiError(pp_error, |
+ nacl::string("PnaclFileDescPair: FD for ") + |
+ component + " failed\n"); |
+ return -1; |
+ } |
+ return file_desc_ok_to_close; |
+} |
+ |
+void PnaclFileDescPair::WriteFileDidOpen(int32_t pp_error) { |
+ PLUGIN_PRINTF(("PnaclFileDescPair::WriteFileDidOpen (pp_error=%" |
+ NACL_PRId32")\n", pp_error)); |
+ // Remember the object temporary file descriptor. |
+ int32_t fd = GetFD(pp_error, *write_io_, "write"); |
+ if (fd < 0) { |
+ return; |
+ } |
+ write_wrapper_.reset( |
+ coordinator_->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_, "read"); |
+ if (fd < 0) { |
+ return; |
+ } |
+ read_wrapper_.reset( |
+ coordinator_->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); |
+} |
+ |
+////////////////////////////////////////////////////////////////////// |
+void PnaclTranslationUnit::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())); |
+ Plugin* plugin = coordinator->plugin(); |
+ const nacl::string& full_url = coordinator->resource_base_url() + url; |
+ pp::CompletionCallback callback = |
+ callback_factory.NewCallback(&PnaclTranslationUnit::DidLoadFile, |
+ full_url, |
+ wrapper, |
+ done_cb); |
+ if (!plugin->StreamAsFile(full_url, callback.pp_completion_callback())) { |
+ coordinator->ReportNonPpapiError("PnaclCoordinator: Failed to load: " + |
+ url + "\n"); |
+ } |
+} |
+ |
+void PnaclTranslationUnit::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 = coordinator->GetLoadedFileDesc(pp_error, full_url, "resource"); |
+ if (fd < 0) { |
+ return; |
+ } |
+ Plugin* plugin = coordinator->plugin(); |
+ *wrapper = plugin->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); |
+ done_cb.Run(PP_OK); |
+} |
+ |
+void PnaclTranslationUnit::ResumeLookup(int32_t pp_error, |
+ PnaclTranslationUnit* trans) { |
+ UNREFERENCED_PARAMETER(pp_error); |
+ nacl::MutexLocker ml(&mu); |
+ trans->lookup_is_complete = true; |
+ NaClXCondVarBroadcast(&cv); |
+} |
+ |
+nacl::DescWrapper* PnaclTranslationUnit::LookupDesc(const nacl::string& url) { |
+ nacl::DescWrapper* wrapper; |
+ // Create the callback used to report when lookup is done. |
+ pp::CompletionCallback resume_cb = |
+ callback_factory.NewCallback(&PnaclTranslationUnit::ResumeLookup, this); |
+ // Run the lookup request on the main thread. |
+ lookup_is_complete = false; |
+ pp::CompletionCallback load_cb = |
+ callback_factory.NewCallback(&PnaclTranslationUnit::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(&mu); |
+ while (!lookup_is_complete) { |
+ // Check for termination. |
+ if (coordinator->SubprocessesShouldDie()) { |
+ NaClXMutexUnlock(&mu); |
+ NaClThreadExit(0); |
+ } |
+ NaClXCondVarTimedWaitRelative(&cv, &mu, &reltime); |
+ } |
+ NaClXMutexUnlock(&mu); |
+ return wrapper; |
+} |
+ |
+////////////////////////////////////////////////////////////////////// |
void PnaclCoordinator::Initialize(Plugin* plugin) { |
PLUGIN_PRINTF(("PnaclCoordinator::Initialize (this=%p)\n", |
static_cast<void*>(this))); |
@@ -40,62 +336,72 @@ |
CHECK(plugin_ == NULL); // Can only initialize once. |
plugin_ = plugin; |
callback_factory_.Initialize(this); |
+ // Open the temporary file system. |
+ file_system_.reset(new pp::FileSystem(plugin, |
+ PP_FILESYSTEMTYPE_LOCALTEMPORARY)); |
+ CHECK(file_system_ != NULL); |
+ // Preload llc and ld. |
+ resource_base_url_ = ResourceBaseUrl(); |
resources_.reset(new PnaclResources(plugin, this)); |
+ CHECK(resources_ != NULL); |
resources_->Initialize(); |
+ pp::CompletionCallback resources_cb = |
+ callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad); |
+ resources_->AddResourceUrl(kLlcUrl); |
+ resources_->AddResourceUrl(kLdUrl); |
+ resources_->RunWhenAllLoaded(resources_cb); |
+ resources_->StartDownloads(); |
+ // ResourcesDidLoad will be invoked when all resources have been received. |
+ // Initialization of the file system continues through that chain. |
} |
PnaclCoordinator::~PnaclCoordinator() { |
PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n", |
static_cast<void*>(this))); |
- |
- // Join helper threads which will block the page from refreshing while a |
+ // Join helper thread which will block the page from refreshing while a |
// translation is happening. |
- if (translate_thread_.get() != NULL || link_thread_.get() != NULL) { |
- SetSubprocessesShouldDie(true); |
- } |
if (translate_thread_.get() != NULL) { |
+ SetSubprocessesShouldDie(true); |
NaClThreadJoin(translate_thread_.get()); |
} |
- if (link_thread_.get() != NULL) { |
- NaClThreadJoin(link_thread_.get()); |
- } |
} |
-void PnaclCoordinator::ReportLoadAbort() { |
- plugin_->ReportLoadAbort(); |
+void PnaclCoordinator::ReportNonPpapiError(const nacl::string& message) { |
+ ErrorInfo error_info; |
+ error_info.SetReport(ERROR_UNKNOWN, message); |
+ ReportPpapiError(PP_ERROR_FAILED, error_info); |
} |
-void PnaclCoordinator::ReportLoadError(const ErrorInfo& error) { |
- plugin_->ReportLoadError(error); |
+void PnaclCoordinator::ReportPpapiError(int32_t pp_error, |
+ const nacl::string& message) { |
+ ErrorInfo error_info; |
+ error_info.SetReport(ERROR_UNKNOWN, message); |
+ ReportPpapiError(pp_error, error_info); |
} |
-void PnaclCoordinator::PnaclPpapiError(int32_t pp_error) { |
- // Attempt to free all the intermediate callbacks we ever created. |
+void PnaclCoordinator::ReportPpapiError(int32_t pp_error, |
+ const ErrorInfo& error_info) { |
+ plugin()->ReportLoadError(error_info); |
+ // Free all the intermediate callbacks we ever created. |
callback_factory_.CancelAll(); |
translate_notify_callback_.Run(pp_error); |
} |
-void PnaclCoordinator::PnaclNonPpapiError() { |
- PnaclPpapiError(PP_ERROR_FAILED); |
-} |
- |
void PnaclCoordinator::PnaclDidFinish(int32_t pp_error, |
PnaclTranslationUnit* translation_unit) { |
PLUGIN_PRINTF(("PnaclCoordinator::PnaclDidFinish (pp_error=%" |
NACL_PRId32")\n", pp_error)); |
if (pp_error != PP_OK) { |
- ReportLoadError(translation_unit->error_info); |
- PnaclPpapiError(pp_error); |
+ ReportPpapiError(pp_error, translation_unit->error_info); |
return; |
} |
// Transfer ownership of the nexe wrapper to the coordinator. |
- translated_fd_.reset(translation_unit->nexe_wrapper.release()); |
+ // TODO(sehr): need to release the translation unit here while transferring. |
+ translated_fd_.reset(translation_unit->nexe_file->read_wrapper()); |
plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); |
translate_notify_callback_.Run(pp_error); |
} |
-////////////////////////////////////////////////////////////////////// |
- |
int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error, |
const nacl::string& url, |
const nacl::string& component) { |
@@ -103,59 +409,34 @@ |
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, |
+ "PnaclCoordinator: " + 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, |
+ "PnaclCoordinator: " + component + " could not dup fd.\n"); |
return -1; |
} |
return file_desc_ok_to_close; |
} |
-bool PnaclCoordinator::StartLlcSubProcess() { |
+NaClSubprocess* PnaclCoordinator::StartSubProcess(const nacl::string& url) { |
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(); |
+ nacl::DescWrapper* wrapper = resources_->WrapperForUrl(url); |
+ NaClSubprocessId id = plugin_->LoadHelperNaClModule(wrapper, &error_info); |
+ PLUGIN_PRINTF(("PnaclCoordinator::StartSubProcess (nexe_id=%" |
+ NACL_PRId32", url=%s)\n", id, url.c_str())); |
+ if (kInvalidNaClSubprocessId == id) { |
return NULL; |
} |
- llc_subprocess_ = plugin_->nacl_subprocess(llc_id); |
- return (llc_subprocess_ != NULL); |
+ return plugin_->nacl_subprocess(id); |
} |
-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; |
- } |
- ld_subprocess_ = plugin_->nacl_subprocess(ld_id); |
- return (ld_subprocess_ != NULL); |
-} |
- |
bool PnaclCoordinator::SubprocessesShouldDie() { |
nacl::MutexLocker ml(&subprocess_mu_); |
return subprocesses_should_die_; |
@@ -166,428 +447,127 @@ |
subprocesses_should_die_ = subprocesses_should_die; |
} |
-////////////////////////////////////////////////////////////////////// |
-// First few callbacks. |
- |
-////////////////////////////////////////////////////////////////////// |
- |
-namespace { |
-void AbortTranslateThread(PnaclTranslationUnit* translation_unit, |
- const nacl::string& error_string) { |
- 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); |
- NaClThreadExit(1); |
-} |
- |
-void WINAPI DoTranslateThread(void* arg) { |
- PnaclTranslationUnit* p = reinterpret_cast<PnaclTranslationUnit*>(arg); |
- PnaclCoordinator* coordinator = p->coordinator; |
- NaClSubprocess* llc_subprocess = coordinator->llc_subprocess(); |
- Plugin* plugin = coordinator->plugin(); |
- BrowserInterface* browser = plugin->browser_interface(); |
- |
- // Set up LLC flags first. |
- // TODO(jvoung): Bake these into the llc nexe? |
- // May also want to improve scriptability, but the only thing we need |
- // probably is PIC vs non-PIC and micro-arch specification. |
- const char* llc_args_x8632[] = { "-march=x86", |
- "-mcpu=pentium4", |
- "-mtriple=i686-none-nacl-gnu", |
- "-asm-verbose=false", |
- "-filetype=obj" }; |
- const char* llc_args_x8664[] = { "-march=x86-64", |
- "-mcpu=core2", |
- "-mtriple=x86_64-none-nacl-gnu", |
- "-asm-verbose=false", |
- "-filetype=obj" }; |
- const char* llc_args_arm[] = { "-march=arm", |
- "-mcpu=cortex-a8", |
- "-mtriple=armv7a-none-nacl-gnueabi", |
- "-asm-verbose=false", |
- "-filetype=obj", |
- "-arm-reserve-r9", |
- "-sfi-disable-cp", |
- "-arm_static_tls", |
- "-sfi-store", |
- "-sfi-load", |
- "-sfi-stack", |
- "-sfi-branch", |
- "-sfi-data", |
- "-no-inline-jumptables" }; |
- |
- nacl::string sandbox_isa = GetSandboxISA(); |
- const char** llc_args; |
- size_t num_args; |
- |
- if (sandbox_isa.compare("x86-32") == 0) { |
- llc_args = llc_args_x8632; |
- num_args = NACL_ARRAY_SIZE(llc_args_x8632); |
- } else if (sandbox_isa.compare("x86-64") == 0) { |
- llc_args = llc_args_x8664; |
- num_args = NACL_ARRAY_SIZE(llc_args_x8664); |
- } else if (sandbox_isa.compare("arm") == 0) { |
- llc_args = llc_args_arm; |
- num_args = NACL_ARRAY_SIZE(llc_args_arm); |
- } else { |
- AbortTranslateThread(p, |
- "PnaclCoordinator compiler unhandled ISA " + |
- sandbox_isa + "."); |
- return; |
- } |
- |
- 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."); |
- } |
- } |
- |
- if (coordinator->SubprocessesShouldDie()) { |
- NaClThreadExit(1); |
- } |
- 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) { |
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, translation_unit->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(); |
+ llc_subprocess_ = StartSubProcess(kLlcUrl); |
+ if (llc_subprocess_ == NULL) { |
+ ReportNonPpapiError( |
+ "PnaclCoordinator: Could not start compiler subprocess\n"); |
return; |
} |
- // Invoke llvm asynchronously. |
- // RunLink runs on the main thread when llvm is done. |
+ ld_subprocess_ = StartSubProcess(kLdUrl); |
+ if (ld_subprocess_ == NULL) { |
+ ReportNonPpapiError( |
+ "PnaclCoordinator: Could not start linker subprocess\n"); |
+ return; |
+ } |
+ // Invoke llc followed by ld off the main thread. This allows use of |
+ // blocking RPCs that would otherwise block the JavaScript main thread. |
translation_unit->translate_done_cb = |
- callback_factory_.NewCallback(&PnaclCoordinator::RunLink, |
+ callback_factory_.NewCallback(&PnaclCoordinator::PnaclDidFinish, |
translation_unit); |
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("PnaclCoordinator: Could not allocate thread struct\n"); |
return; |
} |
+ const int32_t kArbitraryStackSize = 128 << 10; |
if (!NaClThreadCreateJoinable(translate_thread_.get(), |
DoTranslateThread, |
translation_unit, |
kArbitraryStackSize)) { |
- ErrorInfo error_info; |
- error_info.SetReport(ERROR_UNKNOWN, |
- "Could not create a translator thread.\n"); |
- ReportLoadError(error_info); |
- PnaclNonPpapiError(); |
+ ReportNonPpapiError("PnaclCoordinator: 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"); |
+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, "PnaclCoordinator: resources failed to load\n"); |
+ return; |
} |
- results.push_back("crtbegin.o"); |
- if (withGenerated) { |
- results.push_back(GeneratedObjectFileName()); |
+ // 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("PnaclCoordinator: failed to open file system.\n"); |
} |
- results.push_back("libcrt_platform.a"); |
- results.push_back("libgcc.a"); |
- results.push_back("libgcc_eh.a"); |
- results.push_back("crtend.o"); |
- return results; |
} |
-} // namespace |
- |
-////////////////////////////////////////////////////////////////////// |
-// Final link callbacks. |
- |
-namespace { |
- |
-void AbortLinkThread(PnaclTranslationUnit* translation_unit, |
- const nacl::string& error_string) { |
- ErrorInfo error_info; |
- pp::Core* core = pp::Module::Get()->core(); |
- translation_unit->error_info.SetReport(ERROR_UNKNOWN, error_string); |
- core->CallOnMainThread(0, translation_unit->link_done_cb, PP_ERROR_FAILED); |
- NaClThreadExit(1); |
-} |
- |
-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(); |
- 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 + "."); |
+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, "PnaclCoordinator: file system didn't open.\n"); |
+ return; |
} |
- |
- 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."); |
- } |
+ file_system_is_initialized_ = true; |
+ // If there was a pending translation unit, start translating it. |
+ PnaclTranslationUnit* translation_unit = translation_unit_.release(); |
+ if (translation_unit != NULL) { |
+ DoStartTranslation(PP_OK, translation_unit); |
} |
- |
- //// 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."); |
- } |
- } |
- } |
- |
- if (coordinator->SubprocessesShouldDie()) { |
- NaClThreadExit(1); |
- } |
- |
- // Finally, do the Link! |
- SrpcParams params; |
- 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)); |
- } |
- if (coordinator->SubprocessesShouldDie()) { |
- NaClThreadExit(1); |
- } |
- pp::Core* core = pp::Module::Get()->core(); |
- core->CallOnMainThread(0, p->link_done_cb, PP_OK); |
- NaClThreadExit(0); |
} |
-} // namespace |
- |
-void PnaclCoordinator::RunLink(int32_t pp_error, |
- PnaclTranslationUnit* translation_unit) { |
- PLUGIN_PRINTF(("PnaclCoordinator::RunLink (pp_error=%" |
+void PnaclCoordinator::DoStartTranslation(int32_t pp_error, |
+ PnaclTranslationUnit* translation) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::DoStartTranslation (pp_error=%" |
NACL_PRId32")\n", pp_error)); |
if (pp_error != PP_OK) { |
- ReportLoadError(translation_unit->error_info); |
- PnaclPpapiError(pp_error); |
+ ReportPpapiError(pp_error, translation->error_info); |
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; |
- } |
+ // Create the object file pair for connecting llc and ld. |
+ translation->obj_file.reset(new PnaclFileDescPair(file_system_.get(), this)); |
+ pp::CompletionCallback cb = |
+ callback_factory_.NewCallback(&PnaclCoordinator::ObjectPairDidOpen, |
+ translation); |
+ translation->obj_file->Open(cb); |
+} |
- // Invoke ld asynchronously. |
- // When ld has completed, PnaclDidFinish is run on the main thread. |
- translation_unit->link_done_cb = |
- callback_factory_.NewCallback(&PnaclCoordinator::PnaclDidFinish, |
- translation_unit); |
- link_thread_.reset(new NaClThread); |
- if (link_thread_ == NULL) { |
- ErrorInfo error_info; |
- error_info.SetReport(ERROR_UNKNOWN, |
- "Could not allocate DoLinkThread()\n"); |
- ReportLoadError(error_info); |
- PnaclNonPpapiError(); |
+void PnaclCoordinator::ObjectPairDidOpen(int32_t pp_error, |
+ PnaclTranslationUnit* translation) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::ObjectPairDidOpen (pp_error=%" |
+ NACL_PRId32")\n", pp_error)); |
+ if (pp_error != PP_OK) { |
+ ReportPpapiError(pp_error, translation->error_info); |
return; |
} |
- if (!NaClThreadCreateJoinable(link_thread_.get(), |
- DoLinkThread, |
- translation_unit, |
- kArbitraryStackSize)) { |
- ErrorInfo error_info; |
- error_info.SetReport(ERROR_UNKNOWN, |
- "Could not create a linker thread.\n"); |
- ReportLoadError(error_info); |
- PnaclNonPpapiError(); |
- } |
+ // Create the nexe file pair for connecting ld and sel_ldr. |
+ translation->nexe_file.reset(new PnaclFileDescPair(file_system_.get(), this)); |
+ pp::CompletionCallback cb = |
+ callback_factory_.NewCallback(&PnaclCoordinator::NexePairDidOpen, |
+ translation); |
+ translation->nexe_file->Open(cb); |
} |
-////////////////////////////////////////////////////////////////////// |
- |
-void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error, |
- const nacl::string& pexe_url, |
- PnaclTranslationUnit* translation) { |
- PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%" |
+void PnaclCoordinator::NexePairDidOpen(int32_t pp_error, |
+ PnaclTranslationUnit* translation) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::NexePairDidOpen (pp_error=%" |
NACL_PRId32")\n", pp_error)); |
if (pp_error != PP_OK) { |
- ReportLoadError(translation->error_info); |
- PnaclPpapiError(pp_error); |
+ ReportPpapiError(pp_error, translation->error_info); |
return; |
} |
+ // Load the pexe file and get the translation started. |
pp::CompletionCallback cb = |
callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate, |
- pexe_url, |
translation); |
- if (!plugin_->StreamAsFile(pexe_url, cb.pp_completion_callback())) { |
- ErrorInfo error_info; |
- error_info.SetReport(ERROR_UNKNOWN, |
- "PnaclCoordinator: Failed to download file: " + |
- pexe_url + "\n"); |
- ReportLoadError(error_info); |
- PnaclNonPpapiError(); |
+ if (!plugin_->StreamAsFile(translation->pexe_url, |
+ cb.pp_completion_callback())) { |
+ ReportNonPpapiError("PnaclCoordinator: failed to download file: " + |
+ translation->pexe_url + "\n"); |
} |
} |
@@ -596,43 +576,17 @@ |
const pp::CompletionCallback& finish_callback) { |
PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (pexe=%s)\n", |
pexe_url.c_str())); |
- // The base URL for finding all the resources will be obtained from the |
- // PNaCl manifest file. |
- // Also, the llc and ld pathnames should be read from the manifest. |
- // TODO(sehr): change to use the manifest file when ready. |
- resource_base_url_ = ResourceBaseUrl(); |
- llc_url_ = "llc"; |
- ld_url_ = "ld"; |
translate_notify_callback_ = finish_callback; |
- // Steps: |
- // (1) Schedule downloads for llc, ld nexes, and native libraries (resources). |
- // (2) When resources have been downloaded, download pexe. |
- // (3) When pexe download has completed, start translation. |
- // (4) When llc translation has finished do the link. |
- // (5) When the link is done, we are done, call the finish_callback. |
- // Hand off the SHM file descriptor returned by link. |
+ PnaclTranslationUnit* translation_unit = |
+ new PnaclTranslationUnit(this, pexe_url); |
- // 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); |
+ if (file_system_is_initialized_) { |
+ DoStartTranslation(PP_OK, translation_unit_.get()); |
+ } else { |
+ // Hold translation unit until file system initialization is complete. |
+ translation_unit_.reset(translation_unit); |
} |
- resources_->RunWhenAllLoaded(resources_cb); |
- resources_->StartDownloads(); |
} |
} // namespace plugin |