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