Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc

Issue 8786005: Move command line processing out of coordinator (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 nacl::string ResourceBaseUrl() {
36 return nacl::string("pnacl_support/") + GetSandboxISA() + "/";
37 }
38
39 nacl::string Random32CharHexString(struct NaClDescRng* rng) {
40 struct NaClDesc* desc = reinterpret_cast<struct NaClDesc*>(rng);
41 const struct NaClDescVtbl* vtbl =
42 reinterpret_cast<const struct NaClDescVtbl*>(desc->base.vtbl);
43
44 nacl::string hex_string;
45 const int32_t kTempFileNameWords = 4;
46 for (int32_t i = 0; i < kTempFileNameWords; ++i) {
47 int32_t num;
48 CHECK(sizeof num == vtbl->Read(desc,
49 reinterpret_cast<char*>(&num),
50 sizeof num));
51 char frag[16];
52 SNPRINTF(frag, sizeof frag, "%08x", num);
53 hex_string += nacl::string(frag);
54 }
55 return hex_string;
56 }
57
58 // Some constants for PnaclFileDescPair::GetFD readability.
59 const bool kReadOnly = false;
60 const bool kWriteable = true;
29 61
30 } // namespace 62 } // namespace
31 63
32 namespace plugin { 64 //////////////////////////////////////////////////////////////////////
33 65 PnaclFileDescPair::PnaclFileDescPair(Plugin* plugin,
34 class Plugin; 66 pp::FileSystem* file_system,
35 67 PnaclCoordinator* coordinator)
36 void PnaclCoordinator::Initialize(Plugin* plugin) { 68 : plugin_(plugin),
37 PLUGIN_PRINTF(("PnaclCoordinator::Initialize (this=%p)\n", 69 file_system_(file_system),
38 static_cast<void*>(this))); 70 coordinator_(coordinator) {
39 CHECK(plugin != NULL); 71 PLUGIN_PRINTF(("PnaclFileDescPair::PnaclFileDescPair (plugin=%p, "
40 CHECK(plugin_ == NULL); // Can only initialize once. 72 "file_system=%p, coordinator=%p)\n",
41 plugin_ = plugin; 73 static_cast<void*>(plugin), static_cast<void*>(file_system),
74 static_cast<void*>(coordinator)));
42 callback_factory_.Initialize(this); 75 callback_factory_.Initialize(this);
43 resources_.reset(new PnaclResources(plugin, this)); 76 CHECK(NaClDescRngCtor(&rng_desc_));
44 resources_->Initialize(); 77 file_io_trusted_ = static_cast<const PPB_FileIOTrusted*>(
45 } 78 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE));
46 79 // Get a random temp file name.
47 PnaclCoordinator::~PnaclCoordinator() { 80 filename_ = "/" + Random32CharHexString(&rng_desc_);
48 PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n", 81 }
49 static_cast<void*>(this))); 82
50 83 PnaclFileDescPair::~PnaclFileDescPair() {
51 // Join helper threads which will block the page from refreshing while a 84 PLUGIN_PRINTF(("PnaclFileDescPair::~PnaclFileDescPair\n"));
52 // translation is happening. 85 NaClDescUnref(reinterpret_cast<NaClDesc*>(&rng_desc_));
53 if (translate_thread_.get() != NULL || link_thread_.get() != NULL) { 86 }
54 SetSubprocessesShouldDie(true); 87
55 } 88 void PnaclFileDescPair::Open(const pp::CompletionCallback& cb) {
56 if (translate_thread_.get() != NULL) { 89 PLUGIN_PRINTF(("PnaclFileDescPair::Open\n"));
57 NaClThreadJoin(translate_thread_.get()); 90 done_callback_ = cb;
58 } 91
59 if (link_thread_.get() != NULL) { 92 write_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str()));
60 NaClThreadJoin(link_thread_.get()); 93 write_io_.reset(new pp::FileIO(plugin_));
61 } 94 read_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str()));
62 } 95 read_io_.reset(new pp::FileIO(plugin_));
63 96
64 void PnaclCoordinator::ReportLoadAbort() { 97 pp::CompletionCallback open_write_cb =
65 plugin_->ReportLoadAbort(); 98 callback_factory_.NewCallback(&PnaclFileDescPair::WriteFileDidOpen);
66 } 99 // Open the writeable file.
67 100 write_io_->Open(*write_ref_,
68 void PnaclCoordinator::ReportLoadError(const ErrorInfo& error) { 101 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE,
69 plugin_->ReportLoadError(error); 102 open_write_cb);
70 } 103 }
71 104
72 void PnaclCoordinator::PnaclPpapiError(int32_t pp_error) { 105 int32_t PnaclFileDescPair::GetFD(int32_t pp_error,
73 // Attempt to free all the intermediate callbacks we ever created. 106 const pp::Resource& resource,
74 callback_factory_.CancelAll(); 107 bool is_writable) {
75 translate_notify_callback_.Run(pp_error); 108 PLUGIN_PRINTF(("PnaclFileDescPair::GetFD (pp_error=%"NACL_PRId32
76 } 109 ", 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) { 110 if (pp_error != PP_OK) {
87 ReportLoadError(translation_unit->error_info); 111 PLUGIN_PRINTF(("PnaclFileDescPair::GetFD pp_error != PP_OK\n"));
88 PnaclPpapiError(pp_error); 112 return -1;
89 return; 113 }
90 } 114 int32_t file_desc =
91 // Transfer ownership of the nexe wrapper to the coordinator. 115 file_io_trusted_->GetOSFileDescriptor(resource.pp_resource());
92 translated_fd_.reset(translation_unit->nexe_wrapper.release()); 116 #if NACL_WINDOWS
93 plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); 117 // Convert the Windows HANDLE from Pepper to a POSIX file descriptor.
94 translate_notify_callback_.Run(pp_error); 118 int32_t open_flags = ((is_writable ? _O_RDWR : _O_RDONLY) | _O_BINARY);
119 int32_t posix_desc = _open_osfhandle(file_desc, open_flags);
120 if (posix_desc == -1) {
121 // Close the Windows HANDLE if it can't be converted.
122 CloseHandle(reinterpret_cast<HANDLE>(file_desc));
123 PLUGIN_PRINTF(("PnaclFileDescPair::GetFD _open_osfhandle failed.\n"));
124 return NACL_NO_FILE_DESC;
125 }
126 file_desc = posix_desc;
127 #endif
128 int32_t file_desc_ok_to_close = DUP(file_desc);
129 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) {
130 PLUGIN_PRINTF(("PnaclFileDescPair::GetFD dup failed.\n"));
131 return -1;
132 }
133 return file_desc_ok_to_close;
134 }
135
136 void PnaclFileDescPair::WriteFileDidOpen(int32_t pp_error) {
137 PLUGIN_PRINTF(("PnaclFileDescPair::WriteFileDidOpen (pp_error=%"
138 NACL_PRId32")\n", pp_error));
139 // Remember the object temporary file descriptor.
140 int32_t fd = GetFD(pp_error, *write_io_, kWriteable);
141 if (fd < 0) {
142 coordinator_->ReportNonPpapiError("could not open write temp file\n");
143 return;
144 }
145 write_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDWR));
146 pp::CompletionCallback open_read_cb =
147 callback_factory_.NewCallback(&PnaclFileDescPair::ReadFileDidOpen);
148 // Open the read only file.
149 read_io_->Open(*read_ref_, PP_FILEOPENFLAG_READ, open_read_cb);
150 }
151
152 void PnaclFileDescPair::ReadFileDidOpen(int32_t pp_error) {
153 PLUGIN_PRINTF(("PnaclFileDescPair::ReadFileDidOpen (pp_error=%"
154 NACL_PRId32")\n", pp_error));
155 // Remember the object temporary file descriptor.
156 int32_t fd = GetFD(pp_error, *read_io_, kReadOnly);
157 if (fd < 0) {
158 coordinator_->ReportNonPpapiError("could not open read temp file\n");
159 return;
160 }
161 read_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY));
162 // Run the client's completion callback.
163 pp::Core* core = pp::Module::Get()->core();
164 core->CallOnMainThread(0, done_callback_, PP_OK);
95 } 165 }
96 166
97 ////////////////////////////////////////////////////////////////////// 167 //////////////////////////////////////////////////////////////////////
168 PnaclCoordinator* PnaclCoordinator::BitcodeToNative(
169 Plugin* plugin,
170 const nacl::string& pexe_url,
171 const pp::CompletionCallback& translate_notify_callback) {
172 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (plugin=%p, pexe=%s)\n",
173 static_cast<void*>(plugin), pexe_url.c_str()));
174 PnaclCoordinator* coordinator =
175 new PnaclCoordinator(plugin,
176 pexe_url,
177 translate_notify_callback,
178 ResourceBaseUrl());
179 // Load llc and ld.
180 std::vector<nacl::string> resource_urls;
181 resource_urls.push_back(kLlcUrl);
182 resource_urls.push_back(kLdUrl);
183 pp::CompletionCallback resources_cb =
184 coordinator->callback_factory_.NewCallback(
185 &PnaclCoordinator::ResourcesDidLoad);
186 coordinator->resources_.reset(
187 new PnaclResources(plugin,
188 coordinator,
189 coordinator->resource_base_url_,
190 resource_urls,
191 resources_cb));
192 CHECK(coordinator->resources_ != NULL);
193 coordinator->resources_->StartDownloads();
194 // ResourcesDidLoad will be invoked when all resources have been received.
195 return coordinator;
196 }
98 197
99 int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error, 198 int32_t PnaclCoordinator::GetLoadedFileDesc(int32_t pp_error,
100 const nacl::string& url, 199 const nacl::string& url,
101 const nacl::string& component) { 200 const nacl::string& component) {
201 PLUGIN_PRINTF(("PnaclCoordinator::GetLoadedFileDesc (pp_error=%"
202 NACL_PRId32", url=%s, component=%s)\n", pp_error,
203 url.c_str(), component.c_str()));
204 PLUGIN_PRINTF(("PnaclCoordinator::GetLoadedFileDesc (pp_error=%d\n"));
102 ErrorInfo error_info; 205 ErrorInfo error_info;
103 int32_t file_desc = plugin_->GetPOSIXFileDesc(url); 206 int32_t file_desc = plugin_->GetPOSIXFileDesc(url);
104 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) { 207 if (pp_error != PP_OK || file_desc == NACL_NO_FILE_DESC) {
105 if (pp_error == PP_ERROR_ABORTED) { 208 if (pp_error == PP_ERROR_ABORTED) {
106 ReportLoadAbort(); 209 plugin_->ReportLoadAbort();
107 } else { 210 } else {
108 // TODO(jvoung): Make a generic load error, or just use ERROR_UNKNOWN? 211 ReportPpapiError(pp_error, component + " load failed.\n");
109 error_info.SetReport(ERROR_UNKNOWN,
110 "PNaCl " + component + " load failed.");
111 ReportLoadError(error_info);
112 } 212 }
113 return -1; 213 return -1;
114 } 214 }
115 int32_t file_desc_ok_to_close = DUP(file_desc); 215 int32_t file_desc_ok_to_close = DUP(file_desc);
116 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) { 216 if (file_desc_ok_to_close == NACL_NO_FILE_DESC) {
117 // TODO(jvoung): Make a generic load error, or just use ERROR_UNKNOWN? 217 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; 218 return -1;
123 } 219 }
124 return file_desc_ok_to_close; 220 return file_desc_ok_to_close;
125 } 221 }
126 222
127 bool PnaclCoordinator::StartLlcSubProcess() { 223 PnaclCoordinator::PnaclCoordinator(
128 ErrorInfo error_info; 224 Plugin* plugin,
129 nacl::DescWrapper* wrapper = resources_->WrapperForUrl(llc_url_); 225 const nacl::string& pexe_url,
130 NaClSubprocessId llc_id = plugin_->LoadHelperNaClModule(wrapper, &error_info); 226 const pp::CompletionCallback& translate_notify_callback,
131 PLUGIN_PRINTF(("PnaclCoordinator::StartLlcSubProcess (nexe_id=%" 227 const nacl::string& resource_base_url)
132 NACL_PRId32")\n", llc_id)); 228 : plugin_(plugin),
133 if (kInvalidNaClSubprocessId == llc_id) { 229 translate_notify_callback_(translate_notify_callback),
134 error_info.SetReport(ERROR_UNKNOWN, "Could not load pnacl compiler nexe"); 230 resource_base_url_(resource_base_url),
135 ReportLoadError(error_info); 231 llc_subprocess_(NULL),
136 PnaclNonPpapiError(); 232 ld_subprocess_(NULL),
233 subprocesses_should_die_(false),
234 file_system_(new pp::FileSystem(plugin, PP_FILESYSTEMTYPE_LOCALTEMPORARY)),
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 CHECK(file_system_ != NULL);
245 }
246
247 PnaclCoordinator::~PnaclCoordinator() {
248 PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p)\n",
249 static_cast<void*>(this)));
250 // Join helper thread which will block the page from refreshing while a
251 // translation is happening.
252 if (translate_thread_.get() != NULL) {
253 SetSubprocessesShouldDie(true);
254 NaClThreadJoin(translate_thread_.get());
255 }
256 NaClCondVarDtor(&lookup_service_cv_);
257 NaClMutexDtor(&lookup_service_mu_);
258 NaClMutexDtor(&subprocess_mu_);
259 }
260
261 void PnaclCoordinator::ReportNonPpapiError(const nacl::string& message) {
262 error_info_.SetReport(ERROR_UNKNOWN,
263 nacl::string("PnaclCoordinator: ") + message);
264 ReportPpapiError(PP_ERROR_FAILED);
265 }
266
267 void PnaclCoordinator::ReportPpapiError(int32_t pp_error,
268 const nacl::string& message) {
269 error_info_.SetReport(ERROR_UNKNOWN,
270 nacl::string("PnaclCoordinator: ") + message);
271 ReportPpapiError(pp_error);
272 }
273
274 void PnaclCoordinator::ReportPpapiError(int32_t pp_error) {
275 PLUGIN_PRINTF(("PnaclCoordinator::ReportPpappiError (pp_error=%"
276 NACL_PRId32", error_code=%d, message=%s)\n",
277 pp_error, error_info_.error_code(),
278 error_info_.message().c_str()));
279 plugin_->ReportLoadError(error_info_);
280 // Free all the intermediate callbacks we ever created.
281 callback_factory_.CancelAll();
282 translate_notify_callback_.Run(pp_error);
283 }
284
285 void PnaclCoordinator::TranslateFinished(int32_t pp_error) {
286 PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%"
287 NACL_PRId32")\n", pp_error));
288 if (pp_error != PP_OK) {
289 ReportPpapiError(pp_error);
290 return;
291 }
292 // Transfer ownership of the nexe wrapper to the coordinator.
293 // TODO(sehr): need to release the translation unit here while transferring.
294 translated_fd_.reset(nexe_file_->read_wrapper());
295 plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress);
296 translate_notify_callback_.Run(pp_error);
297 }
298
299 void PnaclCoordinator::TranslateFailed(const nacl::string& error_string) {
300 PLUGIN_PRINTF(("PnaclCoordinator::TranslateFailed (error_string=%"
301 NACL_PRId32")\n", error_string.c_str()));
302 pp::Core* core = pp::Module::Get()->core();
303 error_info_.SetReport(ERROR_UNKNOWN,
304 nacl::string("PnaclCoordinator: ") + error_string);
305 core->CallOnMainThread(0, translate_done_cb_, PP_ERROR_FAILED);
306 NaClThreadExit(1);
307 }
308
309 void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) {
310 PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%"
311 NACL_PRId32")\n", pp_error));
312 if (pp_error != PP_OK) {
313 ReportPpapiError(pp_error, "resources failed to load\n");
314 return;
315 }
316 // Open the local temporary file system to create the temporary files
317 // for the object and nexe.
318 pp::CompletionCallback cb =
319 callback_factory_.NewCallback(&PnaclCoordinator::FileSystemDidOpen);
320 if (!file_system_->Open(0, cb)) {
321 ReportNonPpapiError("failed to open file system.\n");
322 }
323 }
324
325 void PnaclCoordinator::FileSystemDidOpen(int32_t pp_error) {
326 PLUGIN_PRINTF(("PnaclCoordinator::FileSystemDidOpen (pp_error=%"
327 NACL_PRId32")\n", pp_error));
328 if (pp_error != PP_OK) {
329 ReportPpapiError(pp_error, "file system didn't open.\n");
330 return;
331 }
332 // Create the object file pair for connecting llc and ld.
333 obj_file_.reset(new PnaclFileDescPair(plugin_, file_system_.get(), this));
334 pp::CompletionCallback cb =
335 callback_factory_.NewCallback(&PnaclCoordinator::ObjectPairDidOpen);
336 obj_file_->Open(cb);
337 }
338
339 void PnaclCoordinator::ObjectPairDidOpen(int32_t pp_error) {
340 PLUGIN_PRINTF(("PnaclCoordinator::ObjectPairDidOpen (pp_error=%"
341 NACL_PRId32")\n", pp_error));
342 if (pp_error != PP_OK) {
343 ReportPpapiError(pp_error);
344 return;
345 }
346 // Create the nexe file pair for connecting ld and sel_ldr.
347 nexe_file_.reset(new PnaclFileDescPair(plugin_, file_system_.get(), this));
348 pp::CompletionCallback cb =
349 callback_factory_.NewCallback(&PnaclCoordinator::NexePairDidOpen);
350 nexe_file_->Open(cb);
351 }
352
353 void PnaclCoordinator::NexePairDidOpen(int32_t pp_error) {
354 PLUGIN_PRINTF(("PnaclCoordinator::NexePairDidOpen (pp_error=%"
355 NACL_PRId32")\n", pp_error));
356 if (pp_error != PP_OK) {
357 ReportPpapiError(pp_error);
358 return;
359 }
360 // Load the pexe file and get the translation started.
361 pp::CompletionCallback cb =
362 callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate);
363
364 if (!plugin_->StreamAsFile(pexe_url_, cb.pp_completion_callback())) {
365 ReportNonPpapiError(nacl::string("failed to download ") + pexe_url_ + "\n");
366 }
367 }
368
369 void PnaclCoordinator::RunTranslate(int32_t pp_error) {
370 PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%"
371 NACL_PRId32")\n", pp_error));
372 int32_t fd = GetLoadedFileDesc(pp_error, pexe_url_, "pexe");
373 if (fd < 0) {
374 return;
375 }
376 pexe_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY));
377 // It would really be nice if we could create subprocesses from other than
378 // the main thread. Until we can, we create them both up front.
379 // TODO(sehr): allow creation of subrpocesses from other threads.
380 llc_subprocess_ = StartSubprocess(kLlcUrl);
381 if (llc_subprocess_ == NULL) {
382 ReportPpapiError(PP_ERROR_FAILED);
383 return;
384 }
385 ld_subprocess_ = StartSubprocess(kLdUrl);
386 if (ld_subprocess_ == NULL) {
387 ReportPpapiError(PP_ERROR_FAILED);
388 return;
389 }
390 // Invoke llc followed by ld off the main thread. This allows use of
391 // blocking RPCs that would otherwise block the JavaScript main thread.
392 translate_done_cb_ =
393 callback_factory_.NewCallback(&PnaclCoordinator::TranslateFinished);
394 translate_thread_.reset(new NaClThread);
395 if (translate_thread_ == NULL) {
396 ReportNonPpapiError("could not allocate thread struct\n");
397 return;
398 }
399 const int32_t kArbitraryStackSize = 128 * 1024;
400 if (!NaClThreadCreateJoinable(translate_thread_.get(),
401 DoTranslateThread,
402 this,
403 kArbitraryStackSize)) {
404 ReportNonPpapiError("could not create thread\n");
405 }
406 }
407
408 NaClSubprocess* PnaclCoordinator::StartSubprocess(
409 const nacl::string& url_for_nexe) {
410 PLUGIN_PRINTF(("PnaclCoordinator::StartSubprocess (url_for_nexe=%s)\n",
411 url_for_nexe.c_str()));
412 nacl::DescWrapper* wrapper = resources_->WrapperForUrl(url_for_nexe);
413 NaClSubprocessId id = plugin_->LoadHelperNaClModule(wrapper, &error_info_);
414 if (kInvalidNaClSubprocessId == id) {
415 PLUGIN_PRINTF((
416 "PnaclCoordinator::StartSubprocess: invalid subprocess id\n"));
137 return NULL; 417 return NULL;
138 } 418 }
139 llc_subprocess_ = plugin_->nacl_subprocess(llc_id); 419 return plugin_->nacl_subprocess(id);
140 return (llc_subprocess_ != NULL); 420 }
141 } 421
142 422 // TODO(sehr): the thread body should be in a class by itself with a delegate
143 bool PnaclCoordinator::StartLdSubProcess() { 423 // class for interfacing with the rest of the coordinator.
144 ErrorInfo error_info; 424 void WINAPI PnaclCoordinator::DoTranslateThread(void* arg) {
145 nacl::DescWrapper* wrapper = resources_->WrapperForUrl(ld_url_); 425 PnaclCoordinator* coordinator = reinterpret_cast<PnaclCoordinator*>(arg);
146 NaClSubprocessId ld_id = plugin_->LoadHelperNaClModule(wrapper, &error_info); 426 Plugin* plugin = coordinator->plugin_;
147 PLUGIN_PRINTF(("PnaclCoordinator::StartLdSubProcess (nexe_id=%" 427 BrowserInterface* browser_interface = plugin->browser_interface();
148 NACL_PRId32")\n", ld_id)); 428
149 if (kInvalidNaClSubprocessId == ld_id) { 429 // Run LLC.
150 error_info.SetReport(ERROR_UNKNOWN, "Could not load pnacl linker nexe"); 430 SrpcParams params;
151 ReportLoadError(error_info); 431 nacl::DescWrapper* llc_out_file = coordinator->obj_file_->write_wrapper();
152 PnaclNonPpapiError(); 432 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface,
153 return NULL; 433 coordinator->llc_subprocess_,
154 } 434 "RunWithDefaultCommandLine",
155 ld_subprocess_ = plugin_->nacl_subprocess(ld_id); 435 "hh",
156 return (ld_subprocess_ != NULL); 436 &params,
437 coordinator->pexe_wrapper_->desc(),
438 llc_out_file->desc())) {
439 coordinator->TranslateFailed("compile failed.");
440 }
441 // LLC returns values that are used to determine how linking is done.
442 int is_shared_library = (params.outs()[0]->u.ival != 0);
443 nacl::string soname = params.outs()[1]->arrays.str;
444 nacl::string lib_dependencies = params.outs()[2]->arrays.str;
445 PLUGIN_PRINTF(("PnaclCoordinator: compile (coordinator=%p) succeeded"
446 " is_shared_library=%d, soname='%s', lib_dependencies='%s')\n",
447 arg, is_shared_library, soname.c_str(),
448 lib_dependencies.c_str()));
449 if (coordinator->SubprocessesShouldDie()) {
450 PLUGIN_PRINTF((
451 "PnaclCoordinator::DoTranslateThread: killed by coordinator.\n"));
452 NaClThreadExit(1);
453 }
454 // Set up the lookup service for filename to handle resolution.
455 NaClSrpcService* service =
456 reinterpret_cast<NaClSrpcService*>(calloc(1, sizeof(*service)));
457 if (NULL == service) {
458 coordinator->TranslateFailed("lookup service alloc failed.");
459 }
460 if (!NaClSrpcServiceHandlerCtor(service, lookup_methods)) {
461 free(service);
462 coordinator->TranslateFailed("lookup service constructor failed.");
463 }
464 char* service_string = const_cast<char*>(service->service_string);
465 NaClSubprocess* ld_subprocess = coordinator->ld_subprocess_;
466 ld_subprocess->srpc_client()->AttachService(service, coordinator);
467 nacl::DescWrapper* ld_out_file = coordinator->nexe_file_->write_wrapper();
468 if (!PnaclSrpcLib::InvokeSrpcMethod(browser_interface,
469 ld_subprocess,
470 "RunWithDefaultCommandLine",
471 "ChiCC",
472 &params,
473 service_string,
474 ld_out_file->desc(),
475 is_shared_library,
476 soname.c_str(),
477 lib_dependencies.c_str())) {
478 coordinator->TranslateFailed("link failed.");
479 }
480 PLUGIN_PRINTF(("PnaclCoordinator: link (coordinator=%p) succeeded\n", arg));
481 if (coordinator->SubprocessesShouldDie()) {
482 PLUGIN_PRINTF((
483 "PnaclCoordinator::DoTranslateThread: killed by coordinator.\n"));
484 NaClThreadExit(1);
485 }
486 pp::Core* core = pp::Module::Get()->core();
487 core->CallOnMainThread(0, coordinator->translate_done_cb_, PP_OK);
488 NaClThreadExit(0);
157 } 489 }
158 490
159 bool PnaclCoordinator::SubprocessesShouldDie() { 491 bool PnaclCoordinator::SubprocessesShouldDie() {
160 nacl::MutexLocker ml(&subprocess_mu_); 492 nacl::MutexLocker ml(&subprocess_mu_);
161 return subprocesses_should_die_; 493 return subprocesses_should_die_;
162 } 494 }
163 495
164 void PnaclCoordinator::SetSubprocessesShouldDie(bool subprocesses_should_die) { 496 void PnaclCoordinator::SetSubprocessesShouldDie(bool subprocesses_should_die) {
165 nacl::MutexLocker ml(&subprocess_mu_); 497 nacl::MutexLocker ml(&subprocess_mu_);
166 subprocesses_should_die_ = subprocesses_should_die; 498 subprocesses_should_die_ = subprocesses_should_die;
167 } 499 }
168 500
169 ////////////////////////////////////////////////////////////////////// 501 void PnaclCoordinator::LoadOneFile(int32_t pp_error,
170 // First few callbacks. 502 const nacl::string& url,
171 503 nacl::DescWrapper** wrapper,
172 ////////////////////////////////////////////////////////////////////// 504 pp::CompletionCallback& done_cb) {
173 505 PLUGIN_PRINTF(("PnaclCoordinator::LoadOneFile (pp_error=%"
174 namespace { 506 NACL_PRId32", url=%s)\n", pp_error, url.c_str()));
175 void AbortTranslateThread(PnaclTranslationUnit* translation_unit, 507 const nacl::string& full_url = resource_base_url_ + url;
176 const nacl::string& error_string) { 508 pp::CompletionCallback callback =
509 callback_factory_.NewCallback(&PnaclCoordinator::DidLoadFile,
510 full_url,
511 wrapper,
512 done_cb);
513 if (!plugin_->StreamAsFile(full_url, callback.pp_completion_callback())) {
514 ReportNonPpapiError(nacl::string("failed to load ") + url + "\n");
515 }
516 }
517
518 void PnaclCoordinator::DidLoadFile(int32_t pp_error,
519 const nacl::string& full_url,
520 nacl::DescWrapper** wrapper,
521 pp::CompletionCallback& done_cb) {
522 PLUGIN_PRINTF(("PnaclCoordinator::DidLoadFile (pp_error=%"
523 NACL_PRId32", url=%s)\n", pp_error, full_url.c_str()));
524 int32_t fd = GetLoadedFileDesc(pp_error, full_url, "resource");
525 if (fd < 0) {
526 PLUGIN_PRINTF((
527 "PnaclCoordinator::DidLoadFile: GetLoadedFileDesc returned bad fd.\n"));
528 return;
529 }
530 *wrapper = plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY);
531 done_cb.Run(PP_OK);
532 }
533
534 void PnaclCoordinator::ResumeLookup(int32_t pp_error) {
535 PLUGIN_PRINTF(("PnaclCoordinator::ResumeLookup (pp_error=%"
536 NACL_PRId32", url=%s)\n", pp_error));
537 UNREFERENCED_PARAMETER(pp_error);
538 nacl::MutexLocker ml(&lookup_service_mu_);
539 lookup_is_complete_ = true;
540 NaClXCondVarBroadcast(&lookup_service_cv_);
541 }
542
543 // Lookup service called by translator nexes.
544 // TODO(sehr): replace this lookup by ReverseService.
545 void PnaclCoordinator::LookupInputFile(NaClSrpcRpc* rpc,
546 NaClSrpcArg** inputs,
547 NaClSrpcArg** outputs,
548 NaClSrpcClosure* done) {
549 PLUGIN_PRINTF(("PnaclCoordinator::LookupInputFile (url=%s)\n",
550 inputs[0]->arrays.str));
551 NaClSrpcClosureRunner runner(done);
552 rpc->result = NACL_SRPC_RESULT_APP_ERROR;
553 const char* file_name = inputs[0]->arrays.str;
554 PnaclCoordinator* coordinator = reinterpret_cast<PnaclCoordinator*>(
555 rpc->channel->server_instance_data);
556 outputs[0]->u.hval = coordinator->LookupDesc(file_name);
557 rpc->result = NACL_SRPC_RESULT_OK;
558 }
559
560 NaClSrpcHandlerDesc PnaclCoordinator::lookup_methods[] = {
561 { "LookupInputFile:s:h", LookupInputFile },
562 { NULL, NULL }
563 };
564
565 struct NaClDesc* PnaclCoordinator::LookupDesc(const nacl::string& url) {
566 PLUGIN_PRINTF(("PnaclCoordinator::LookupDesc (url=%s)\n", url.c_str()));
567 // This filename is part of the contract with the linker. It is a
568 // fake filename for the object file generated by llc and consumed by ld.
569 // TODO(sehr): Pass the FD in, and move lookup for this file to the linker.
570 const nacl::string kGeneratedObjectFileName = "___PNACL_GENERATED";
571 if (url == kGeneratedObjectFileName) {
572 return obj_file_->read_wrapper()->desc();
573 }
574 nacl::DescWrapper* wrapper;
575 // Create the callback used to report when lookup is done.
576 pp::CompletionCallback resume_cb =
577 callback_factory_.NewCallback(&PnaclCoordinator::ResumeLookup);
578 // Run the lookup request on the main thread.
579 lookup_is_complete_ = false;
580 pp::CompletionCallback load_cb =
581 callback_factory_.NewCallback(&PnaclCoordinator::LoadOneFile,
582 url, &wrapper, resume_cb);
177 pp::Core* core = pp::Module::Get()->core(); 583 pp::Core* core = pp::Module::Get()->core();
178 translation_unit->error_info.SetReport(ERROR_UNKNOWN, error_string); 584 core->CallOnMainThread(0, load_cb, PP_OK);
179 core->CallOnMainThread(0, translation_unit->translate_done_cb, 585 // Wait for completion (timeout every 10ms to check for process end).
180 PP_ERROR_FAILED); 586 const int32_t kTenMilliseconds = 10 * 1000 * 1000;
181 NaClThreadExit(1); 587 NACL_TIMESPEC_T reltime;
182 } 588 reltime.tv_sec = 0;
183 589 reltime.tv_nsec = kTenMilliseconds;
184 void WINAPI DoTranslateThread(void* arg) { 590 NaClXMutexLock(&lookup_service_mu_);
185 PnaclTranslationUnit* p = reinterpret_cast<PnaclTranslationUnit*>(arg); 591 while (!lookup_is_complete_) {
186 PnaclCoordinator* coordinator = p->coordinator; 592 // Check for termination.
187 NaClSubprocess* llc_subprocess = coordinator->llc_subprocess(); 593 if (SubprocessesShouldDie()) {
188 Plugin* plugin = coordinator->plugin(); 594 NaClXMutexUnlock(&lookup_service_mu_);
189 BrowserInterface* browser = plugin->browser_interface(); 595 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 } 596 }
244 SrpcParams dummy_params; 597 NaClXCondVarTimedWaitRelative(&lookup_service_cv_,
245 if (!PnaclSrpcLib::InvokeSrpcMethod(browser, 598 &lookup_service_mu_,
246 llc_subprocess, 599 &reltime);
247 "AddArg", 600 }
248 "C", 601 NaClXMutexUnlock(&lookup_service_mu_);
249 &dummy_params, 602 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 &params,
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 &params)) {
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 } 603 }
637 604
638 } // namespace plugin 605 } // namespace plugin
OLDNEW
« no previous file with comments | « ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h ('k') | ppapi/native_client/src/trusted/plugin/pnacl_resources.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698