OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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_coordinator.h" | 5 #include "native_client/src/trusted/plugin/pnacl_coordinator.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "native_client/src/include/portability_io.h" | 10 #include "native_client/src/include/portability_io.h" |
11 #include "native_client/src/shared/platform/nacl_check.h" | 11 #include "native_client/src/shared/platform/nacl_check.h" |
12 #include "native_client/src/shared/platform/nacl_sync_raii.h" | 12 #include "native_client/src/shared/platform/nacl_sync_raii.h" |
13 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" | 13 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" |
14 #include "native_client/src/trusted/plugin/browser_interface.h" | 14 #include "native_client/src/trusted/plugin/browser_interface.h" |
15 #include "native_client/src/trusted/plugin/nacl_subprocess.h" | 15 #include "native_client/src/trusted/plugin/nacl_subprocess.h" |
16 #include "native_client/src/trusted/plugin/nexe_arch.h" | 16 #include "native_client/src/trusted/plugin/nexe_arch.h" |
17 #include "native_client/src/trusted/plugin/plugin.h" | 17 #include "native_client/src/trusted/plugin/plugin.h" |
18 #include "native_client/src/trusted/plugin/plugin_error.h" | 18 #include "native_client/src/trusted/plugin/plugin_error.h" |
19 #include "native_client/src/trusted/plugin/pnacl_srpc_lib.h" | 19 #include "native_client/src/trusted/plugin/pnacl_srpc_lib.h" |
20 #include "native_client/src/trusted/plugin/scriptable_handle.h" | |
21 #include "native_client/src/trusted/plugin/utility.h" | 20 #include "native_client/src/trusted/plugin/utility.h" |
22 | 21 |
23 #include "ppapi/c/pp_errors.h" | 22 #include "ppapi/c/pp_errors.h" |
23 #include "ppapi/c/ppb_file_io.h" | |
24 #include "ppapi/cpp/file_io.h" | |
25 | |
26 namespace plugin { | |
27 | |
28 class Plugin; | |
24 | 29 |
25 namespace { | 30 namespace { |
26 | 31 |
27 typedef std::vector<nacl::string> string_vector; | 32 const char kLlcUrl[] = "llc"; |
28 int32_t kArbitraryStackSize = 128 << 10; | 33 const char kLdUrl[] = "ld"; |
34 | |
35 // Fake filename for the object file generated by llc and consumed by ld. | |
36 nacl::string ResourceBaseUrl() { | |
37 return nacl::string("pnacl_support/") + GetSandboxISA() + "/"; | |
38 } | |
39 | |
40 nacl::string Random32CharHexString(struct NaClDescRng* rng) { | |
41 struct NaClDesc* desc = reinterpret_cast<struct NaClDesc*>(rng); | |
42 const struct NaClDescVtbl* vtbl = | |
43 reinterpret_cast<const struct NaClDescVtbl*>(desc->base.vtbl); | |
44 | |
45 nacl::string hex_string; | |
46 const int32_t kTempFileNameWords = 4; | |
47 for (int32_t i = 0; i < kTempFileNameWords; ++i) { | |
48 int32_t num; | |
49 CHECK(sizeof num == vtbl->Read(desc, | |
50 reinterpret_cast<char*>(&num), | |
51 sizeof num)); | |
52 char frag[16]; | |
53 SNPRINTF(frag, sizeof frag, "%08x", num); | |
54 hex_string += nacl::string(frag); | |
55 } | |
56 return hex_string; | |
57 } | |
58 | |
59 // Some constants for PnaclFileDescPair::GetFD readability. | |
60 const bool kReadOnly = false; | |
61 const bool kWriteable = true; | |
29 | 62 |
30 } // namespace | 63 } // namespace |
31 | 64 |
32 namespace plugin { | 65 ////////////////////////////////////////////////////////////////////// |
33 | 66 PnaclFileDescPair::PnaclFileDescPair(Plugin* plugin, |
34 class Plugin; | 67 pp::FileSystem* file_system, |
35 | 68 PnaclCoordinator* coordinator) |
36 void PnaclCoordinator::Initialize(Plugin* plugin) { | 69 : plugin_(plugin), |
37 PLUGIN_PRINTF(("PnaclCoordinator::Initialize (this=%p)\n", | 70 file_system_(file_system), |
38 static_cast<void*>(this))); | 71 coordinator_(coordinator) { |
39 CHECK(plugin != NULL); | 72 PLUGIN_PRINTF(("PnaclFileDescPair::PnaclFileDescPair (plugin=%p, " |
40 CHECK(plugin_ == NULL); // Can only initialize once. | 73 "file_system=%p, coordinator=%p)\n", |
41 plugin_ = plugin; | 74 static_cast<void*>(plugin), static_cast<void*>(file_system), |
75 static_cast<void*>(coordinator))); | |
42 callback_factory_.Initialize(this); | 76 callback_factory_.Initialize(this); |
43 resources_.reset(new PnaclResources(plugin, this)); | 77 CHECK(NaClDescRngCtor(&rng_desc_)); |
44 resources_->Initialize(); | 78 file_io_trusted_ = static_cast<const PPB_FileIOTrusted*>( |
45 } | 79 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); |
46 | 80 // Get a random temp file name. |
47 PnaclCoordinator::~PnaclCoordinator() { | 81 filename_ = "/" + Random32CharHexString(&rng_desc_); |
48 PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n", | 82 } |
49 static_cast<void*>(this))); | 83 |
50 | 84 PnaclFileDescPair::~PnaclFileDescPair() { |
51 // Join helper threads which will block the page from refreshing while a | 85 PLUGIN_PRINTF(("PnaclFileDescPair::~PnaclFileDescPair\n")); |
52 // translation is happening. | 86 NaClDescUnref(reinterpret_cast<NaClDesc*>(&rng_desc_)); |
53 if (translate_thread_.get() != NULL || link_thread_.get() != NULL) { | 87 } |
54 SetSubprocessesShouldDie(true); | 88 |
55 } | 89 void PnaclFileDescPair::Open(const pp::CompletionCallback& cb) { |
56 if (translate_thread_.get() != NULL) { | 90 PLUGIN_PRINTF(("PnaclFileDescPair::Open\n")); |
57 NaClThreadJoin(translate_thread_.get()); | 91 done_callback_ = cb; |
58 } | 92 |
59 if (link_thread_.get() != NULL) { | 93 write_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
60 NaClThreadJoin(link_thread_.get()); | 94 write_io_.reset(new pp::FileIO(plugin_)); |
61 } | 95 read_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str())); |
62 } | 96 read_io_.reset(new pp::FileIO(plugin_)); |
63 | 97 |
64 void PnaclCoordinator::ReportLoadAbort() { | 98 pp::CompletionCallback open_write_cb = |
65 plugin_->ReportLoadAbort(); | 99 callback_factory_.NewCallback(&PnaclFileDescPair::WriteFileDidOpen); |
66 } | 100 // Open the writeable file. |
67 | 101 write_io_->Open(*write_ref_, |
68 void PnaclCoordinator::ReportLoadError(const ErrorInfo& error) { | 102 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE, |
69 plugin_->ReportLoadError(error); | 103 open_write_cb); |
70 } | 104 } |
71 | 105 |
72 void PnaclCoordinator::PnaclPpapiError(int32_t pp_error) { | 106 int32_t PnaclFileDescPair::GetFD(int32_t pp_error, |
73 // Attempt to free all the intermediate callbacks we ever created. | 107 const pp::Resource& resource, |
74 callback_factory_.CancelAll(); | 108 bool is_writable) { |
75 translate_notify_callback_.Run(pp_error); | 109 PLUGIN_PRINTF(("PnaclFileDescPair::GetFD (pp_error=%"NACL_PRId32 |
76 } | 110 ", is_writable=%d)\n", pp_error, is_writable)); |
77 | |
78 void PnaclCoordinator::PnaclNonPpapiError() { | |
79 PnaclPpapiError(PP_ERROR_FAILED); | |
80 } | |
81 | |
82 void PnaclCoordinator::PnaclDidFinish(int32_t pp_error, | |
83 PnaclTranslationUnit* translation_unit) { | |
84 PLUGIN_PRINTF(("PnaclCoordinator::PnaclDidFinish (pp_error=%" | |
85 NACL_PRId32")\n", pp_error)); | |
86 if (pp_error != PP_OK) { | 111 if (pp_error != PP_OK) { |
87 ReportLoadError(translation_unit->error_info); | 112 PLUGIN_PRINTF(("PnaclFileDescPair::GetFD pp_error != PP_OK\n")); |
88 PnaclPpapiError(pp_error); | 113 return -1; |
89 return; | 114 } |
90 } | 115 int32_t file_desc = |
91 // Transfer ownership of the nexe wrapper to the coordinator. | 116 file_io_trusted_->GetOSFileDescriptor(resource.pp_resource()); |
92 translated_fd_.reset(translation_unit->nexe_wrapper.release()); | 117 #if NACL_WINDOWS |
93 plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); | 118 // Convert the Windows HANDLE from Pepper to a POSIX file descriptor. |
94 translate_notify_callback_.Run(pp_error); | 119 int32_t open_flags = ((is_writable ? _O_RDWR : _O_RDONLY) | _O_BINARY); |
120 int32_t posix_desc = _open_osfhandle(file_desc, open_flags); | |
121 if (posix_desc == -1) { | |
122 // Close the Windows HANDLE if it can't be converted. | |
123 CloseHandle(reinterpret_cast<HANDLE>(file_desc)); | |
124 PLUGIN_PRINTF(("PnaclFileDescPair::GetFD _open_osfhandle failed.\n")); | |
125 return NACL_NO_FILE_DESC; | |
126 } | |
127 file_desc = posix_desc; | |
128 #endif | |
129 int32_t file_desc_ok_to_close = DUP(file_desc); | |
130 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { | |
131 PLUGIN_PRINTF(("PnaclFileDescPair::GetFD dup failed.\n")); | |
132 return -1; | |
133 } | |
134 return file_desc_ok_to_close; | |
135 } | |
136 | |
137 void PnaclFileDescPair::WriteFileDidOpen(int32_t pp_error) { | |
138 PLUGIN_PRINTF(("PnaclFileDescPair::WriteFileDidOpen (pp_error=%" | |
139 NACL_PRId32")\n", pp_error)); | |
140 // Remember the object temporary file descriptor. | |
141 int32_t fd = GetFD(pp_error, *write_io_, kWriteable); | |
142 if (fd < 0) { | |
143 coordinator_->ReportNonPpapiError("could not open write temp file\n"); | |
144 return; | |
145 } | |
146 write_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDWR)); | |
147 pp::CompletionCallback open_read_cb = | |
148 callback_factory_.NewCallback(&PnaclFileDescPair::ReadFileDidOpen); | |
149 // Open the read only file. | |
150 read_io_->Open(*read_ref_, PP_FILEOPENFLAG_READ, open_read_cb); | |
151 } | |
152 | |
153 void PnaclFileDescPair::ReadFileDidOpen(int32_t pp_error) { | |
154 PLUGIN_PRINTF(("PnaclFileDescPair::ReadFileDidOpen (pp_error=%" | |
155 NACL_PRId32")\n", pp_error)); | |
156 // Remember the object temporary file descriptor. | |
157 int32_t fd = GetFD(pp_error, *read_io_, kReadOnly); | |
158 if (fd < 0) { | |
159 coordinator_->ReportNonPpapiError("could not open read temp file\n"); | |
160 return; | |
161 } | |
162 read_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); | |
163 // Run the client's completion callback. | |
164 pp::Core* core = pp::Module::Get()->core(); | |
165 core->CallOnMainThread(0, done_callback_, PP_OK); | |
95 } | 166 } |
96 | 167 |
97 ////////////////////////////////////////////////////////////////////// | 168 ////////////////////////////////////////////////////////////////////// |
169 PnaclCoordinator* PnaclCoordinator::BitcodeToNative( | |
170 Plugin* plugin, | |
171 const nacl::string& pexe_url, | |
172 const pp::CompletionCallback& translate_notify_callback) { | |
173 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (plugin=%p, pexe=%s)\n", | |
174 static_cast<void*>(plugin), pexe_url.c_str())); | |
175 PnaclCoordinator* coordinator = | |
176 new PnaclCoordinator(plugin, | |
177 pexe_url, | |
178 translate_notify_callback, | |
179 ResourceBaseUrl()); | |
180 // Load llc and ld. | |
181 std::vector<nacl::string> resource_urls; | |
182 resource_urls.push_back(kLlcUrl); | |
183 resource_urls.push_back(kLdUrl); | |
184 pp::CompletionCallback resources_cb = | |
185 coordinator->callback_factory_.NewCallback( | |
186 &PnaclCoordinator::ResourcesDidLoad); | |
187 coordinator->resources_.reset( | |
188 new PnaclResources(plugin, | |
189 coordinator, | |
190 coordinator->resource_base_url_, | |
191 resource_urls, | |
192 resources_cb)); | |
193 CHECK(coordinator->resources_ != NULL); | |
194 coordinator->resources_->StartDownloads(); | |
195 // ResourcesDidLoad will be invoked when all resources have been received. | |
196 return coordinator; | |
197 } | |
98 | 198 |
99 int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error, | 199 int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error, |
100 const nacl::string& url, | 200 const nacl::string& url, |
101 const nacl::string& component) { | 201 const nacl::string& component) { |
202 PLUGIN_PRINTF(("PnaclCoordinator::GetLoadedFileDesc (pp_error=%" | |
203 NACL_PRId32", url=%s, component=%s)\n", pp_error, | |
204 url.c_str(), component.c_str())); | |
205 PLUGIN_PRINTF(("PnaclCoordinator::GetLoadedFileDesc (pp_error=%d\n")); | |
102 ErrorInfo error_info; | 206 ErrorInfo error_info; |
103 int32_t file_desc = plugin_->GetPOSIXFileDesc(url); | 207 int32_t file_desc = plugin_->GetPOSIXFileDesc(url); |
104 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) { | 208 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) { |
105 if (pp_error == PP_ERROR_ABORTED) { | 209 if (pp_error == PP_ERROR_ABORTED) { |
106 ReportLoadAbort(); | 210 plugin_->ReportLoadAbort(); |
107 } else { | 211 } else { |
108 // TODO(jvoung): Make a generic load error, or just use ERROR_UNKNOWN? | 212 ReportPpapiError(pp_error, component + " load failed.\n"); |
109 error_info.SetReport(ERROR_UNKNOWN, | |
110 "PNaCl " + component + " load failed."); | |
111 ReportLoadError(error_info); | |
112 } | 213 } |
113 return -1; | 214 return -1; |
114 } | 215 } |
115 int32_t file_desc_ok_to_close = DUP(file_desc); | 216 int32_t file_desc_ok_to_close = DUP(file_desc); |
116 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { | 217 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { |
117 // TODO(jvoung): Make a generic load error, or just use ERROR_UNKNOWN? | 218 ReportPpapiError(PP_ERROR_FAILED, component + " could not dup fd.\n"); |
118 error_info.SetReport(ERROR_UNKNOWN, | |
119 "PNaCl " + component + " load failed: " | |
120 "could not dup fd."); | |
121 ReportLoadError(error_info); | |
122 return -1; | 219 return -1; |
123 } | 220 } |
124 return file_desc_ok_to_close; | 221 return file_desc_ok_to_close; |
125 } | 222 } |
126 | 223 |
127 bool PnaclCoordinator::StartLlcSubProcess() { | 224 PnaclCoordinator::PnaclCoordinator( |
128 ErrorInfo error_info; | 225 Plugin* plugin, |
129 nacl::DescWrapper* wrapper = resources_->WrapperForUrl(llc_url_); | 226 const nacl::string& pexe_url, |
130 NaClSubprocessId llc_id = plugin_->LoadHelperNaClModule(wrapper, &error_info); | 227 const pp::CompletionCallback& translate_notify_callback, |
131 PLUGIN_PRINTF(("PnaclCoordinator::StartLlcSubProcess (nexe_id=%" | 228 const nacl::string& resource_base_url) |
132 NACL_PRId32")\n", llc_id)); | 229 : plugin_(plugin), |
133 if (kInvalidNaClSubprocessId == llc_id) { | 230 translate_notify_callback_(translate_notify_callback), |
134 error_info.SetReport(ERROR_UNKNOWN, "Could not load pnacl compiler nexe"); | 231 resource_base_url_(resource_base_url), |
135 ReportLoadError(error_info); | 232 llc_subprocess_(NULL), |
136 PnaclNonPpapiError(); | 233 ld_subprocess_(NULL), |
234 subprocesses_should_die_(false), | |
235 pexe_url_(pexe_url) { | |
236 PLUGIN_PRINTF(("PnaclCoordinator::PnaclCoordinator (this=%p, plugin=%p)\n", | |
237 static_cast<void*>(this), static_cast<void*>(plugin))); | |
238 callback_factory_.Initialize(this); | |
239 NaClXMutexCtor(&subprocess_mu_); | |
240 // Initialize the file lookup related members. | |
241 NaClXMutexCtor(&lookup_service_mu_); | |
242 NaClXCondVarCtor(&lookup_service_cv_); | |
243 // Open the temporary file system. | |
244 file_system_.reset( | |
robertm
2011/12/13 22:12:51
add this to the ":" section and you wont need the
sehr (please use chromium)
2011/12/14 16:34:20
Done.
| |
245 new pp::FileSystem(plugin, PP_FILESYSTEMTYPE_LOCALTEMPORARY)); | |
246 CHECK(file_system_ != NULL); | |
247 } | |
248 | |
249 PnaclCoordinator::~PnaclCoordinator() { | |
250 PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n", | |
251 static_cast<void*>(this))); | |
252 // Join helper thread which will block the page from refreshing while a | |
253 // translation is happening. | |
254 if (translate_thread_.get() != NULL) { | |
255 SetSubprocessesShouldDie(true); | |
256 NaClThreadJoin(translate_thread_.get()); | |
257 } | |
258 NaClCondVarDtor(&lookup_service_cv_); | |
259 NaClMutexDtor(&lookup_service_mu_); | |
260 NaClMutexDtor(&subprocess_mu_); | |
261 } | |
262 | |
263 void PnaclCoordinator::ReportNonPpapiError(const nacl::string& message) { | |
264 error_info_.SetReport(ERROR_UNKNOWN, | |
265 nacl::string("PnaclCoordinator: ") + message); | |
266 ReportPpapiError(PP_ERROR_FAILED); | |
267 } | |
268 | |
269 void PnaclCoordinator::ReportPpapiError(int32_t pp_error, | |
270 const nacl::string& message) { | |
271 error_info_.SetReport(ERROR_UNKNOWN, | |
272 nacl::string("PnaclCoordinator: ") + message); | |
273 ReportPpapiError(pp_error); | |
274 } | |
275 | |
276 void PnaclCoordinator::ReportPpapiError(int32_t pp_error) { | |
277 plugin_->ReportLoadError(error_info_); | |
278 // Free all the intermediate callbacks we ever created. | |
279 callback_factory_.CancelAll(); | |
280 translate_notify_callback_.Run(pp_error); | |
281 } | |
282 | |
283 void PnaclCoordinator::PnaclDidFinish(int32_t pp_error) { | |
284 PLUGIN_PRINTF(("PnaclCoordinator::PnaclDidFinish (pp_error=%" | |
285 NACL_PRId32")\n", pp_error)); | |
286 if (pp_error != PP_OK) { | |
287 ReportPpapiError(pp_error); | |
288 return; | |
289 } | |
290 // Transfer ownership of the nexe wrapper to the coordinator. | |
291 // TODO(sehr): need to release the translation unit here while transferring. | |
292 translated_fd_.reset(nexe_file_->read_wrapper()); | |
293 plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); | |
294 translate_notify_callback_.Run(pp_error); | |
295 } | |
296 | |
297 void PnaclCoordinator::PnaclFailed(const nacl::string& error_string) { | |
robertm
2011/12/13 22:12:51
rename to translateFailed or similar
add comment:
sehr (please use chromium)
2011/12/14 16:34:20
Name changed. Comment is in header.
| |
298 PLUGIN_PRINTF(("PnaclCoordinator::PnaclFailed (error_string=%" | |
299 NACL_PRId32")\n", error_string.c_str())); | |
300 pp::Core* core = pp::Module::Get()->core(); | |
301 error_info_.SetReport(ERROR_UNKNOWN, | |
302 nacl::string("PnaclCoordinator: ") + error_string); | |
303 core->CallOnMainThread(0, translate_done_cb_, PP_ERROR_FAILED); | |
304 NaClThreadExit(1); | |
305 } | |
306 | |
307 void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) { | |
308 PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%" | |
309 NACL_PRId32")\n", pp_error)); | |
310 if (pp_error != PP_OK) { | |
311 ReportPpapiError(pp_error, "resources failed to load\n"); | |
312 return; | |
313 } | |
314 // Open the local temporary file system to create the temporary files | |
315 // for the object and nexe. | |
316 pp::CompletionCallback cb = | |
317 callback_factory_.NewCallback(&PnaclCoordinator::FileSystemDidOpen); | |
318 if (!file_system_->Open(0, cb)) { | |
319 ReportNonPpapiError("failed to open file system.\n"); | |
320 } | |
321 } | |
322 | |
323 void PnaclCoordinator::FileSystemDidOpen(int32_t pp_error) { | |
324 PLUGIN_PRINTF(("PnaclCoordinator::FileSystemDidOpen (pp_error=%" | |
325 NACL_PRId32")\n", pp_error)); | |
326 if (pp_error != PP_OK) { | |
327 ReportPpapiError(pp_error, "file system didn't open.\n"); | |
328 return; | |
329 } | |
330 // Create the object file pair for connecting llc and ld. | |
331 obj_file_.reset(new PnaclFileDescPair(plugin_, file_system_.get(), this)); | |
332 pp::CompletionCallback cb = | |
333 callback_factory_.NewCallback(&PnaclCoordinator::ObjectPairDidOpen); | |
334 obj_file_->Open(cb); | |
335 } | |
336 | |
337 void PnaclCoordinator::ObjectPairDidOpen(int32_t pp_error) { | |
338 PLUGIN_PRINTF(("PnaclCoordinator::ObjectPairDidOpen (pp_error=%" | |
339 NACL_PRId32")\n", pp_error)); | |
340 if (pp_error != PP_OK) { | |
341 ReportPpapiError(pp_error); | |
342 return; | |
343 } | |
344 // Create the nexe file pair for connecting ld and sel_ldr. | |
345 nexe_file_.reset(new PnaclFileDescPair(plugin_, file_system_.get(), this)); | |
346 pp::CompletionCallback cb = | |
347 callback_factory_.NewCallback(&PnaclCoordinator::NexePairDidOpen); | |
348 nexe_file_->Open(cb); | |
349 } | |
350 | |
351 void PnaclCoordinator::NexePairDidOpen(int32_t pp_error) { | |
352 PLUGIN_PRINTF(("PnaclCoordinator::NexePairDidOpen (pp_error=%" | |
353 NACL_PRId32")\n", pp_error)); | |
354 if (pp_error != PP_OK) { | |
355 ReportPpapiError(pp_error); | |
356 return; | |
357 } | |
358 // Load the pexe file and get the translation started. | |
359 pp::CompletionCallback cb = | |
360 callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate); | |
361 | |
362 if (!plugin_->StreamAsFile(pexe_url_, cb.pp_completion_callback())) { | |
363 ReportNonPpapiError(nacl::string("failed to download ") + pexe_url_ + "\n"); | |
364 } | |
365 } | |
366 | |
367 void PnaclCoordinator::RunTranslate(int32_t pp_error) { | |
368 PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%" | |
369 NACL_PRId32")\n", pp_error)); | |
370 int32_t fd = GetLoadedFileDesc(pp_error, pexe_url_, "pexe"); | |
371 if (fd < 0) { | |
372 return; | |
373 } | |
374 pexe_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); | |
375 llc_subprocess_ = StartSubprocess(kLlcUrl); | |
376 if (llc_subprocess_ == NULL) { | |
377 ReportPpapiError(PP_ERROR_FAILED); | |
378 return; | |
379 } | |
380 ld_subprocess_ = StartSubprocess(kLdUrl); | |
381 if (ld_subprocess_ == NULL) { | |
382 ReportPpapiError(PP_ERROR_FAILED); | |
383 return; | |
384 } | |
385 // Invoke llc followed by ld off the main thread. This allows use of | |
386 // blocking RPCs that would otherwise block the JavaScript main thread. | |
387 translate_done_cb_ = | |
388 callback_factory_.NewCallback(&PnaclCoordinator::PnaclDidFinish); | |
robertm
2011/12/13 22:12:51
PnaclDidFinish is not a good name, TranslateFinish
sehr (please use chromium)
2011/12/14 16:34:20
Done.
| |
389 translate_thread_.reset(new NaClThread); | |
390 if (translate_thread_ == NULL) { | |
391 ReportNonPpapiError("could not allocate thread struct\n"); | |
392 return; | |
393 } | |
394 const int32_t kArbitraryStackSize = 128 << 10; | |
robertm
2011/12/13 22:12:51
128 * 1024 is less "clever".
sehr (please use chromium)
2011/12/14 16:34:20
Done.
| |
395 if (!NaClThreadCreateJoinable(translate_thread_.get(), | |
396 DoTranslateThread, | |
397 this, | |
398 kArbitraryStackSize)) { | |
399 ReportNonPpapiError("could not create thread\n"); | |
400 } | |
401 } | |
402 | |
403 NaClSubprocess* PnaclCoordinator::StartSubprocess(const nacl::string& url) { | |
robertm
2011/12/13 22:12:51
maybe rename url -> url_for_nexe
sehr (please use chromium)
2011/12/14 16:34:20
Done.
| |
404 PLUGIN_PRINTF(("PnaclCoordinator::StartSubprocess (url=%s)\n", url.c_str())); | |
405 nacl::DescWrapper* wrapper = resources_->WrapperForUrl(url); | |
406 NaClSubprocessId id = plugin_->LoadHelperNaClModule(wrapper, &error_info_); | |
407 if (kInvalidNaClSubprocessId == id) { | |
137 return NULL; | 408 return NULL; |
robertm
2011/12/13 22:12:51
error message?
sehr (please use chromium)
2011/12/14 16:34:20
Added a PLUGIN_PRINTF. Caller will invoke ReportP
| |
138 } | 409 } |
139 llc_subprocess_ = plugin_->nacl_subprocess(llc_id); | 410 return plugin_->nacl_subprocess(id); |
140 return (llc_subprocess_ != NULL); | 411 } |
141 } | 412 |
142 | 413 void WINAPI PnaclCoordinator::DoTranslateThread(void* arg) { |
143 bool PnaclCoordinator::StartLdSubProcess() { | 414 PnaclCoordinator* coordinator = reinterpret_cast<PnaclCoordinator*>(arg); |
144 ErrorInfo error_info; | 415 Plugin* plugin = coordinator->plugin_; |
robertm
2011/12/13 22:12:51
I the long it would probably best to move this thr
sehr (please use chromium)
2011/12/14 16:34:20
As we discussed on the phone, I completely agree,
| |
145 nacl::DescWrapper* wrapper = resources_->WrapperForUrl(ld_url_); | 416 BrowserInterface* browser_interface = plugin->browser_interface(); |
146 NaClSubprocessId ld_id = plugin_->LoadHelperNaClModule(wrapper, &error_info); | 417 |
147 PLUGIN_PRINTF(("PnaclCoordinator::StartLdSubProcess (nexe_id=%" | 418 // Run LLC. |
148 NACL_PRId32")\n", ld_id)); | 419 SrpcParams params; |
149 if (kInvalidNaClSubprocessId == ld_id) { | 420 nacl::DescWrapper* llc_out_file = coordinator->obj_file_->write_wrapper(); |
150 error_info.SetReport(ERROR_UNKNOWN, "Could not load pnacl linker nexe"); | 421 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, |
151 ReportLoadError(error_info); | 422 coordinator->llc_subprocess_, |
152 PnaclNonPpapiError(); | 423 "RunWithDefaultCommandLine", |
153 return NULL; | 424 "hh", |
154 } | 425 ¶ms, |
155 ld_subprocess_ = plugin_->nacl_subprocess(ld_id); | 426 coordinator->pexe_wrapper_->desc(), |
156 return (ld_subprocess_ != NULL); | 427 llc_out_file->desc())) { |
428 coordinator->PnaclFailed("compile failed."); | |
429 } | |
430 // LLC returns values that are used to determine how linking is done. | |
431 int is_shared_library = (params.outs()[0]->u.ival != 0); | |
432 nacl::string soname = params.outs()[1]->arrays.str; | |
433 nacl::string lib_dependencies = params.outs()[2]->arrays.str; | |
434 PLUGIN_PRINTF(("PnaclCoordinator: compile (coordinator=%p) succeeded" | |
435 " is_shared_library=%d, soname='%s', lib_dependencies='%s')\n", | |
436 arg, is_shared_library, soname.c_str(), | |
437 lib_dependencies.c_str())); | |
438 if (coordinator->SubprocessesShouldDie()) { | |
439 NaClThreadExit(1); | |
robertm
2011/12/13 22:12:51
maybe printf
sehr (please use chromium)
2011/12/14 16:34:20
Done.
| |
440 } | |
441 // Set up the lookup service for filename to handle resolution. | |
442 NaClSrpcService* service = | |
443 reinterpret_cast<NaClSrpcService*>(calloc(1, sizeof(*service))); | |
444 if (NULL == service) { | |
445 coordinator->PnaclFailed("lookup service alloc failed."); | |
446 } | |
447 if (!NaClSrpcServiceHandlerCtor(service, lookup_methods)) { | |
448 free(service); | |
449 coordinator->PnaclFailed("lookup service constructor failed."); | |
450 } | |
451 char* service_string = const_cast<char*>(service->service_string); | |
452 NaClSubprocess* ld_subprocess = coordinator->ld_subprocess_; | |
453 ld_subprocess->srpc_client()->AttachService(service, coordinator); | |
454 nacl::DescWrapper* ld_out_file = coordinator->nexe_file_->write_wrapper(); | |
455 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, | |
456 ld_subprocess, | |
457 "RunWithDefaultCommandLine", | |
458 "ChiCC", | |
459 ¶ms, | |
460 service_string, | |
461 ld_out_file->desc(), | |
462 is_shared_library, | |
463 soname.c_str(), | |
464 lib_dependencies.c_str())) { | |
465 coordinator->PnaclFailed("link failed."); | |
466 } | |
467 PLUGIN_PRINTF(("PnaclCoordinator: link (coordinator=%p) succeeded\n", arg)); | |
468 if (coordinator->SubprocessesShouldDie()) { | |
robertm
2011/12/13 22:12:51
add a PLUGIN_PRINTF
sehr (please use chromium)
2011/12/14 16:34:20
Done.
| |
469 NaClThreadExit(1); | |
470 } | |
471 pp::Core* core = pp::Module::Get()->core(); | |
472 core->CallOnMainThread(0, coordinator->translate_done_cb_, PP_OK); | |
473 NaClThreadExit(0); | |
157 } | 474 } |
158 | 475 |
159 bool PnaclCoordinator::SubprocessesShouldDie() { | 476 bool PnaclCoordinator::SubprocessesShouldDie() { |
160 nacl::MutexLocker ml(&subprocess_mu_); | 477 nacl::MutexLocker ml(&subprocess_mu_); |
161 return subprocesses_should_die_; | 478 return subprocesses_should_die_; |
162 } | 479 } |
163 | 480 |
164 void PnaclCoordinator::SetSubprocessesShouldDie(bool subprocesses_should_die) { | 481 void PnaclCoordinator::SetSubprocessesShouldDie(bool subprocesses_should_die) { |
165 nacl::MutexLocker ml(&subprocess_mu_); | 482 nacl::MutexLocker ml(&subprocess_mu_); |
166 subprocesses_should_die_ = subprocesses_should_die; | 483 subprocesses_should_die_ = subprocesses_should_die; |
167 } | 484 } |
168 | 485 |
169 ////////////////////////////////////////////////////////////////////// | 486 void PnaclCoordinator::LoadOneFile(int32_t pp_error, |
170 // First few callbacks. | 487 const nacl::string& url, |
171 | 488 nacl::DescWrapper** wrapper, |
172 ////////////////////////////////////////////////////////////////////// | 489 pp::CompletionCallback& done_cb) { |
173 | 490 PLUGIN_PRINTF(("PnaclCoordinator::LoadOneFile (pp_error=%" |
174 namespace { | 491 NACL_PRId32", url=%s)\n", pp_error, url.c_str())); |
175 void AbortTranslateThread(PnaclTranslationUnit* translation_unit, | 492 const nacl::string& full_url = resource_base_url_ + url; |
176 const nacl::string& error_string) { | 493 pp::CompletionCallback callback = |
494 callback_factory_.NewCallback(&PnaclCoordinator::DidLoadFile, | |
495 full_url, | |
496 wrapper, | |
497 done_cb); | |
498 if (!plugin_->StreamAsFile(full_url, callback.pp_completion_callback())) { | |
499 ReportNonPpapiError(nacl::string("failed to load ") + url + "\n"); | |
500 } | |
501 } | |
502 | |
503 void PnaclCoordinator::DidLoadFile(int32_t pp_error, | |
504 const nacl::string& full_url, | |
505 nacl::DescWrapper** wrapper, | |
506 pp::CompletionCallback& done_cb) { | |
507 PLUGIN_PRINTF(("PnaclCoordinator::DidLoadFile (pp_error=%" | |
508 NACL_PRId32", url=%s)\n", pp_error, full_url.c_str())); | |
509 int32_t fd = GetLoadedFileDesc(pp_error, full_url, "resource"); | |
510 if (fd < 0) { | |
511 return; | |
robertm
2011/12/13 22:12:51
maybe also a add a PLUGIN_PRINTF here to make the
sehr (please use chromium)
2011/12/14 16:34:20
Done.
| |
512 } | |
513 *wrapper = plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); | |
514 done_cb.Run(PP_OK); | |
515 } | |
516 | |
517 void PnaclCoordinator::ResumeLookup(int32_t pp_error) { | |
518 PLUGIN_PRINTF(("PnaclCoordinator::ResumeLookup (pp_error=%" | |
519 NACL_PRId32", url=%s)\n", pp_error)); | |
520 UNREFERENCED_PARAMETER(pp_error); | |
521 nacl::MutexLocker ml(&lookup_service_mu_); | |
522 lookup_is_complete_ = true; | |
523 NaClXCondVarBroadcast(&lookup_service_cv_); | |
524 } | |
525 | |
526 // Lookup service called by translator nexes. | |
527 // TODO(sehr): replace this lookup by ReverseService. | |
528 void PnaclCoordinator::LookupInputFile(NaClSrpcRpc* rpc, | |
529 NaClSrpcArg** inputs, | |
530 NaClSrpcArg** outputs, | |
531 NaClSrpcClosure* done) { | |
532 PLUGIN_PRINTF(("PnaclCoordinator::LookupInputFile (url=%s)\n", | |
533 inputs[0]->arrays.str)); | |
534 NaClSrpcClosureRunner runner(done); | |
535 rpc->result = NACL_SRPC_RESULT_APP_ERROR; | |
536 const char* file_name = inputs[0]->arrays.str; | |
537 PnaclCoordinator* coordinator = reinterpret_cast<PnaclCoordinator*>( | |
538 rpc->channel->server_instance_data); | |
539 outputs[0]->u.hval = coordinator->LookupDesc(file_name); | |
540 rpc->result = NACL_SRPC_RESULT_OK; | |
541 } | |
542 | |
543 NaClSrpcHandlerDesc PnaclCoordinator::lookup_methods[] = { | |
544 { "LookupInputFile:s:h", LookupInputFile }, | |
545 { NULL, NULL } | |
546 }; | |
547 | |
548 struct NaClDesc* PnaclCoordinator::LookupDesc(const nacl::string& url) { | |
549 PLUGIN_PRINTF(("PnaclCoordinator::LookupDesc (url=%s)\n", url.c_str())); | |
550 // This filename is part of the contract with the linker. | |
551 // TODO(sehr): Pass the FD in, and move lookup for this file to the linker. | |
552 const nacl::string kGeneratedObjectFileName = "___PNACL_GENERATED"; | |
553 if (url == kGeneratedObjectFileName) { | |
554 return obj_file_->read_wrapper()->desc(); | |
555 } | |
556 nacl::DescWrapper* wrapper; | |
557 // Create the callback used to report when lookup is done. | |
558 pp::CompletionCallback resume_cb = | |
559 callback_factory_.NewCallback(&PnaclCoordinator::ResumeLookup); | |
560 // Run the lookup request on the main thread. | |
561 lookup_is_complete_ = false; | |
562 pp::CompletionCallback load_cb = | |
563 callback_factory_.NewCallback(&PnaclCoordinator::LoadOneFile, | |
564 url, &wrapper, resume_cb); | |
177 pp::Core* core = pp::Module::Get()->core(); | 565 pp::Core* core = pp::Module::Get()->core(); |
178 translation_unit->error_info.SetReport(ERROR_UNKNOWN, error_string); | 566 core->CallOnMainThread(0, load_cb, PP_OK); |
179 core->CallOnMainThread(0, translation_unit->translate_done_cb, | 567 // Wait for completion (timeout every 10ms to check for process end). |
180 PP_ERROR_FAILED); | 568 const int32_t kTenMilliseconds = 10 * 1000 * 1000; |
181 NaClThreadExit(1); | 569 NACL_TIMESPEC_T reltime; |
182 } | 570 reltime.tv_sec = 0; |
183 | 571 reltime.tv_nsec = kTenMilliseconds; |
184 void WINAPI DoTranslateThread(void* arg) { | 572 NaClXMutexLock(&lookup_service_mu_); |
185 PnaclTranslationUnit* p = reinterpret_cast<PnaclTranslationUnit*>(arg); | 573 while (!lookup_is_complete_) { |
186 PnaclCoordinator* coordinator = p->coordinator; | 574 // Check for termination. |
187 NaClSubprocess* llc_subprocess = coordinator->llc_subprocess(); | 575 if (SubprocessesShouldDie()) { |
188 Plugin* plugin = coordinator->plugin(); | 576 NaClXMutexUnlock(&lookup_service_mu_); |
189 BrowserInterface* browser = plugin->browser_interface(); | 577 NaClThreadExit(0); |
190 | |
191 // Set up LLC flags first. | |
192 // TODO(jvoung): Bake these into the llc nexe? | |
193 // May also want to improve scriptability, but the only thing we need | |
194 // probably is PIC vs non-PIC and micro-arch specification. | |
195 const char* llc_args_x8632[] = { "-march=x86", | |
196 "-mcpu=pentium4", | |
197 "-mtriple=i686-none-nacl-gnu", | |
198 "-asm-verbose=false", | |
199 "-filetype=obj" }; | |
200 const char* llc_args_x8664[] = { "-march=x86-64", | |
201 "-mcpu=core2", | |
202 "-mtriple=x86_64-none-nacl-gnu", | |
203 "-asm-verbose=false", | |
204 "-filetype=obj" }; | |
205 const char* llc_args_arm[] = { "-march=arm", | |
206 "-mcpu=cortex-a8", | |
207 "-mtriple=armv7a-none-nacl-gnueabi", | |
208 "-asm-verbose=false", | |
209 "-filetype=obj", | |
210 "-arm-reserve-r9", | |
211 "-sfi-disable-cp", | |
212 "-arm_static_tls", | |
213 "-sfi-store", | |
214 "-sfi-load", | |
215 "-sfi-stack", | |
216 "-sfi-branch", | |
217 "-sfi-data", | |
218 "-no-inline-jumptables" }; | |
219 | |
220 nacl::string sandbox_isa = GetSandboxISA(); | |
221 const char** llc_args; | |
222 size_t num_args; | |
223 | |
224 if (sandbox_isa.compare("x86-32") == 0) { | |
225 llc_args = llc_args_x8632; | |
226 num_args = NACL_ARRAY_SIZE(llc_args_x8632); | |
227 } else if (sandbox_isa.compare("x86-64") == 0) { | |
228 llc_args = llc_args_x8664; | |
229 num_args = NACL_ARRAY_SIZE(llc_args_x8664); | |
230 } else if (sandbox_isa.compare("arm") == 0) { | |
231 llc_args = llc_args_arm; | |
232 num_args = NACL_ARRAY_SIZE(llc_args_arm); | |
233 } else { | |
234 AbortTranslateThread(p, | |
235 "PnaclCoordinator compiler unhandled ISA " + | |
236 sandbox_isa + "."); | |
237 return; | |
238 } | |
239 | |
240 for (uint32_t i = 0; i < num_args; i++) { | |
241 if (coordinator->SubprocessesShouldDie()) { | |
242 NaClThreadExit(1); | |
243 } | 578 } |
244 SrpcParams dummy_params; | 579 NaClXCondVarTimedWaitRelative(&lookup_service_cv_, |
245 if (!PnaclSrpcLib::InvokeSrpcMethod(browser, | 580 &lookup_service_mu_, |
246 llc_subprocess, | 581 &reltime); |
247 "AddArg", | 582 } |
248 "C", | 583 NaClXMutexUnlock(&lookup_service_mu_); |
249 &dummy_params, | 584 return wrapper->desc(); |
250 llc_args[i])) { | |
251 AbortTranslateThread(p, | |
252 "PnaclCoordinator compiler AddArg(" + | |
253 nacl::string(llc_args[i]) + ") failed."); | |
254 } | |
255 } | |
256 | |
257 if (coordinator->SubprocessesShouldDie()) { | |
258 NaClThreadExit(1); | |
259 } | |
260 SrpcParams params; | |
261 if (!PnaclSrpcLib::InvokeSrpcMethod(browser, | |
262 llc_subprocess, | |
263 "Translate", | |
264 "h", | |
265 ¶ms, | |
266 p->pexe_wrapper->desc())) { | |
267 AbortTranslateThread(p, | |
268 "PnaclCoordinator compile failed."); | |
269 } else { | |
270 // Grab the outparams. | |
271 p->obj_wrapper.reset( | |
272 plugin->wrapper_factory()->MakeGeneric(params.outs()[0]->u.hval)); | |
273 p->obj_len = params.outs()[1]->u.ival; | |
274 p->is_shared_library = params.outs()[2]->u.ival != 0; | |
275 p->soname = params.outs()[3]->arrays.str; | |
276 p->lib_dependencies = params.outs()[4]->arrays.str; | |
277 PLUGIN_PRINTF(("PnaclCoordinator::Translate SRPC succeeded (bytes=%" | |
278 NACL_PRId32", is_shared_library=%d, soname='%s', " | |
279 "lib_dependencies='%s')\n", p->obj_len, | |
280 p->is_shared_library, p->soname.c_str(), | |
281 p->lib_dependencies.c_str())); | |
282 } | |
283 if (coordinator->SubprocessesShouldDie()) { | |
284 NaClThreadExit(1); | |
285 } | |
286 pp::Core* core = pp::Module::Get()->core(); | |
287 core->CallOnMainThread(0, p->translate_done_cb, PP_OK); | |
288 NaClThreadExit(0); | |
289 } | |
290 | |
291 } // namespace | |
292 | |
293 void PnaclCoordinator::RunTranslate(int32_t pp_error, | |
294 const nacl::string& pexe_url, | |
295 PnaclTranslationUnit* translation_unit) { | |
296 PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%" | |
297 NACL_PRId32")\n", pp_error)); | |
298 // pp_error is checked by GetLoadedFileDesc. | |
299 int32_t fd = GetLoadedFileDesc(pp_error, pexe_url, "pexe"); | |
300 if (fd < 0) { | |
301 PnaclPpapiError(pp_error); | |
302 return; | |
303 } | |
304 translation_unit->pexe_wrapper.reset( | |
305 plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY)); | |
306 if (!StartLlcSubProcess()) { | |
307 ErrorInfo error_info; | |
308 error_info.SetReport(ERROR_UNKNOWN, | |
309 "Could not start compiler subprocess\n"); | |
310 ReportLoadError(error_info); | |
311 PnaclNonPpapiError(); | |
312 return; | |
313 } | |
314 // Invoke llvm asynchronously. | |
315 // RunLink runs on the main thread when llvm is done. | |
316 translation_unit->translate_done_cb = | |
317 callback_factory_.NewCallback(&PnaclCoordinator::RunLink, | |
318 translation_unit); | |
319 translate_thread_.reset(new NaClThread); | |
320 if (translate_thread_ == NULL) { | |
321 ErrorInfo error_info; | |
322 error_info.SetReport(ERROR_UNKNOWN, | |
323 "Could not allocate DoTranslateThread()\n"); | |
324 ReportLoadError(error_info); | |
325 PnaclNonPpapiError(); | |
326 return; | |
327 } | |
328 if (!NaClThreadCreateJoinable(translate_thread_.get(), | |
329 DoTranslateThread, | |
330 translation_unit, | |
331 kArbitraryStackSize)) { | |
332 ErrorInfo error_info; | |
333 error_info.SetReport(ERROR_UNKNOWN, | |
334 "Could not create a translator thread.\n"); | |
335 ReportLoadError(error_info); | |
336 PnaclNonPpapiError(); | |
337 } | |
338 } | |
339 | |
340 ////////////////////////////////////////////////////////////////////// | |
341 // Helper functions for loading native libs. | |
342 // Done here to avoid hacking on the manifest parser further... | |
343 | |
344 namespace { | |
345 | |
346 // Fake filename for the object file generated by llvm. | |
347 nacl::string GeneratedObjectFileName() { | |
348 return nacl::string("___PNACL_GENERATED"); | |
349 } | |
350 | |
351 nacl::string ResourceBaseUrl() { | |
352 nacl::string sandbox_isa = GetSandboxISA(); | |
353 nacl::string base_url = "pnacl_support/" + sandbox_isa + "/"; | |
354 return base_url; | |
355 } | |
356 | |
357 string_vector LinkResources(const nacl::string& sandbox_isa, | |
358 bool withGenerated) { | |
359 string_vector results; | |
360 // NOTE: order of items == link order. | |
361 if (sandbox_isa.compare("x86-64") == 0) { | |
362 results.push_back("libpnacl_irt_shim.a"); | |
363 } | |
364 results.push_back("crtbegin.o"); | |
365 if (withGenerated) { | |
366 results.push_back(GeneratedObjectFileName()); | |
367 } | |
368 results.push_back("libcrt_platform.a"); | |
369 results.push_back("libgcc.a"); | |
370 results.push_back("libgcc_eh.a"); | |
371 results.push_back("crtend.o"); | |
372 return results; | |
373 } | |
374 | |
375 } // namespace | |
376 | |
377 ////////////////////////////////////////////////////////////////////// | |
378 // Final link callbacks. | |
379 | |
380 namespace { | |
381 | |
382 void AbortLinkThread(PnaclTranslationUnit* translation_unit, | |
383 const nacl::string& error_string) { | |
384 ErrorInfo error_info; | |
385 pp::Core* core = pp::Module::Get()->core(); | |
386 translation_unit->error_info.SetReport(ERROR_UNKNOWN, error_string); | |
387 core->CallOnMainThread(0, translation_unit->link_done_cb, PP_ERROR_FAILED); | |
388 NaClThreadExit(1); | |
389 } | |
390 | |
391 void WINAPI DoLinkThread(void* arg) { | |
392 PnaclTranslationUnit* p = reinterpret_cast<PnaclTranslationUnit*>(arg); | |
393 PnaclCoordinator* coordinator = p->coordinator; | |
394 NaClSubprocess* ld_subprocess = coordinator->ld_subprocess(); | |
395 Plugin* plugin = coordinator->plugin(); | |
396 BrowserInterface* browser_interface = plugin->browser_interface(); | |
397 | |
398 // Set up command line arguments (flags then files). | |
399 | |
400 //// Flags. | |
401 // TODO(jvoung): Be able to handle the dynamic linking flags too, | |
402 // and don't hardcode so much here. | |
403 string_vector flags; | |
404 nacl::string sandbox_isa = GetSandboxISA(); | |
405 flags.push_back("-nostdlib"); | |
406 flags.push_back("-m"); | |
407 if (sandbox_isa.compare("x86-32") == 0) { | |
408 flags.push_back("elf_nacl"); | |
409 } else if (sandbox_isa.compare("x86-64") == 0) { | |
410 flags.push_back("elf64_nacl"); | |
411 flags.push_back("-entry=_pnacl_wrapper_start"); | |
412 } else if (sandbox_isa.compare("arm") == 0) { | |
413 flags.push_back("armelf_nacl"); | |
414 } else { | |
415 AbortLinkThread(p, | |
416 "PnaclCoordinator linker unhandled ISA " + | |
417 sandbox_isa + "."); | |
418 } | |
419 | |
420 for (string_vector::iterator i = flags.begin(), e = flags.end(); | |
421 i != e; ++i) { | |
422 const nacl::string& flag = *i; | |
423 if (coordinator->SubprocessesShouldDie()) { | |
424 NaClThreadExit(1); | |
425 } | |
426 SrpcParams dummy_params; | |
427 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, | |
428 ld_subprocess, | |
429 "AddArg", | |
430 "C", | |
431 &dummy_params, | |
432 flag.c_str())) { | |
433 AbortLinkThread(p, | |
434 "PnaclCoordinator linker AddArg(" + flag + | |
435 ") failed."); | |
436 } | |
437 } | |
438 | |
439 //// Files. | |
440 string_vector files = LinkResources(sandbox_isa, true); | |
441 PnaclResources* resources = coordinator->resources(); | |
442 for (string_vector::iterator i = files.begin(), e = files.end(); | |
443 i != e; ++i) { | |
444 const nacl::string& link_file = *i; | |
445 if (coordinator->SubprocessesShouldDie()) { | |
446 NaClThreadExit(1); | |
447 } | |
448 // Add as argument. | |
449 SrpcParams dummy_params; | |
450 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, | |
451 ld_subprocess, | |
452 "AddArg", | |
453 "C", | |
454 &dummy_params, | |
455 link_file.c_str())) { | |
456 AbortLinkThread(p, | |
457 "PnaclCoordinator linker AddArg(" + | |
458 link_file + ") failed."); | |
459 } | |
460 // Also map the file name to descriptor. | |
461 if (i->compare(GeneratedObjectFileName()) == 0) { | |
462 SrpcParams dummy_params2; | |
463 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, | |
464 ld_subprocess, | |
465 "AddFileWithSize", | |
466 "Chi", | |
467 &dummy_params2, | |
468 link_file.c_str(), | |
469 p->obj_wrapper->desc(), | |
470 p->obj_len)) { | |
471 AbortLinkThread(p, | |
472 "PnaclCoordinator linker AddFileWithSize" | |
473 "(" + link_file + ") failed."); | |
474 } | |
475 } else { | |
476 SrpcParams dummy_params2; | |
477 NaClDesc* link_file_desc = resources->WrapperForUrl(link_file)->desc(); | |
478 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, | |
479 ld_subprocess, | |
480 "AddFile", | |
481 "Ch", | |
482 &dummy_params2, | |
483 link_file.c_str(), | |
484 link_file_desc)) { | |
485 AbortLinkThread(p, | |
486 "PnaclCoordinator linker AddFile(" + link_file + | |
487 ") failed."); | |
488 } | |
489 } | |
490 } | |
491 | |
492 if (coordinator->SubprocessesShouldDie()) { | |
493 NaClThreadExit(1); | |
494 } | |
495 | |
496 // Finally, do the Link! | |
497 SrpcParams params; | |
498 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface, | |
499 ld_subprocess, | |
500 "Link", | |
501 "", | |
502 ¶ms)) { | |
503 AbortLinkThread(p, "PnaclCoordinator link failed."); | |
504 } else { | |
505 // Grab the outparams. | |
506 p->nexe_wrapper.reset( | |
507 plugin->wrapper_factory()->MakeGeneric(params.outs()[0]->u.hval)); | |
508 int32_t nexe_size = params.outs()[1]->u.ival; // only for debug. | |
509 PLUGIN_PRINTF(("PnaclCoordinator::InvokeLink succeeded (bytes=%" | |
510 NACL_PRId32")\n", nexe_size)); | |
511 } | |
512 if (coordinator->SubprocessesShouldDie()) { | |
513 NaClThreadExit(1); | |
514 } | |
515 pp::Core* core = pp::Module::Get()->core(); | |
516 core->CallOnMainThread(0, p->link_done_cb, PP_OK); | |
517 NaClThreadExit(0); | |
518 } | |
519 | |
520 } // namespace | |
521 | |
522 void PnaclCoordinator::RunLink(int32_t pp_error, | |
523 PnaclTranslationUnit* translation_unit) { | |
524 PLUGIN_PRINTF(("PnaclCoordinator::RunLink (pp_error=%" | |
525 NACL_PRId32")\n", pp_error)); | |
526 if (pp_error != PP_OK) { | |
527 ReportLoadError(translation_unit->error_info); | |
528 PnaclPpapiError(pp_error); | |
529 return; | |
530 } | |
531 plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); | |
532 if (!StartLdSubProcess()) { | |
533 ErrorInfo error_info; | |
534 error_info.SetReport(ERROR_UNKNOWN, | |
535 "Could not start linker subprocess\n"); | |
536 ReportLoadError(error_info); | |
537 PnaclNonPpapiError(); | |
538 return; | |
539 } | |
540 | |
541 // Invoke ld asynchronously. | |
542 // When ld has completed, PnaclDidFinish is run on the main thread. | |
543 translation_unit->link_done_cb = | |
544 callback_factory_.NewCallback(&PnaclCoordinator::PnaclDidFinish, | |
545 translation_unit); | |
546 link_thread_.reset(new NaClThread); | |
547 if (link_thread_ == NULL) { | |
548 ErrorInfo error_info; | |
549 error_info.SetReport(ERROR_UNKNOWN, | |
550 "Could not allocate DoLinkThread()\n"); | |
551 ReportLoadError(error_info); | |
552 PnaclNonPpapiError(); | |
553 return; | |
554 } | |
555 if (!NaClThreadCreateJoinable(link_thread_.get(), | |
556 DoLinkThread, | |
557 translation_unit, | |
558 kArbitraryStackSize)) { | |
559 ErrorInfo error_info; | |
560 error_info.SetReport(ERROR_UNKNOWN, | |
561 "Could not create a linker thread.\n"); | |
562 ReportLoadError(error_info); | |
563 PnaclNonPpapiError(); | |
564 } | |
565 } | |
566 | |
567 ////////////////////////////////////////////////////////////////////// | |
568 | |
569 void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error, | |
570 const nacl::string& pexe_url, | |
571 PnaclTranslationUnit* translation) { | |
572 PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%" | |
573 NACL_PRId32")\n", pp_error)); | |
574 if (pp_error != PP_OK) { | |
575 ReportLoadError(translation->error_info); | |
576 PnaclPpapiError(pp_error); | |
577 return; | |
578 } | |
579 pp::CompletionCallback cb = | |
580 callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate, | |
581 pexe_url, | |
582 translation); | |
583 | |
584 if (!plugin_->StreamAsFile(pexe_url, cb.pp_completion_callback())) { | |
585 ErrorInfo error_info; | |
586 error_info.SetReport(ERROR_UNKNOWN, | |
587 "PnaclCoordinator: Failed to download file: " + | |
588 pexe_url + "\n"); | |
589 ReportLoadError(error_info); | |
590 PnaclNonPpapiError(); | |
591 } | |
592 } | |
593 | |
594 void PnaclCoordinator::BitcodeToNative( | |
595 const nacl::string& pexe_url, | |
596 const pp::CompletionCallback& finish_callback) { | |
597 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (pexe=%s)\n", | |
598 pexe_url.c_str())); | |
599 // The base URL for finding all the resources will be obtained from the | |
600 // PNaCl manifest file. | |
601 // Also, the llc and ld pathnames should be read from the manifest. | |
602 // TODO(sehr): change to use the manifest file when ready. | |
603 resource_base_url_ = ResourceBaseUrl(); | |
604 llc_url_ = "llc"; | |
605 ld_url_ = "ld"; | |
606 translate_notify_callback_ = finish_callback; | |
607 | |
608 // Steps: | |
609 // (1) Schedule downloads for llc, ld nexes, and native libraries (resources). | |
610 // (2) When resources have been downloaded, download pexe. | |
611 // (3) When pexe download has completed, start translation. | |
612 // (4) When llc translation has finished do the link. | |
613 // (5) When the link is done, we are done, call the finish_callback. | |
614 // Hand off the SHM file descriptor returned by link. | |
615 | |
616 // Set up async callbacks for these steps in reverse order. | |
617 | |
618 translation_unit_.reset(new PnaclTranslationUnit(this)); | |
619 | |
620 // When resources loading completes, this causes the pexe download. | |
621 pp::CompletionCallback resources_cb = | |
622 callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad, | |
623 pexe_url, | |
624 translation_unit_.get()); | |
625 resources_->AddResourceUrl(llc_url_); | |
626 resources_->AddResourceUrl(ld_url_); | |
627 string_vector link_resources = LinkResources(GetSandboxISA(), false); | |
628 for (string_vector::iterator | |
629 i = link_resources.begin(), e = link_resources.end(); | |
630 i != e; | |
631 ++i) { | |
632 resources_->AddResourceUrl(*i); | |
633 } | |
634 resources_->RunWhenAllLoaded(resources_cb); | |
635 resources_->StartDownloads(); | |
636 } | 585 } |
637 | 586 |
638 } // namespace plugin | 587 } // namespace plugin |
OLD | NEW |