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