| Index: ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc
|
| diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc
|
| index 06d31e802c12acadd49edbd772e8904404f296a6..7eb699c4ab67aab93e3ecb1c899aa03cd65a797a 100644
|
| --- a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc
|
| +++ b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc
|
| @@ -15,6 +15,7 @@ namespace plugin {
|
|
|
| PnaclTranslateThread::PnaclTranslateThread() : subprocesses_should_die_(false),
|
| current_rev_interface_(NULL),
|
| + done_(false),
|
| manifest_(NULL),
|
| ld_manifest_(NULL),
|
| obj_file_(NULL),
|
| @@ -23,6 +24,77 @@ PnaclTranslateThread::PnaclTranslateThread() : subprocesses_should_die_(false),
|
| resources_(NULL),
|
| plugin_(NULL) {
|
| NaClXMutexCtor(&subprocess_mu_);
|
| + NaClXMutexCtor(&cond_mu_);
|
| + NaClXCondVarCtor(&buffer_cond_);
|
| +}
|
| +
|
| +void PnaclTranslateThread::RunTranslate(
|
| + const pp::CompletionCallback& finish_callback,
|
| + const Manifest* manifest,
|
| + const Manifest* ld_manifest,
|
| + TempFile* obj_file,
|
| + LocalTempFile* nexe_file,
|
| + ErrorInfo* error_info,
|
| + PnaclResources* resources,
|
| + Plugin* plugin) {
|
| + PLUGIN_PRINTF(("PnaclStreamingTranslateThread::RunTranslate)\n"));
|
| + manifest_ = manifest;
|
| + ld_manifest_ = ld_manifest;
|
| + obj_file_ = obj_file;
|
| + nexe_file_ = nexe_file;
|
| + coordinator_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.");
|
| + translate_thread_.reset(NULL);
|
| + }
|
| +}
|
| +
|
| +// Called from main thread to send bytes to the translator.
|
| +void PnaclTranslateThread::PutBytes(std::vector<char>* bytes,
|
| + int count) {
|
| + PLUGIN_PRINTF(("PutBytes, this %p bytes %p, size %d, count %d\n", this, bytes,
|
| + bytes ? bytes->size(): 0, count));
|
| + size_t buffer_size = 0;
|
| + // If we are done (error or not), Signal the translation thread to stop.
|
| + if (count <= PP_OK) {
|
| + NaClXMutexLock(&cond_mu_);
|
| + done_ = true;
|
| + NaClXCondVarSignal(&buffer_cond_);
|
| + NaClXMutexUnlock(&cond_mu_);
|
| + return;
|
| + }
|
| +
|
| + CHECK(bytes != NULL);
|
| + // Ensure that the buffer we send to the translation thread is the right size
|
| + // (count can be < the buffer size). This can be done without the lock.
|
| + buffer_size = bytes->size();
|
| + bytes->resize(count);
|
| +
|
| + NaClXMutexLock(&cond_mu_);
|
| +
|
| + data_buffers_.push_back(std::vector<char>());
|
| + bytes->swap(data_buffers_.back()); // Avoid copying the buffer data.
|
| +
|
| + NaClXCondVarSignal(&buffer_cond_);
|
| + NaClXMutexUnlock(&cond_mu_);
|
| +
|
| + // Ensure the buffer we send back to the coordinator is the expected size
|
| + bytes->resize(buffer_size);
|
| }
|
|
|
| NaClSubprocess* PnaclTranslateThread::StartSubprocess(
|
| @@ -48,6 +120,99 @@ void WINAPI PnaclTranslateThread::DoTranslateThread(void* arg) {
|
| translator->DoTranslate();
|
| }
|
|
|
| +void PnaclTranslateThread::DoTranslate() {
|
| + ErrorInfo error_info;
|
| + nacl::scoped_ptr<NaClSubprocess> llc_subprocess(
|
| + StartSubprocess(PnaclUrls::GetLlcUrl(), manifest_, &error_info));
|
| + if (llc_subprocess == NULL) {
|
| + TranslateFailed("Compile process could not be created: " +
|
| + error_info.message());
|
| + return;
|
| + }
|
| + // Run LLC.
|
| + SrpcParams params;
|
| + nacl::DescWrapper* llc_out_file = obj_file_->get_wrapper();
|
| + PluginReverseInterface* llc_reverse =
|
| + llc_subprocess->service_runtime()->rev_interface();
|
| + llc_reverse->AddTempQuotaManagedFile(obj_file_->identifier());
|
| + RegisterReverseInterface(llc_reverse);
|
| +
|
| + if (!llc_subprocess->InvokeSrpcMethod("StreamInit",
|
| + "h",
|
| + ¶ms,
|
| + llc_out_file->desc())) {
|
| + // StreamInit returns an error message if the RPC fails.
|
| + TranslateFailed(nacl::string("Stream init failed: ") +
|
| + nacl::string(params.outs()[0]->arrays.str));
|
| + return;
|
| + }
|
| +
|
| + PLUGIN_PRINTF(("PnaclCoordinator: StreamInit successful\n"));
|
| +
|
| + // llc process is started.
|
| + while(!done_ || data_buffers_.size() > 0) {
|
| + NaClXMutexLock(&cond_mu_);
|
| + while(!done_ && data_buffers_.size() == 0) {
|
| + NaClXCondVarWait(&buffer_cond_, &cond_mu_);
|
| + }
|
| + PLUGIN_PRINTF(("PnaclTranslateThread awake, done %d, size %d\n",
|
| + done_, data_buffers_.size()));
|
| + if (data_buffers_.size() > 0) {
|
| + std::vector<char> data;
|
| + data.swap(data_buffers_.front());
|
| + data_buffers_.pop_front();
|
| + NaClXMutexUnlock(&cond_mu_);
|
| + PLUGIN_PRINTF(("StreamChunk\n"));
|
| + if (!llc_subprocess->InvokeSrpcMethod("StreamChunk",
|
| + "C",
|
| + ¶ms,
|
| + &data[0],
|
| + data.size())) {
|
| + TranslateFailed("Compile stream chunk failed.");
|
| + return;
|
| + }
|
| + PLUGIN_PRINTF(("StreamChunk Successful\n"));
|
| + } else {
|
| + NaClXMutexUnlock(&cond_mu_);
|
| + }
|
| + if (SubprocessesShouldDie()) {
|
| + TranslateFailed("Stopped by coordinator.");
|
| + return;
|
| + }
|
| + }
|
| + PLUGIN_PRINTF(("PnaclTranslateThread done with chunks\n"));
|
| + // Finish llc.
|
| + if(!llc_subprocess->InvokeSrpcMethod("StreamEnd",
|
| + "",
|
| + ¶ms)) {
|
| + PLUGIN_PRINTF(("PnaclTranslateThread StreamEnd failed\n"));
|
| + TranslateFailed(params.outs()[3]->arrays.str);
|
| + 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",
|
| + this, is_shared_library, soname.c_str(),
|
| + lib_dependencies.c_str()));
|
| +
|
| + // Shut down the llc subprocess.
|
| + RegisterReverseInterface(NULL);
|
| + llc_subprocess.reset(NULL);
|
| + if (SubprocessesShouldDie()) {
|
| + TranslateFailed("stopped by coordinator.");
|
| + return;
|
| + }
|
| +
|
| + if(!RunLdSubprocess(is_shared_library, soname, lib_dependencies)) {
|
| + return;
|
| + }
|
| + pp::Core* core = pp::Module::Get()->core();
|
| + core->CallOnMainThread(0, report_translate_finished_, PP_OK);
|
| +}
|
| +
|
| bool PnaclTranslateThread::RunLdSubprocess(int is_shared_library,
|
| const nacl::string& soname,
|
| const nacl::string& lib_dependencies
|
| @@ -132,15 +297,23 @@ bool PnaclTranslateThread::SubprocessesShouldDie() {
|
|
|
| void PnaclTranslateThread::SetSubprocessesShouldDie() {
|
| PLUGIN_PRINTF(("PnaclTranslateThread::SetSubprocessesShouldDie\n"));
|
| - nacl::MutexLocker ml(&subprocess_mu_);
|
| + NaClXMutexLock(&subprocess_mu_);
|
| subprocesses_should_die_ = true;
|
| if (current_rev_interface_) {
|
| current_rev_interface_->ShutDown();
|
| current_rev_interface_ = NULL;
|
| }
|
| + NaClXMutexUnlock(&subprocess_mu_);
|
| + nacl::MutexLocker ml(&cond_mu_);
|
| + done_ = true;
|
| + NaClXCondVarSignal(&buffer_cond_);
|
| }
|
|
|
| PnaclTranslateThread::~PnaclTranslateThread() {
|
| + PLUGIN_PRINTF(("~PnaclTranslateThread (translate_thread=%p)\n", this));
|
| + SetSubprocessesShouldDie();
|
| + NaClThreadJoin(translate_thread_.get());
|
| + PLUGIN_PRINTF(("~PnaclTranslateThread joined\n"));
|
| NaClMutexDtor(&subprocess_mu_);
|
| }
|
|
|
|
|