OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "native_client/src/trusted/plugin/pnacl_translate_thread.h" | 5 #include "native_client/src/trusted/plugin/pnacl_translate_thread.h" |
6 | 6 |
7 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" | 7 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" |
8 #include "native_client/src/trusted/plugin/plugin.h" | 8 #include "native_client/src/trusted/plugin/plugin.h" |
9 #include "native_client/src/trusted/plugin/pnacl_resources.h" | 9 #include "native_client/src/trusted/plugin/pnacl_resources.h" |
10 #include "native_client/src/trusted/plugin/srpc_params.h" | 10 #include "native_client/src/trusted/plugin/srpc_params.h" |
11 #include "native_client/src/trusted/plugin/temporary_file.h" | 11 #include "native_client/src/trusted/plugin/temporary_file.h" |
12 #include "native_client/src/trusted/plugin/utility.h" | 12 #include "native_client/src/trusted/plugin/utility.h" |
13 | 13 |
14 namespace plugin { | 14 namespace plugin { |
15 | 15 |
16 PnaclTranslateThread::PnaclTranslateThread() : subprocesses_should_die_(false), | 16 PnaclTranslateThread::PnaclTranslateThread() : subprocesses_should_die_(false), |
17 current_rev_interface_(NULL), | 17 current_rev_interface_(NULL), |
| 18 done_(false), |
18 manifest_(NULL), | 19 manifest_(NULL), |
19 ld_manifest_(NULL), | 20 ld_manifest_(NULL), |
20 obj_file_(NULL), | 21 obj_file_(NULL), |
21 nexe_file_(NULL), | 22 nexe_file_(NULL), |
22 coordinator_error_info_(NULL), | 23 coordinator_error_info_(NULL), |
23 resources_(NULL), | 24 resources_(NULL), |
24 plugin_(NULL) { | 25 plugin_(NULL) { |
25 NaClXMutexCtor(&subprocess_mu_); | 26 NaClXMutexCtor(&subprocess_mu_); |
| 27 NaClXMutexCtor(&cond_mu_); |
| 28 NaClXCondVarCtor(&buffer_cond_); |
| 29 } |
| 30 |
| 31 void PnaclTranslateThread::RunTranslate( |
| 32 const pp::CompletionCallback& finish_callback, |
| 33 const Manifest* manifest, |
| 34 const Manifest* ld_manifest, |
| 35 TempFile* obj_file, |
| 36 LocalTempFile* nexe_file, |
| 37 ErrorInfo* error_info, |
| 38 PnaclResources* resources, |
| 39 Plugin* plugin) { |
| 40 PLUGIN_PRINTF(("PnaclStreamingTranslateThread::RunTranslate)\n")); |
| 41 manifest_ = manifest; |
| 42 ld_manifest_ = ld_manifest; |
| 43 obj_file_ = obj_file; |
| 44 nexe_file_ = nexe_file; |
| 45 coordinator_error_info_ = error_info; |
| 46 resources_ = resources; |
| 47 plugin_ = plugin; |
| 48 |
| 49 // Invoke llc followed by ld off the main thread. This allows use of |
| 50 // blocking RPCs that would otherwise block the JavaScript main thread. |
| 51 report_translate_finished_ = finish_callback; |
| 52 translate_thread_.reset(new NaClThread); |
| 53 if (translate_thread_ == NULL) { |
| 54 TranslateFailed("could not allocate thread struct."); |
| 55 return; |
| 56 } |
| 57 const int32_t kArbitraryStackSize = 128 * 1024; |
| 58 if (!NaClThreadCreateJoinable(translate_thread_.get(), |
| 59 DoTranslateThread, |
| 60 this, |
| 61 kArbitraryStackSize)) { |
| 62 TranslateFailed("could not create thread."); |
| 63 translate_thread_.reset(NULL); |
| 64 } |
| 65 } |
| 66 |
| 67 // Called from main thread to send bytes to the translator. |
| 68 void PnaclTranslateThread::PutBytes(std::vector<char>* bytes, |
| 69 int count) { |
| 70 PLUGIN_PRINTF(("PutBytes, this %p bytes %p, size %d, count %d\n", this, bytes, |
| 71 bytes ? bytes->size(): 0, count)); |
| 72 size_t buffer_size = 0; |
| 73 // If we are done (error or not), Signal the translation thread to stop. |
| 74 if (count <= PP_OK) { |
| 75 NaClXMutexLock(&cond_mu_); |
| 76 done_ = true; |
| 77 NaClXCondVarSignal(&buffer_cond_); |
| 78 NaClXMutexUnlock(&cond_mu_); |
| 79 return; |
| 80 } |
| 81 |
| 82 CHECK(bytes != NULL); |
| 83 // Ensure that the buffer we send to the translation thread is the right size |
| 84 // (count can be < the buffer size). This can be done without the lock. |
| 85 buffer_size = bytes->size(); |
| 86 bytes->resize(count); |
| 87 |
| 88 NaClXMutexLock(&cond_mu_); |
| 89 |
| 90 data_buffers_.push_back(std::vector<char>()); |
| 91 bytes->swap(data_buffers_.back()); // Avoid copying the buffer data. |
| 92 |
| 93 NaClXCondVarSignal(&buffer_cond_); |
| 94 NaClXMutexUnlock(&cond_mu_); |
| 95 |
| 96 // Ensure the buffer we send back to the coordinator is the expected size |
| 97 bytes->resize(buffer_size); |
26 } | 98 } |
27 | 99 |
28 NaClSubprocess* PnaclTranslateThread::StartSubprocess( | 100 NaClSubprocess* PnaclTranslateThread::StartSubprocess( |
29 const nacl::string& url_for_nexe, | 101 const nacl::string& url_for_nexe, |
30 const Manifest* manifest, | 102 const Manifest* manifest, |
31 ErrorInfo* error_info) { | 103 ErrorInfo* error_info) { |
32 PLUGIN_PRINTF(("PnaclTranslateThread::StartSubprocess (url_for_nexe=%s)\n", | 104 PLUGIN_PRINTF(("PnaclTranslateThread::StartSubprocess (url_for_nexe=%s)\n", |
33 url_for_nexe.c_str())); | 105 url_for_nexe.c_str())); |
34 nacl::DescWrapper* wrapper = resources_->WrapperForUrl(url_for_nexe); | 106 nacl::DescWrapper* wrapper = resources_->WrapperForUrl(url_for_nexe); |
35 nacl::scoped_ptr<NaClSubprocess> subprocess( | 107 nacl::scoped_ptr<NaClSubprocess> subprocess( |
36 plugin_->LoadHelperNaClModule(wrapper, manifest, error_info)); | 108 plugin_->LoadHelperNaClModule(wrapper, manifest, error_info)); |
37 if (subprocess.get() == NULL) { | 109 if (subprocess.get() == NULL) { |
38 PLUGIN_PRINTF(( | 110 PLUGIN_PRINTF(( |
39 "PnaclTranslateThread::StartSubprocess: subprocess creation failed\n")); | 111 "PnaclTranslateThread::StartSubprocess: subprocess creation failed\n")); |
40 return NULL; | 112 return NULL; |
41 } | 113 } |
42 return subprocess.release(); | 114 return subprocess.release(); |
43 } | 115 } |
44 | 116 |
45 void WINAPI PnaclTranslateThread::DoTranslateThread(void* arg) { | 117 void WINAPI PnaclTranslateThread::DoTranslateThread(void* arg) { |
46 PnaclTranslateThread* translator = | 118 PnaclTranslateThread* translator = |
47 reinterpret_cast<PnaclTranslateThread*>(arg); | 119 reinterpret_cast<PnaclTranslateThread*>(arg); |
48 translator->DoTranslate(); | 120 translator->DoTranslate(); |
49 } | 121 } |
50 | 122 |
| 123 void PnaclTranslateThread::DoTranslate() { |
| 124 ErrorInfo error_info; |
| 125 nacl::scoped_ptr<NaClSubprocess> llc_subprocess( |
| 126 StartSubprocess(PnaclUrls::GetLlcUrl(), manifest_, &error_info)); |
| 127 if (llc_subprocess == NULL) { |
| 128 TranslateFailed("Compile process could not be created: " + |
| 129 error_info.message()); |
| 130 return; |
| 131 } |
| 132 // Run LLC. |
| 133 SrpcParams params; |
| 134 nacl::DescWrapper* llc_out_file = obj_file_->get_wrapper(); |
| 135 PluginReverseInterface* llc_reverse = |
| 136 llc_subprocess->service_runtime()->rev_interface(); |
| 137 llc_reverse->AddTempQuotaManagedFile(obj_file_->identifier()); |
| 138 RegisterReverseInterface(llc_reverse); |
| 139 |
| 140 if (!llc_subprocess->InvokeSrpcMethod("StreamInit", |
| 141 "h", |
| 142 ¶ms, |
| 143 llc_out_file->desc())) { |
| 144 // StreamInit returns an error message if the RPC fails. |
| 145 TranslateFailed(nacl::string("Stream init failed: ") + |
| 146 nacl::string(params.outs()[0]->arrays.str)); |
| 147 return; |
| 148 } |
| 149 |
| 150 PLUGIN_PRINTF(("PnaclCoordinator: StreamInit successful\n")); |
| 151 |
| 152 // llc process is started. |
| 153 while(!done_ || data_buffers_.size() > 0) { |
| 154 NaClXMutexLock(&cond_mu_); |
| 155 while(!done_ && data_buffers_.size() == 0) { |
| 156 NaClXCondVarWait(&buffer_cond_, &cond_mu_); |
| 157 } |
| 158 PLUGIN_PRINTF(("PnaclTranslateThread awake, done %d, size %d\n", |
| 159 done_, data_buffers_.size())); |
| 160 if (data_buffers_.size() > 0) { |
| 161 std::vector<char> data; |
| 162 data.swap(data_buffers_.front()); |
| 163 data_buffers_.pop_front(); |
| 164 NaClXMutexUnlock(&cond_mu_); |
| 165 PLUGIN_PRINTF(("StreamChunk\n")); |
| 166 if (!llc_subprocess->InvokeSrpcMethod("StreamChunk", |
| 167 "C", |
| 168 ¶ms, |
| 169 &data[0], |
| 170 data.size())) { |
| 171 TranslateFailed("Compile stream chunk failed."); |
| 172 return; |
| 173 } |
| 174 PLUGIN_PRINTF(("StreamChunk Successful\n")); |
| 175 } else { |
| 176 NaClXMutexUnlock(&cond_mu_); |
| 177 } |
| 178 if (SubprocessesShouldDie()) { |
| 179 TranslateFailed("Stopped by coordinator."); |
| 180 return; |
| 181 } |
| 182 } |
| 183 PLUGIN_PRINTF(("PnaclTranslateThread done with chunks\n")); |
| 184 // Finish llc. |
| 185 if(!llc_subprocess->InvokeSrpcMethod("StreamEnd", |
| 186 "", |
| 187 ¶ms)) { |
| 188 PLUGIN_PRINTF(("PnaclTranslateThread StreamEnd failed\n")); |
| 189 TranslateFailed(params.outs()[3]->arrays.str); |
| 190 return; |
| 191 } |
| 192 // LLC returns values that are used to determine how linking is done. |
| 193 int is_shared_library = (params.outs()[0]->u.ival != 0); |
| 194 nacl::string soname = params.outs()[1]->arrays.str; |
| 195 nacl::string lib_dependencies = params.outs()[2]->arrays.str; |
| 196 PLUGIN_PRINTF(("PnaclCoordinator: compile (translator=%p) succeeded" |
| 197 " is_shared_library=%d, soname='%s', lib_dependencies='%s')\n", |
| 198 this, is_shared_library, soname.c_str(), |
| 199 lib_dependencies.c_str())); |
| 200 |
| 201 // Shut down the llc subprocess. |
| 202 RegisterReverseInterface(NULL); |
| 203 llc_subprocess.reset(NULL); |
| 204 if (SubprocessesShouldDie()) { |
| 205 TranslateFailed("stopped by coordinator."); |
| 206 return; |
| 207 } |
| 208 |
| 209 if(!RunLdSubprocess(is_shared_library, soname, lib_dependencies)) { |
| 210 return; |
| 211 } |
| 212 pp::Core* core = pp::Module::Get()->core(); |
| 213 core->CallOnMainThread(0, report_translate_finished_, PP_OK); |
| 214 } |
| 215 |
51 bool PnaclTranslateThread::RunLdSubprocess(int is_shared_library, | 216 bool PnaclTranslateThread::RunLdSubprocess(int is_shared_library, |
52 const nacl::string& soname, | 217 const nacl::string& soname, |
53 const nacl::string& lib_dependencies | 218 const nacl::string& lib_dependencies |
54 ) { | 219 ) { |
55 ErrorInfo error_info; | 220 ErrorInfo error_info; |
56 nacl::scoped_ptr<NaClSubprocess> ld_subprocess( | 221 nacl::scoped_ptr<NaClSubprocess> ld_subprocess( |
57 StartSubprocess(PnaclUrls::GetLdUrl(), ld_manifest_, &error_info)); | 222 StartSubprocess(PnaclUrls::GetLdUrl(), ld_manifest_, &error_info)); |
58 if (ld_subprocess == NULL) { | 223 if (ld_subprocess == NULL) { |
59 TranslateFailed("Link process could not be created: " + | 224 TranslateFailed("Link process could not be created: " + |
60 error_info.message()); | 225 error_info.message()); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 } | 290 } |
126 | 291 |
127 | 292 |
128 bool PnaclTranslateThread::SubprocessesShouldDie() { | 293 bool PnaclTranslateThread::SubprocessesShouldDie() { |
129 nacl::MutexLocker ml(&subprocess_mu_); | 294 nacl::MutexLocker ml(&subprocess_mu_); |
130 return subprocesses_should_die_; | 295 return subprocesses_should_die_; |
131 } | 296 } |
132 | 297 |
133 void PnaclTranslateThread::SetSubprocessesShouldDie() { | 298 void PnaclTranslateThread::SetSubprocessesShouldDie() { |
134 PLUGIN_PRINTF(("PnaclTranslateThread::SetSubprocessesShouldDie\n")); | 299 PLUGIN_PRINTF(("PnaclTranslateThread::SetSubprocessesShouldDie\n")); |
135 nacl::MutexLocker ml(&subprocess_mu_); | 300 NaClXMutexLock(&subprocess_mu_); |
136 subprocesses_should_die_ = true; | 301 subprocesses_should_die_ = true; |
137 if (current_rev_interface_) { | 302 if (current_rev_interface_) { |
138 current_rev_interface_->ShutDown(); | 303 current_rev_interface_->ShutDown(); |
139 current_rev_interface_ = NULL; | 304 current_rev_interface_ = NULL; |
140 } | 305 } |
| 306 NaClXMutexUnlock(&subprocess_mu_); |
| 307 nacl::MutexLocker ml(&cond_mu_); |
| 308 done_ = true; |
| 309 NaClXCondVarSignal(&buffer_cond_); |
141 } | 310 } |
142 | 311 |
143 PnaclTranslateThread::~PnaclTranslateThread() { | 312 PnaclTranslateThread::~PnaclTranslateThread() { |
| 313 PLUGIN_PRINTF(("~PnaclTranslateThread (translate_thread=%p)\n", this)); |
| 314 SetSubprocessesShouldDie(); |
| 315 NaClThreadJoin(translate_thread_.get()); |
| 316 PLUGIN_PRINTF(("~PnaclTranslateThread joined\n")); |
144 NaClMutexDtor(&subprocess_mu_); | 317 NaClMutexDtor(&subprocess_mu_); |
145 } | 318 } |
146 | 319 |
147 } // namespace plugin | 320 } // namespace plugin |
OLD | NEW |