Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Ben Murdoch | ca12bfa | 2013-07-23 11:17:05 +0100 | [diff] [blame] | 5 | #include "ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 6 | |
| 7 | #include <utility> |
| 8 | #include <vector> |
| 9 | |
| 10 | #include "native_client/src/include/checked_cast.h" |
| 11 | #include "native_client/src/include/portability_io.h" |
| 12 | #include "native_client/src/shared/platform/nacl_check.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 13 | #include "native_client/src/trusted/service_runtime/include/sys/stat.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 14 | |
| 15 | #include "ppapi/c/pp_bool.h" |
| 16 | #include "ppapi/c/pp_errors.h" |
| 17 | #include "ppapi/c/ppb_file_io.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 18 | #include "ppapi/c/private/ppb_uma_private.h" |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 19 | #include "ppapi/cpp/file_io.h" |
| 20 | |
Ben Murdoch | ca12bfa | 2013-07-23 11:17:05 +0100 | [diff] [blame] | 21 | #include "ppapi/native_client/src/trusted/plugin/local_temp_file.h" |
| 22 | #include "ppapi/native_client/src/trusted/plugin/manifest.h" |
| 23 | #include "ppapi/native_client/src/trusted/plugin/nacl_http_response_headers.h" |
| 24 | #include "ppapi/native_client/src/trusted/plugin/plugin.h" |
| 25 | #include "ppapi/native_client/src/trusted/plugin/plugin_error.h" |
| 26 | #include "ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h" |
| 27 | #include "ppapi/native_client/src/trusted/plugin/service_runtime.h" |
| 28 | #include "ppapi/native_client/src/trusted/plugin/temporary_file.h" |
| 29 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 30 | namespace { |
| 31 | const char kPnaclTempDir[] = "/.pnacl"; |
| 32 | const uint32_t kCopyBufSize = 512 << 10; |
| 33 | } |
| 34 | |
| 35 | namespace plugin { |
| 36 | |
| 37 | ////////////////////////////////////////////////////////////////////// |
| 38 | // Pnacl-specific manifest support. |
| 39 | ////////////////////////////////////////////////////////////////////// |
| 40 | |
Torne (Richard Coles) | a93a17c | 2013-05-15 11:34:50 +0100 | [diff] [blame] | 41 | // The PNaCl linker gets file descriptors via the service runtime's |
| 42 | // reverse service lookup. The reverse service lookup requires a manifest. |
| 43 | // Normally, that manifest is an NMF containing mappings for shared libraries. |
| 44 | // Here, we provide a manifest that redirects to PNaCl component files |
| 45 | // that are part of Chrome. |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 46 | class PnaclManifest : public Manifest { |
| 47 | public: |
Torne (Richard Coles) | a93a17c | 2013-05-15 11:34:50 +0100 | [diff] [blame] | 48 | PnaclManifest() : manifest_base_url_(PnaclUrls::GetBaseUrl()) { } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 49 | virtual ~PnaclManifest() { } |
| 50 | |
| 51 | virtual bool GetProgramURL(nacl::string* full_url, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 52 | PnaclOptions* pnacl_options, |
| 53 | ErrorInfo* error_info) const { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 54 | // Does not contain program urls. |
| 55 | UNREFERENCED_PARAMETER(full_url); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 56 | UNREFERENCED_PARAMETER(pnacl_options); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 57 | UNREFERENCED_PARAMETER(error_info); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 58 | PLUGIN_PRINTF(("PnaclManifest does not contain a program\n")); |
| 59 | error_info->SetReport(ERROR_MANIFEST_GET_NEXE_URL, |
| 60 | "pnacl manifest does not contain a program."); |
| 61 | return false; |
| 62 | } |
| 63 | |
| 64 | virtual bool ResolveURL(const nacl::string& relative_url, |
| 65 | nacl::string* full_url, |
| 66 | ErrorInfo* error_info) const { |
| 67 | // Does not do general URL resolution, simply appends relative_url to |
| 68 | // the end of manifest_base_url_. |
| 69 | UNREFERENCED_PARAMETER(error_info); |
| 70 | *full_url = manifest_base_url_ + relative_url; |
| 71 | return true; |
| 72 | } |
| 73 | |
| 74 | virtual bool GetFileKeys(std::set<nacl::string>* keys) const { |
| 75 | // Does not support enumeration. |
| 76 | PLUGIN_PRINTF(("PnaclManifest does not support key enumeration\n")); |
| 77 | UNREFERENCED_PARAMETER(keys); |
| 78 | return false; |
| 79 | } |
| 80 | |
| 81 | virtual bool ResolveKey(const nacl::string& key, |
| 82 | nacl::string* full_url, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 83 | PnaclOptions* pnacl_options, |
| 84 | ErrorInfo* error_info) const { |
Torne (Richard Coles) | a93a17c | 2013-05-15 11:34:50 +0100 | [diff] [blame] | 85 | // All of the component files are native (do not require pnacl translate). |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 86 | pnacl_options->set_translate(false); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 87 | // We can only resolve keys in the files/ namespace. |
| 88 | const nacl::string kFilesPrefix = "files/"; |
| 89 | size_t files_prefix_pos = key.find(kFilesPrefix); |
| 90 | if (files_prefix_pos == nacl::string::npos) { |
| 91 | error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 92 | "key did not start with files/"); |
| 93 | return false; |
| 94 | } |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 95 | // Resolve the full URL to the file. Provide it with a platform-specific |
| 96 | // prefix. |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 97 | nacl::string key_basename = key.substr(kFilesPrefix.length()); |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 98 | return ResolveURL(PnaclUrls::PrependPlatformPrefix(key_basename), |
| 99 | full_url, error_info); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | private: |
| 103 | NACL_DISALLOW_COPY_AND_ASSIGN(PnaclManifest); |
| 104 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 105 | nacl::string manifest_base_url_; |
| 106 | }; |
| 107 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 108 | ////////////////////////////////////////////////////////////////////// |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 109 | // UMA stat helpers. |
| 110 | ////////////////////////////////////////////////////////////////////// |
| 111 | |
| 112 | namespace { |
| 113 | |
| 114 | // Assume translation time metrics *can be* large. |
| 115 | // Up to 12 minutes. |
| 116 | const int64_t kTimeLargeMin = 10; // in ms |
| 117 | const int64_t kTimeLargeMax = 720000; // in ms |
| 118 | const uint32_t kTimeLargeBuckets = 100; |
| 119 | |
| 120 | const int32_t kSizeKBMin = 1; |
| 121 | const int32_t kSizeKBMax = 512*1024; // very large .pexe / .nexe. |
| 122 | const uint32_t kSizeKBBuckets = 100; |
| 123 | |
| 124 | const int32_t kRatioMin = 10; |
| 125 | const int32_t kRatioMax = 10*100; // max of 10x difference. |
| 126 | const uint32_t kRatioBuckets = 100; |
| 127 | |
| 128 | const int32_t kKBPSMin = 1; |
| 129 | const int32_t kKBPSMax = 30*1000; // max of 30 MB / sec. |
| 130 | const uint32_t kKBPSBuckets = 100; |
| 131 | |
| 132 | const PPB_UMA_Private* uma_interface = NULL; |
| 133 | |
| 134 | const PPB_UMA_Private* GetUMAInterface() { |
| 135 | if (uma_interface != NULL) { |
| 136 | return uma_interface; |
| 137 | } |
| 138 | pp::Module *module = pp::Module::Get(); |
| 139 | DCHECK(module); |
| 140 | uma_interface = static_cast<const PPB_UMA_Private*>( |
| 141 | module->GetBrowserInterface(PPB_UMA_PRIVATE_INTERFACE)); |
| 142 | return uma_interface; |
| 143 | } |
| 144 | |
| 145 | void HistogramTime(const std::string& name, int64_t ms) { |
| 146 | if (ms < 0) return; |
| 147 | |
| 148 | const PPB_UMA_Private* ptr = GetUMAInterface(); |
| 149 | if (ptr == NULL) return; |
| 150 | |
| 151 | ptr->HistogramCustomTimes(pp::Var(name).pp_var(), |
| 152 | ms, |
| 153 | kTimeLargeMin, kTimeLargeMax, |
| 154 | kTimeLargeBuckets); |
| 155 | } |
| 156 | |
| 157 | void HistogramSizeKB(const std::string& name, int32_t kb) { |
| 158 | if (kb < 0) return; |
| 159 | |
| 160 | const PPB_UMA_Private* ptr = GetUMAInterface(); |
| 161 | if (ptr == NULL) return; |
| 162 | |
| 163 | ptr->HistogramCustomCounts(pp::Var(name).pp_var(), |
| 164 | kb, |
| 165 | kSizeKBMin, kSizeKBMax, |
| 166 | kSizeKBBuckets); |
| 167 | } |
| 168 | |
| 169 | void HistogramRatio(const std::string& name, int64_t a, int64_t b) { |
| 170 | if (a < 0 || b <= 0) return; |
| 171 | |
| 172 | const PPB_UMA_Private* ptr = GetUMAInterface(); |
| 173 | if (ptr == NULL) return; |
| 174 | |
| 175 | ptr->HistogramCustomCounts(pp::Var(name).pp_var(), |
| 176 | 100 * a / b, |
| 177 | kRatioMin, kRatioMax, |
| 178 | kRatioBuckets); |
| 179 | } |
| 180 | |
| 181 | void HistogramKBPerSec(const std::string& name, double kb, double s) { |
| 182 | if (kb < 0.0 || s <= 0.0) return; |
| 183 | |
| 184 | const PPB_UMA_Private* ptr = GetUMAInterface(); |
| 185 | if (ptr == NULL) return; |
| 186 | |
| 187 | ptr->HistogramCustomCounts(pp::Var(name).pp_var(), |
| 188 | static_cast<int64_t>(kb / s), |
| 189 | kKBPSMin, kKBPSMax, |
| 190 | kKBPSBuckets); |
| 191 | } |
| 192 | |
| 193 | void HistogramEnumerateTranslationCache(bool hit) { |
| 194 | const PPB_UMA_Private* ptr = GetUMAInterface(); |
| 195 | if (ptr == NULL) return; |
| 196 | ptr->HistogramEnumeration(pp::Var("NaCl.Perf.PNaClCache.IsHit").pp_var(), |
| 197 | hit, 2); |
| 198 | } |
| 199 | |
| 200 | // Opt level is expected to be 0 to 3. Treating 4 as unknown. |
| 201 | const int8_t kOptUnknown = 4; |
| 202 | |
| 203 | void HistogramOptLevel(int8_t opt_level) { |
| 204 | const PPB_UMA_Private* ptr = GetUMAInterface(); |
| 205 | if (ptr == NULL) return; |
| 206 | if (opt_level < 0 || opt_level > 3) { |
| 207 | opt_level = kOptUnknown; |
| 208 | } |
| 209 | ptr->HistogramEnumeration(pp::Var("NaCl.Options.PNaCl.OptLevel").pp_var(), |
| 210 | opt_level, kOptUnknown+1); |
| 211 | } |
| 212 | |
| 213 | } // namespace |
| 214 | |
| 215 | |
| 216 | ////////////////////////////////////////////////////////////////////// |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 217 | // The coordinator class. |
| 218 | ////////////////////////////////////////////////////////////////////// |
| 219 | |
| 220 | // Out-of-line destructor to keep it from getting put in every .o where |
| 221 | // callback_source.h is included |
| 222 | template<> |
| 223 | CallbackSource<FileStreamData>::~CallbackSource() {} |
| 224 | |
| 225 | PnaclCoordinator* PnaclCoordinator::BitcodeToNative( |
| 226 | Plugin* plugin, |
| 227 | const nacl::string& pexe_url, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 228 | const PnaclOptions& pnacl_options, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 229 | const pp::CompletionCallback& translate_notify_callback) { |
| 230 | PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (plugin=%p, pexe=%s)\n", |
| 231 | static_cast<void*>(plugin), pexe_url.c_str())); |
| 232 | PnaclCoordinator* coordinator = |
| 233 | new PnaclCoordinator(plugin, pexe_url, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 234 | pnacl_options, |
| 235 | translate_notify_callback); |
| 236 | coordinator->pnacl_init_time_ = NaClGetTimeOfDayMicroseconds(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 237 | coordinator->off_the_record_ = |
| 238 | plugin->nacl_interface()->IsOffTheRecord(); |
| 239 | PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (manifest=%p, " |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 240 | "off_the_record=%d)\n", |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 241 | reinterpret_cast<const void*>(coordinator->manifest_.get()), |
| 242 | coordinator->off_the_record_)); |
| 243 | |
Ben Murdoch | 2385ea3 | 2013-08-06 11:01:04 +0100 | [diff] [blame] | 244 | // First check that PNaCl is installed. |
| 245 | pp::CompletionCallback pnacl_installed_cb = |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 246 | coordinator->callback_factory_.NewCallback( |
Ben Murdoch | 2385ea3 | 2013-08-06 11:01:04 +0100 | [diff] [blame] | 247 | &PnaclCoordinator::DidCheckPnaclInstalled); |
| 248 | plugin->nacl_interface()->EnsurePnaclInstalled( |
| 249 | plugin->pp_instance(), |
| 250 | pnacl_installed_cb.pp_completion_callback()); |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 251 | return coordinator; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | PnaclCoordinator::PnaclCoordinator( |
| 255 | Plugin* plugin, |
| 256 | const nacl::string& pexe_url, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 257 | const PnaclOptions& pnacl_options, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 258 | const pp::CompletionCallback& translate_notify_callback) |
| 259 | : translate_finish_error_(PP_OK), |
| 260 | plugin_(plugin), |
| 261 | translate_notify_callback_(translate_notify_callback), |
| 262 | file_system_(new pp::FileSystem(plugin, PP_FILESYSTEMTYPE_LOCALTEMPORARY)), |
Torne (Richard Coles) | a93a17c | 2013-05-15 11:34:50 +0100 | [diff] [blame] | 263 | manifest_(new PnaclManifest()), |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 264 | pexe_url_(pexe_url), |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 265 | pnacl_options_(pnacl_options), |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 266 | use_new_cache_(false), |
| 267 | is_cache_hit_(PP_FALSE), |
| 268 | nexe_handle_(PP_kInvalidFileHandle), |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 269 | error_already_reported_(false), |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 270 | off_the_record_(false), |
| 271 | pnacl_init_time_(0), |
| 272 | pexe_size_(0), |
| 273 | pexe_bytes_compiled_(0), |
| 274 | expected_pexe_size_(-1) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 275 | PLUGIN_PRINTF(("PnaclCoordinator::PnaclCoordinator (this=%p, plugin=%p)\n", |
| 276 | static_cast<void*>(this), static_cast<void*>(plugin))); |
| 277 | callback_factory_.Initialize(this); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 278 | if (getenv("PNACL_USE_NEW_CACHE")) { |
| 279 | PLUGIN_PRINTF(("PnaclCoordinator using new translation cache\n")); |
| 280 | use_new_cache_ = true; |
| 281 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 282 | } |
| 283 | |
| 284 | PnaclCoordinator::~PnaclCoordinator() { |
| 285 | PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p, " |
| 286 | "translate_thread=%p\n", |
| 287 | static_cast<void*>(this), translate_thread_.get())); |
| 288 | // Stopping the translate thread will cause the translate thread to try to |
| 289 | // run translation_complete_callback_ on the main thread. This destructor is |
| 290 | // running from the main thread, and by the time it exits, callback_factory_ |
| 291 | // will have been destroyed. This will result in the cancellation of |
| 292 | // translation_complete_callback_, so no notification will be delivered. |
| 293 | if (translate_thread_.get() != NULL) { |
| 294 | translate_thread_->AbortSubprocesses(); |
| 295 | } |
| 296 | } |
| 297 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 298 | void PnaclCoordinator::ReportNonPpapiError(enum PluginErrorCode err_code, |
| 299 | const nacl::string& message) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 300 | error_info_.SetReport(err_code, message); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 301 | ExitWithError(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 302 | } |
| 303 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 304 | void PnaclCoordinator::ReportPpapiError(enum PluginErrorCode err_code, |
| 305 | int32_t pp_error, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 306 | const nacl::string& message) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 307 | nacl::stringstream ss; |
| 308 | ss << "PnaclCoordinator: " << message << " (pp_error=" << pp_error << ")."; |
| 309 | error_info_.SetReport(err_code, ss.str()); |
| 310 | ExitWithError(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 311 | } |
| 312 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 313 | void PnaclCoordinator::ExitWithError() { |
| 314 | PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError (error_code=%d, " |
| 315 | "message='%s')\n", |
| 316 | error_info_.error_code(), |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 317 | error_info_.message().c_str())); |
| 318 | plugin_->ReportLoadError(error_info_); |
| 319 | // Free all the intermediate callbacks we ever created. |
| 320 | // Note: this doesn't *cancel* the callbacks from the factories attached |
| 321 | // to the various helper classes (e.g., pnacl_resources). Thus, those |
| 322 | // callbacks may still run asynchronously. We let those run but ignore |
| 323 | // any other errors they may generate so that they do not end up running |
| 324 | // translate_notify_callback_, which has already been freed. |
| 325 | callback_factory_.CancelAll(); |
| 326 | if (!error_already_reported_) { |
| 327 | error_already_reported_ = true; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 328 | translate_notify_callback_.Run(PP_ERROR_FAILED); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 329 | } else { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 330 | PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError an earlier error was " |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 331 | "already reported -- Skipping.\n")); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | // Signal that Pnacl translation completed normally. |
| 336 | void PnaclCoordinator::TranslateFinished(int32_t pp_error) { |
| 337 | PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 338 | NACL_PRId32 ")\n", pp_error)); |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 339 | // Bail out if there was an earlier error (e.g., pexe load failure), |
| 340 | // or if there is an error from the translation thread. |
| 341 | if (translate_finish_error_ != PP_OK || pp_error != PP_OK) { |
| 342 | if (use_new_cache_) { |
| 343 | plugin_->nacl_interface()->ReportTranslationFinished( |
| 344 | plugin_->pp_instance(), |
| 345 | PP_FALSE); |
| 346 | } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 347 | ExitWithError(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 348 | return; |
| 349 | } |
Torne (Richard Coles) | a93a17c | 2013-05-15 11:34:50 +0100 | [diff] [blame] | 350 | // Send out one last progress event, to finish up the progress events |
| 351 | // that were delayed (see the delay inserted in BitcodeGotCompiled). |
| 352 | if (ExpectedProgressKnown()) { |
| 353 | pexe_bytes_compiled_ = expected_pexe_size_; |
| 354 | plugin_->EnqueueProgressEvent(plugin::Plugin::kProgressEventProgress, |
| 355 | pexe_url_, |
| 356 | plugin::Plugin::LENGTH_IS_COMPUTABLE, |
| 357 | pexe_bytes_compiled_, |
| 358 | expected_pexe_size_); |
| 359 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 360 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 361 | // If there are no errors, report stats from this thread (the main thread). |
| 362 | HistogramOptLevel(pnacl_options_.opt_level()); |
| 363 | const plugin::PnaclTimeStats& time_stats = translate_thread_->GetTimeStats(); |
| 364 | HistogramTime("NaCl.Perf.PNaClLoadTime.LoadCompiler", |
| 365 | time_stats.pnacl_llc_load_time / NACL_MICROS_PER_MILLI); |
| 366 | HistogramTime("NaCl.Perf.PNaClLoadTime.CompileTime", |
| 367 | time_stats.pnacl_compile_time / NACL_MICROS_PER_MILLI); |
| 368 | HistogramKBPerSec("NaCl.Perf.PNaClLoadTime.CompileKBPerSec", |
| 369 | pexe_size_ / 1024.0, |
| 370 | time_stats.pnacl_compile_time / 1000000.0); |
| 371 | HistogramTime("NaCl.Perf.PNaClLoadTime.LoadLinker", |
| 372 | time_stats.pnacl_ld_load_time / NACL_MICROS_PER_MILLI); |
| 373 | HistogramTime("NaCl.Perf.PNaClLoadTime.LinkTime", |
| 374 | time_stats.pnacl_link_time / NACL_MICROS_PER_MILLI); |
| 375 | HistogramSizeKB("NaCl.Perf.Size.Pexe", |
| 376 | static_cast<int64_t>(pexe_size_ / 1024)); |
| 377 | |
| 378 | struct nacl_abi_stat stbuf; |
| 379 | struct NaClDesc* desc = temp_nexe_file_->read_wrapper()->desc(); |
| 380 | int stat_ret; |
| 381 | if (0 != (stat_ret = (*((struct NaClDescVtbl const *) desc->base.vtbl)-> |
| 382 | Fstat)(desc, &stbuf))) { |
| 383 | PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished can't stat nexe.\n")); |
| 384 | } else { |
| 385 | size_t nexe_size = stbuf.nacl_abi_st_size; |
| 386 | HistogramSizeKB("NaCl.Perf.Size.PNaClTranslatedNexe", |
| 387 | static_cast<int64_t>(nexe_size / 1024)); |
| 388 | HistogramRatio("NaCl.Perf.Size.PexeNexeSizePct", pexe_size_, nexe_size); |
| 389 | } |
| 390 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 391 | // The nexe is written to the temp_nexe_file_. We must Reset() the file |
| 392 | // pointer to be able to read it again from the beginning. |
| 393 | temp_nexe_file_->Reset(); |
| 394 | |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 395 | if (use_new_cache_) { |
| 396 | // Report to the browser that translation finished. The browser will take |
| 397 | // care of caching. |
| 398 | plugin_->nacl_interface()->ReportTranslationFinished( |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 399 | plugin_->pp_instance(), PP_TRUE); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 400 | NexeReadDidOpen(PP_OK); |
| 401 | return; |
| 402 | } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 403 | if (pnacl_options_.HasCacheKey() && cached_nexe_file_ != NULL) { |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 404 | // We are using a cache, but had a cache miss, which is why we did the |
| 405 | // translation. Reset cached_nexe_file_ to have a random name, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 406 | // for scratch purposes, before renaming to the final cache_identity. |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 407 | cached_nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), |
| 408 | nacl::string(kPnaclTempDir))); |
| 409 | pp::CompletionCallback cb = callback_factory_.NewCallback( |
| 410 | &PnaclCoordinator::CachedNexeOpenedForWrite); |
| 411 | cached_nexe_file_->OpenWrite(cb); |
| 412 | } else { |
| 413 | // For now, tolerate bitcode that is missing a cache identity, and |
| 414 | // tolerate the lack of caching in incognito mode. |
| 415 | PLUGIN_PRINTF(("PnaclCoordinator -- not caching.\n")); |
| 416 | NexeReadDidOpen(PP_OK); |
| 417 | } |
| 418 | } |
| 419 | |
| 420 | void PnaclCoordinator::CachedNexeOpenedForWrite(int32_t pp_error) { |
| 421 | if (pp_error != PP_OK) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 422 | if (pp_error == PP_ERROR_NOACCESS) { |
| 423 | ReportPpapiError( |
| 424 | ERROR_PNACL_CACHE_FILEOPEN_NOACCESS, |
| 425 | pp_error, |
| 426 | "PNaCl translation cache failed to open file for write " |
| 427 | "(no access)."); |
| 428 | return; |
| 429 | } |
| 430 | if (pp_error == PP_ERROR_NOQUOTA) { |
| 431 | ReportPpapiError( |
| 432 | ERROR_PNACL_CACHE_FILEOPEN_NOQUOTA, |
| 433 | pp_error, |
| 434 | "PNaCl translation cache failed to open file for write " |
| 435 | "(no quota)."); |
| 436 | return; |
| 437 | } |
| 438 | if (pp_error == PP_ERROR_NOSPACE) { |
| 439 | ReportPpapiError( |
| 440 | ERROR_PNACL_CACHE_FILEOPEN_NOSPACE, |
| 441 | pp_error, |
| 442 | "PNaCl translation cache failed to open file for write " |
| 443 | "(no space)."); |
| 444 | return; |
| 445 | } |
| 446 | if (pp_error == PP_ERROR_NOTAFILE) { |
| 447 | ReportPpapiError(ERROR_PNACL_CACHE_FILEOPEN_NOTAFILE, |
| 448 | pp_error, |
| 449 | "PNaCl translation cache failed to open file for write." |
| 450 | " File already exists as a directory."); |
| 451 | return; |
| 452 | } |
| 453 | ReportPpapiError(ERROR_PNACL_CACHE_FILEOPEN_OTHER, |
| 454 | pp_error, |
| 455 | "PNaCl translation cache failed to open file for write."); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 456 | return; |
| 457 | } |
| 458 | |
| 459 | // Copy the contents from temp_nexe_file_ -> cached_nexe_file_, |
| 460 | // then rename the cached_nexe_file_ file to the cache id. |
| 461 | int64_t cur_offset = 0; |
| 462 | nacl::DescWrapper* read_wrapper = temp_nexe_file_->read_wrapper(); |
| 463 | char buf[kCopyBufSize]; |
| 464 | int32_t num_read = |
| 465 | nacl::assert_cast<int32_t>(read_wrapper->Read(buf, sizeof buf)); |
| 466 | // Hit EOF or something. |
| 467 | if (num_read == 0) { |
| 468 | NexeWasCopiedToCache(PP_OK); |
| 469 | return; |
| 470 | } |
| 471 | if (num_read < 0) { |
| 472 | PLUGIN_PRINTF(("PnaclCoordinator::CachedNexeOpenedForWrite read failed " |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 473 | "(error=%" NACL_PRId32 ")\n", num_read)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 474 | NexeWasCopiedToCache(PP_ERROR_FAILED); |
| 475 | return; |
| 476 | } |
| 477 | pp::CompletionCallback cb = callback_factory_.NewCallback( |
| 478 | &PnaclCoordinator::DidCopyNexeToCachePartial, num_read, cur_offset); |
| 479 | cached_nexe_file_->write_file_io()->Write(cur_offset, buf, num_read, cb); |
| 480 | } |
| 481 | |
| 482 | void PnaclCoordinator::DidCopyNexeToCachePartial(int32_t pp_error, |
| 483 | int32_t num_read_prev, |
| 484 | int64_t cur_offset) { |
| 485 | PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial " |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 486 | "(pp_error=%" NACL_PRId32 ", num_read_prev=%" NACL_PRId32 |
| 487 | ", cur_offset=%" NACL_PRId64 ").\n", |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 488 | pp_error, num_read_prev, cur_offset)); |
| 489 | // Assume we are done. |
| 490 | if (pp_error == PP_OK) { |
| 491 | NexeWasCopiedToCache(PP_OK); |
| 492 | return; |
| 493 | } |
| 494 | if (pp_error < PP_OK) { |
| 495 | PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial failed (err=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 496 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 497 | NexeWasCopiedToCache(pp_error); |
| 498 | return; |
| 499 | } |
| 500 | |
| 501 | // Check if we wrote as much as we read. |
| 502 | nacl::DescWrapper* read_wrapper = temp_nexe_file_->read_wrapper(); |
| 503 | if (pp_error != num_read_prev) { |
| 504 | PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial partial " |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 505 | "write (bytes_written=%" NACL_PRId32 " vs " |
| 506 | "read=%" NACL_PRId32 ")\n", pp_error, num_read_prev)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 507 | CHECK(pp_error < num_read_prev); |
| 508 | // Seek back to re-read the bytes that were not written. |
| 509 | nacl_off64_t seek_result = |
| 510 | read_wrapper->Seek(pp_error - num_read_prev, SEEK_CUR); |
| 511 | if (seek_result < 0) { |
| 512 | PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial seek failed " |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 513 | "(err=%" NACL_PRId64 ")\n", seek_result)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 514 | NexeWasCopiedToCache(PP_ERROR_FAILED); |
| 515 | return; |
| 516 | } |
| 517 | } |
| 518 | |
| 519 | int64_t next_offset = cur_offset + pp_error; |
| 520 | char buf[kCopyBufSize]; |
| 521 | int32_t num_read = |
| 522 | nacl::assert_cast<int32_t>(read_wrapper->Read(buf, sizeof buf)); |
| 523 | PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial read (bytes=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 524 | NACL_PRId32 ")\n", num_read)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 525 | // Hit EOF or something. |
| 526 | if (num_read == 0) { |
| 527 | NexeWasCopiedToCache(PP_OK); |
| 528 | return; |
| 529 | } |
| 530 | if (num_read < 0) { |
| 531 | PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial read failed " |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 532 | "(error=%" NACL_PRId32 ")\n", num_read)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 533 | NexeWasCopiedToCache(PP_ERROR_FAILED); |
| 534 | return; |
| 535 | } |
| 536 | pp::CompletionCallback cb = callback_factory_.NewCallback( |
| 537 | &PnaclCoordinator::DidCopyNexeToCachePartial, num_read, next_offset); |
| 538 | PLUGIN_PRINTF(("PnaclCoordinator::CopyNexeToCache Writing (" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 539 | "bytes=%" NACL_PRId32 ", buf=%p, file_io=%p)\n", num_read, buf, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 540 | cached_nexe_file_->write_file_io())); |
| 541 | cached_nexe_file_->write_file_io()->Write(next_offset, buf, num_read, cb); |
| 542 | } |
| 543 | |
| 544 | void PnaclCoordinator::NexeWasCopiedToCache(int32_t pp_error) { |
| 545 | if (pp_error != PP_OK) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 546 | // Try to delete the partially written not-yet-committed cache file before |
| 547 | // returning. We pass the current pp_error along so that it can be reported |
| 548 | // before returning. |
| 549 | pp::CompletionCallback cb = callback_factory_.NewCallback( |
| 550 | &PnaclCoordinator::CorruptCacheFileWasDeleted, pp_error); |
| 551 | cached_nexe_file_->Delete(cb); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 552 | return; |
| 553 | } |
| 554 | // Rename the cached_nexe_file_ file to the cache id, to finalize. |
| 555 | pp::CompletionCallback cb = |
| 556 | callback_factory_.NewCallback(&PnaclCoordinator::NexeFileWasRenamed); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 557 | cached_nexe_file_->Rename(pnacl_options_.GetCacheKey(), cb); |
| 558 | } |
| 559 | |
| 560 | void PnaclCoordinator::CorruptCacheFileWasDeleted(int32_t delete_pp_error, |
| 561 | int32_t orig_pp_error) { |
| 562 | if (delete_pp_error != PP_OK) { |
| 563 | // The cache file was certainly already opened by the time we tried |
| 564 | // to write to it, so it should certainly be deletable. |
| 565 | PLUGIN_PRINTF(("PnaclCoordinator::CorruptCacheFileWasDeleted " |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 566 | "delete failed with pp_error=%" NACL_PRId32 "\n", |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 567 | delete_pp_error)); |
| 568 | // fall through and report the original error. |
| 569 | } |
| 570 | // Report the original error that caused us to consider the |
| 571 | // cache file corrupted. |
| 572 | if (orig_pp_error == PP_ERROR_NOQUOTA) { |
| 573 | ReportPpapiError(ERROR_PNACL_CACHE_FINALIZE_COPY_NOQUOTA, |
| 574 | orig_pp_error, |
| 575 | "Failed to copy translated nexe to cache (no quota)."); |
| 576 | return; |
| 577 | } |
| 578 | if (orig_pp_error == PP_ERROR_NOSPACE) { |
| 579 | ReportPpapiError(ERROR_PNACL_CACHE_FINALIZE_COPY_NOSPACE, |
| 580 | orig_pp_error, |
| 581 | "Failed to copy translated nexe to cache (no space)."); |
| 582 | return; |
| 583 | } |
| 584 | ReportPpapiError(ERROR_PNACL_CACHE_FINALIZE_COPY_OTHER, |
| 585 | orig_pp_error, |
| 586 | "Failed to copy translated nexe to cache."); |
| 587 | return; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 588 | } |
| 589 | |
| 590 | void PnaclCoordinator::NexeFileWasRenamed(int32_t pp_error) { |
| 591 | PLUGIN_PRINTF(("PnaclCoordinator::NexeFileWasRenamed (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 592 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 593 | if (pp_error != PP_OK) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 594 | if (pp_error == PP_ERROR_NOACCESS) { |
| 595 | ReportPpapiError(ERROR_PNACL_CACHE_FINALIZE_RENAME_NOACCESS, |
| 596 | pp_error, |
| 597 | "Failed to finalize cached translation (no access)."); |
| 598 | return; |
| 599 | } else if (pp_error != PP_ERROR_FILEEXISTS) { |
| 600 | ReportPpapiError(ERROR_PNACL_CACHE_FINALIZE_RENAME_OTHER, |
| 601 | pp_error, |
| 602 | "Failed to finalize cached translation."); |
| 603 | return; |
| 604 | } else { // pp_error == PP_ERROR_FILEEXISTS. |
| 605 | // NOTE: if the file already existed, it looks like the rename will |
| 606 | // happily succeed. However, we should add a test for this. |
| 607 | // Could be a hash collision, or it could also be two tabs racing to |
| 608 | // translate the same pexe. We may want UMA stats to know if this happens. |
| 609 | // For now, assume that it is a race and try to continue. |
| 610 | // If there is truly a corrupted file, then sel_ldr should prevent the |
| 611 | // file from loading due to the file size not matching the ELF header. |
| 612 | PLUGIN_PRINTF(("PnaclCoordinator::NexeFileWasRenamed file existed\n")); |
| 613 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 614 | } |
| 615 | |
| 616 | cached_nexe_file_->FinishRename(); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 617 | |
| 618 | int64_t total_time = NaClGetTimeOfDayMicroseconds() - pnacl_init_time_; |
| 619 | HistogramTime("NaCl.Perf.PNaClLoadTime.TotalUncachedTime", |
| 620 | total_time / NACL_MICROS_PER_MILLI); |
| 621 | HistogramKBPerSec("NaCl.Perf.PNaClLoadTime.TotalUncachedKBPerSec", |
| 622 | pexe_size_ / 1024.0, |
| 623 | total_time / 1000000.0); |
| 624 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 625 | // Open the cache file for reading. |
| 626 | pp::CompletionCallback cb = |
| 627 | callback_factory_.NewCallback(&PnaclCoordinator::NexeReadDidOpen); |
| 628 | cached_nexe_file_->OpenRead(cb); |
| 629 | } |
| 630 | |
| 631 | void PnaclCoordinator::NexeReadDidOpen(int32_t pp_error) { |
| 632 | PLUGIN_PRINTF(("PnaclCoordinator::NexeReadDidOpen (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 633 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 634 | if (pp_error != PP_OK) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 635 | if (pp_error == PP_ERROR_FILENOTFOUND) { |
| 636 | ReportPpapiError(ERROR_PNACL_CACHE_FETCH_NOTFOUND, |
| 637 | pp_error, |
| 638 | "Failed to open translated nexe (not found)."); |
| 639 | return; |
| 640 | } |
| 641 | if (pp_error == PP_ERROR_NOACCESS) { |
| 642 | ReportPpapiError(ERROR_PNACL_CACHE_FETCH_NOACCESS, |
| 643 | pp_error, |
| 644 | "Failed to open translated nexe (no access)."); |
| 645 | return; |
| 646 | } |
| 647 | ReportPpapiError(ERROR_PNACL_CACHE_FETCH_OTHER, |
| 648 | pp_error, |
| 649 | "Failed to open translated nexe."); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 650 | return; |
| 651 | } |
| 652 | |
| 653 | // Transfer ownership of cache/temp file's wrapper to the coordinator. |
| 654 | if (cached_nexe_file_ != NULL) { |
| 655 | translated_fd_.reset(cached_nexe_file_->release_read_wrapper()); |
| 656 | } else { |
| 657 | translated_fd_.reset(temp_nexe_file_->release_read_wrapper()); |
| 658 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 659 | translate_notify_callback_.Run(pp_error); |
| 660 | } |
| 661 | |
Ben Murdoch | 2385ea3 | 2013-08-06 11:01:04 +0100 | [diff] [blame] | 662 | void PnaclCoordinator::DidCheckPnaclInstalled(int32_t pp_error) { |
| 663 | if (pp_error != PP_OK) { |
| 664 | ReportNonPpapiError( |
| 665 | ERROR_PNACL_RESOURCE_FETCH, |
| 666 | nacl::string("The Portable Native Client component is not installed" |
| 667 | " or has been disabled.")); |
| 668 | return; |
| 669 | } |
| 670 | |
| 671 | // Loading resources (e.g. llc and ld nexes) is done with PnaclResources. |
| 672 | resources_.reset(new PnaclResources(plugin_, |
| 673 | this, |
| 674 | this->manifest_.get())); |
| 675 | CHECK(resources_ != NULL); |
| 676 | |
| 677 | // The first step of loading resources: read the resource info file. |
| 678 | pp::CompletionCallback resource_info_read_cb = |
| 679 | callback_factory_.NewCallback( |
| 680 | &PnaclCoordinator::ResourceInfoWasRead); |
| 681 | resources_->ReadResourceInfo(PnaclUrls::GetResourceInfoUrl(), |
| 682 | resource_info_read_cb); |
| 683 | } |
| 684 | |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 685 | void PnaclCoordinator::ResourceInfoWasRead(int32_t pp_error) { |
| 686 | PLUGIN_PRINTF(("PluginCoordinator::ResourceInfoWasRead (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 687 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 688 | // Second step of loading resources: call StartLoad. |
| 689 | pp::CompletionCallback resources_cb = |
| 690 | callback_factory_.NewCallback(&PnaclCoordinator::ResourcesDidLoad); |
| 691 | resources_->StartLoad(resources_cb); |
| 692 | } |
| 693 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 694 | void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) { |
| 695 | PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 696 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 697 | if (pp_error != PP_OK) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 698 | // Finer-grained error code should have already been reported by |
| 699 | // the PnaclResources class. |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 700 | return; |
| 701 | } |
| 702 | |
| 703 | if (!off_the_record_) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 704 | if (use_new_cache_) { |
| 705 | OpenBitcodeStream(); |
| 706 | } else { |
| 707 | // Open the local temporary FS to see if we get a hit in the cache. |
| 708 | pp::CompletionCallback cb = |
| 709 | callback_factory_.NewCallback(&PnaclCoordinator::FileSystemDidOpen); |
| 710 | int32_t open_error = file_system_->Open(0, cb); |
| 711 | if (open_error != PP_OK_COMPLETIONPENDING) { |
| 712 | // At this point, no async request has kicked off to check for |
| 713 | // permissions, space, etc., so the only error that can be detected |
| 714 | // now is that an open() is already in progress (or a really terrible |
| 715 | // error). |
| 716 | if (pp_error == PP_ERROR_INPROGRESS) { |
| 717 | ReportPpapiError( |
| 718 | ERROR_PNACL_CACHE_OPEN_INPROGRESS, |
| 719 | pp_error, |
| 720 | "File system for PNaCl translation cache failed to open " |
| 721 | "(in progress)."); |
| 722 | return; |
| 723 | } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 724 | ReportPpapiError( |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 725 | ERROR_PNACL_CACHE_OPEN_OTHER, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 726 | pp_error, |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 727 | "File system for PNaCl translation cache failed to open."); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 728 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 729 | } |
| 730 | } else { |
| 731 | // We don't have a cache, so do the non-cached codepath. |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 732 | OpenBitcodeStream(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 733 | } |
| 734 | } |
| 735 | |
| 736 | void PnaclCoordinator::FileSystemDidOpen(int32_t pp_error) { |
| 737 | PLUGIN_PRINTF(("PnaclCoordinator::FileSystemDidOpen (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 738 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 739 | if (pp_error != PP_OK) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 740 | if (pp_error == PP_ERROR_NOACCESS) { |
| 741 | ReportPpapiError( |
| 742 | ERROR_PNACL_CACHE_OPEN_NOACCESS, |
| 743 | pp_error, |
| 744 | "File system for PNaCl translation cache failed to open " |
| 745 | "(no access)."); |
| 746 | return; |
| 747 | } |
| 748 | if (pp_error == PP_ERROR_NOQUOTA) { |
| 749 | ReportPpapiError( |
| 750 | ERROR_PNACL_CACHE_OPEN_NOQUOTA, |
| 751 | pp_error, |
| 752 | "File system for PNaCl translation cache failed to open " |
| 753 | "(no quota)."); |
| 754 | return; |
| 755 | } |
| 756 | if (pp_error == PP_ERROR_NOSPACE) { |
| 757 | ReportPpapiError( |
| 758 | ERROR_PNACL_CACHE_OPEN_NOSPACE, |
| 759 | pp_error, |
| 760 | "File system for PNaCl translation cache failed to open " |
| 761 | "(no space)."); |
| 762 | return; |
| 763 | } |
| 764 | ReportPpapiError(ERROR_PNACL_CACHE_OPEN_OTHER, |
| 765 | pp_error, |
| 766 | "File system for PNaCl translation cache failed to open."); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 767 | } |
| 768 | dir_ref_.reset(new pp::FileRef(*file_system_, kPnaclTempDir)); |
| 769 | // Attempt to create the directory. |
| 770 | pp::CompletionCallback cb = |
| 771 | callback_factory_.NewCallback(&PnaclCoordinator::DirectoryWasCreated); |
| 772 | dir_ref_->MakeDirectory(cb); |
| 773 | } |
| 774 | |
| 775 | void PnaclCoordinator::DirectoryWasCreated(int32_t pp_error) { |
| 776 | PLUGIN_PRINTF(("PnaclCoordinator::DirectoryWasCreated (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 777 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 778 | if (pp_error != PP_ERROR_FILEEXISTS && pp_error != PP_OK) { |
| 779 | // Directory did not exist and could not be created. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 780 | if (pp_error == PP_ERROR_NOACCESS) { |
| 781 | ReportPpapiError( |
| 782 | ERROR_PNACL_CACHE_DIRECTORY_CREATE, |
| 783 | pp_error, |
| 784 | "PNaCl translation cache directory creation/check failed " |
| 785 | "(no access)."); |
| 786 | return; |
| 787 | } |
| 788 | ReportPpapiError( |
| 789 | ERROR_PNACL_CACHE_DIRECTORY_CREATE, |
| 790 | pp_error, |
| 791 | "PNaCl translation cache directory creation/check failed."); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 792 | return; |
| 793 | } |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 794 | OpenBitcodeStream(); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 795 | } |
| 796 | |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 797 | void PnaclCoordinator::OpenBitcodeStream() { |
| 798 | // Now open the pexe stream. |
| 799 | streaming_downloader_.reset(new FileDownloader()); |
| 800 | streaming_downloader_->Initialize(plugin_); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 801 | |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 802 | // Even though we haven't started downloading, create the translation |
| 803 | // thread object immediately. This ensures that any pieces of the file |
| 804 | // that get downloaded before the compilation thread is accepting |
| 805 | // SRPCs won't get dropped. |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 806 | translate_thread_.reset(new PnaclTranslateThread()); |
| 807 | if (translate_thread_ == NULL) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 808 | ReportNonPpapiError( |
| 809 | ERROR_PNACL_THREAD_CREATE, |
| 810 | "PnaclCoordinator: could not allocate translation thread."); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 811 | return; |
| 812 | } |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 813 | if (!use_new_cache_) { |
| 814 | // We also want to open the object file now so the |
| 815 | // translator can start writing to it during streaming translation. |
| 816 | obj_file_.reset(new TempFile(plugin_)); |
| 817 | pp::CompletionCallback obj_cb = |
| 818 | callback_factory_.NewCallback(&PnaclCoordinator::ObjectFileDidOpen); |
| 819 | obj_file_->Open(obj_cb, true); |
| 820 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 821 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 822 | pp::CompletionCallback cb = |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 823 | callback_factory_.NewCallback(&PnaclCoordinator::BitcodeStreamDidOpen); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 824 | if (!streaming_downloader_->OpenStream(pexe_url_, cb, this)) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 825 | ReportNonPpapiError( |
| 826 | ERROR_PNACL_PEXE_FETCH_OTHER, |
| 827 | nacl::string("PnaclCoordinator: failed to open stream ") + pexe_url_); |
| 828 | return; |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 829 | } |
| 830 | } |
| 831 | |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 832 | void PnaclCoordinator::BitcodeStreamDidOpen(int32_t pp_error) { |
| 833 | if (pp_error != PP_OK) { |
| 834 | BitcodeStreamDidFinish(pp_error); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 835 | // In the new cache case, we have not spun up the translation process yet, |
| 836 | // so we need to call TranslateFinished here. |
| 837 | if (use_new_cache_) |
| 838 | TranslateFinished(pp_error); |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 839 | return; |
| 840 | } |
| 841 | |
| 842 | if (!off_the_record_) { |
| 843 | // Get the cache key and try to open an existing entry. |
| 844 | nacl::string headers = streaming_downloader_->GetResponseHeaders(); |
| 845 | NaClHttpResponseHeaders parser; |
| 846 | parser.Parse(headers); |
| 847 | nacl::string cache_validators = parser.GetCacheValidators(); |
| 848 | if (parser.CacheControlNoStore() || cache_validators.empty()) { |
| 849 | // We can't cache in this case. |
| 850 | pnacl_options_.set_cache_validators(""); |
| 851 | CachedFileDidOpen(PP_ERROR_FAILED); |
| 852 | return; |
| 853 | } else { |
| 854 | nacl::string url = streaming_downloader_->url(); |
| 855 | // For now, combine the cache_validators + the URL as the key. |
| 856 | // When we change the cache backend to be not-origin-specific |
| 857 | // we should send the URL separately, and check in the browser's |
| 858 | // RenderViewHost / SiteInstance's IsSameWebsite() to prevent |
| 859 | // people from forging the URL for a different origin. |
| 860 | pnacl_options_.set_cache_validators(cache_validators + url); |
| 861 | } |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 862 | if (use_new_cache_) { |
| 863 | pp::CompletionCallback cb = |
| 864 | callback_factory_.NewCallback(&PnaclCoordinator::NexeFdDidOpen); |
| 865 | int32_t nexe_fd_err = |
| 866 | plugin_->nacl_interface()->GetNexeFd( |
| 867 | plugin_->pp_instance(), |
Ben Murdoch | 7dbb3d5 | 2013-07-17 14:55:54 +0100 | [diff] [blame] | 868 | streaming_downloader_->url().c_str(), |
| 869 | // TODO(dschuff): use the right abi version here. |
| 870 | 0, |
| 871 | pnacl_options_.opt_level(), |
| 872 | parser.GetHeader("last-modified").c_str(), |
| 873 | parser.GetHeader("etag").c_str(), |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 874 | &is_cache_hit_, |
| 875 | &nexe_handle_, |
| 876 | cb.pp_completion_callback()); |
| 877 | if (nexe_fd_err < PP_OK_COMPLETIONPENDING) { |
| 878 | ReportPpapiError(ERROR_PNACL_CREATE_TEMP, nexe_fd_err, |
| 879 | nacl::string("Call to GetNexeFd failed")); |
| 880 | return; |
| 881 | } |
| 882 | } else { |
| 883 | cached_nexe_file_.reset(new LocalTempFile( |
| 884 | plugin_, file_system_.get(), |
| 885 | nacl::string(kPnaclTempDir), |
| 886 | pnacl_options_.GetCacheKey())); |
| 887 | pp::CompletionCallback cb = |
| 888 | callback_factory_.NewCallback(&PnaclCoordinator::CachedFileDidOpen); |
| 889 | cached_nexe_file_->OpenRead(cb); |
| 890 | } |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 891 | } else { |
| 892 | // No cache case. |
| 893 | CachedFileDidOpen(PP_ERROR_FAILED); |
| 894 | } |
| 895 | } |
| 896 | |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 897 | void PnaclCoordinator::NexeFdDidOpen(int32_t pp_error) { |
| 898 | PLUGIN_PRINTF(("PnaclCoordinator::NexeFdDidOpen (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 899 | NACL_PRId32 ", hit=%d, handle=%d)\n", pp_error, |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 900 | is_cache_hit_ == PP_TRUE, |
| 901 | nexe_handle_)); |
| 902 | if (pp_error < PP_OK) { |
| 903 | ReportPpapiError(ERROR_PNACL_CREATE_TEMP, pp_error, |
| 904 | nacl::string("GetNexeFd failed")); |
| 905 | return; |
| 906 | } |
| 907 | temp_nexe_file_.reset(new TempFile(plugin_)); |
| 908 | if (!temp_nexe_file_->SetExistingFd(nexe_handle_)) { |
| 909 | ReportNonPpapiError( |
| 910 | ERROR_PNACL_CREATE_TEMP, |
| 911 | nacl::string( |
| 912 | "PnaclCoordinator: Got bad temp file handle from GetNexeFd")); |
| 913 | return; |
| 914 | } |
| 915 | if (is_cache_hit_ == PP_TRUE) { |
| 916 | // Cache hit -- no need to stream the rest of the file. |
| 917 | streaming_downloader_.reset(NULL); |
| 918 | // TODO(dschuff): update UMA stats for hit/miss once there could actually |
| 919 | // be hits/misses. |
| 920 | // Open it for reading as the cached nexe file. |
| 921 | pp::CompletionCallback cb = |
| 922 | callback_factory_.NewCallback(&PnaclCoordinator::NexeReadDidOpen); |
| 923 | temp_nexe_file_->Open(cb, false); |
| 924 | } else { |
| 925 | // Open an object file first so the translator can start writing to it |
| 926 | // during streaming translation. |
| 927 | obj_file_.reset(new TempFile(plugin_)); |
| 928 | pp::CompletionCallback obj_cb = |
| 929 | callback_factory_.NewCallback(&PnaclCoordinator::ObjectFileDidOpen); |
| 930 | obj_file_->Open(obj_cb, true); |
| 931 | |
| 932 | // Meanwhile, a miss means we know we need to stream the bitcode, so stream |
| 933 | // the rest of it now. (Calling FinishStreaming means that the downloader |
| 934 | // will begin handing data to the coordinator, which is safe any time after |
| 935 | // the translate_thread_ object has been initialized). |
| 936 | pp::CompletionCallback finish_cb = callback_factory_.NewCallback( |
| 937 | &PnaclCoordinator::BitcodeStreamDidFinish); |
| 938 | streaming_downloader_->FinishStreaming(finish_cb); |
| 939 | } |
| 940 | } |
| 941 | |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 942 | void PnaclCoordinator::CachedFileDidOpen(int32_t pp_error) { |
| 943 | PLUGIN_PRINTF(("PnaclCoordinator::CachedFileDidOpen (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 944 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 945 | if (pp_error == PP_OK) { |
| 946 | // Cache hit -- no need to stream the rest of the file. |
| 947 | streaming_downloader_.reset(NULL); |
| 948 | HistogramEnumerateTranslationCache(true); |
| 949 | NexeReadDidOpen(PP_OK); |
| 950 | return; |
| 951 | } |
| 952 | // Otherwise, the cache file is missing so we must translate. |
| 953 | HistogramEnumerateTranslationCache(false); |
| 954 | |
| 955 | // Continue streaming. |
| 956 | pp::CompletionCallback cb = |
| 957 | callback_factory_.NewCallback(&PnaclCoordinator::BitcodeStreamDidFinish); |
| 958 | streaming_downloader_->FinishStreaming(cb); |
| 959 | } |
| 960 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 961 | void PnaclCoordinator::BitcodeStreamDidFinish(int32_t pp_error) { |
| 962 | PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamDidFinish (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 963 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 964 | if (pp_error != PP_OK) { |
| 965 | // Defer reporting the error and cleanup until after the translation |
| 966 | // thread returns, because it may be accessing the coordinator's |
| 967 | // objects or writing to the files. |
| 968 | translate_finish_error_ = pp_error; |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 969 | if (pp_error == PP_ERROR_ABORTED) { |
| 970 | error_info_.SetReport(ERROR_PNACL_PEXE_FETCH_ABORTED, |
| 971 | "PnaclCoordinator: pexe load failed (aborted)."); |
| 972 | } |
| 973 | if (pp_error == PP_ERROR_NOACCESS) { |
| 974 | error_info_.SetReport(ERROR_PNACL_PEXE_FETCH_NOACCESS, |
| 975 | "PnaclCoordinator: pexe load failed (no access)."); |
| 976 | } else { |
| 977 | nacl::stringstream ss; |
| 978 | ss << "PnaclCoordinator: pexe load failed (pp_error=" << pp_error << ")."; |
| 979 | error_info_.SetReport(ERROR_PNACL_PEXE_FETCH_OTHER, ss.str()); |
| 980 | } |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 981 | if (use_new_cache_) { |
| 982 | plugin_->nacl_interface()->ReportTranslationFinished( |
| 983 | plugin_->pp_instance(), |
| 984 | PP_FALSE); |
| 985 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 986 | translate_thread_->AbortSubprocesses(); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 987 | } else { |
| 988 | // Compare download completion pct (100% now), to compile completion pct. |
| 989 | HistogramRatio("NaCl.Perf.PNaClLoadTime.PctCompiledWhenFullyDownloaded", |
| 990 | pexe_bytes_compiled_, pexe_size_); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 991 | } |
| 992 | } |
| 993 | |
| 994 | void PnaclCoordinator::BitcodeStreamGotData(int32_t pp_error, |
| 995 | FileStreamData data) { |
| 996 | PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamGotData (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 997 | NACL_PRId32 ", data=%p)\n", pp_error, data ? &(*data)[0] : 0)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 998 | DCHECK(translate_thread_.get()); |
Torne (Richard Coles) | 7d4cd47 | 2013-06-19 11:58:07 +0100 | [diff] [blame] | 999 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1000 | translate_thread_->PutBytes(data, pp_error); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 1001 | // If pp_error > 0, then it represents the number of bytes received. |
| 1002 | if (data && pp_error > 0) { |
| 1003 | pexe_size_ += pp_error; |
| 1004 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1005 | } |
| 1006 | |
| 1007 | StreamCallback PnaclCoordinator::GetCallback() { |
| 1008 | return callback_factory_.NewCallbackWithOutput( |
| 1009 | &PnaclCoordinator::BitcodeStreamGotData); |
| 1010 | } |
| 1011 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 1012 | void PnaclCoordinator::BitcodeGotCompiled(int32_t pp_error, |
| 1013 | int64_t bytes_compiled) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 1014 | pexe_bytes_compiled_ += bytes_compiled; |
Torne (Richard Coles) | a93a17c | 2013-05-15 11:34:50 +0100 | [diff] [blame] | 1015 | // If we don't know the expected total yet, ask. |
| 1016 | if (!ExpectedProgressKnown()) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 1017 | int64_t amount_downloaded; // dummy variable. |
| 1018 | streaming_downloader_->GetDownloadProgress(&amount_downloaded, |
| 1019 | &expected_pexe_size_); |
| 1020 | } |
Torne (Richard Coles) | a93a17c | 2013-05-15 11:34:50 +0100 | [diff] [blame] | 1021 | // Hold off reporting the last few bytes of progress, since we don't know |
| 1022 | // when they are actually completely compiled. "bytes_compiled" only means |
| 1023 | // that bytes were sent to the compiler. |
| 1024 | if (ExpectedProgressKnown()) { |
| 1025 | if (!ShouldDelayProgressEvent()) { |
| 1026 | plugin_->EnqueueProgressEvent(plugin::Plugin::kProgressEventProgress, |
| 1027 | pexe_url_, |
| 1028 | plugin::Plugin::LENGTH_IS_COMPUTABLE, |
| 1029 | pexe_bytes_compiled_, |
| 1030 | expected_pexe_size_); |
| 1031 | } |
| 1032 | } else { |
| 1033 | plugin_->EnqueueProgressEvent(plugin::Plugin::kProgressEventProgress, |
| 1034 | pexe_url_, |
| 1035 | plugin::Plugin::LENGTH_IS_NOT_COMPUTABLE, |
| 1036 | pexe_bytes_compiled_, |
| 1037 | expected_pexe_size_); |
| 1038 | } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 1039 | } |
| 1040 | |
| 1041 | pp::CompletionCallback PnaclCoordinator::GetCompileProgressCallback( |
| 1042 | int64_t bytes_compiled) { |
| 1043 | return callback_factory_.NewCallback(&PnaclCoordinator::BitcodeGotCompiled, |
| 1044 | bytes_compiled); |
| 1045 | } |
| 1046 | |
| 1047 | void PnaclCoordinator::GetCurrentProgress(int64_t* bytes_loaded, |
| 1048 | int64_t* bytes_total) { |
| 1049 | *bytes_loaded = pexe_bytes_compiled_; |
| 1050 | *bytes_total = expected_pexe_size_; |
| 1051 | } |
| 1052 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1053 | void PnaclCoordinator::ObjectFileDidOpen(int32_t pp_error) { |
| 1054 | PLUGIN_PRINTF(("PnaclCoordinator::ObjectFileDidOpen (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 1055 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1056 | if (pp_error != PP_OK) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 1057 | ReportPpapiError(ERROR_PNACL_CREATE_TEMP, |
| 1058 | pp_error, |
| 1059 | "Failed to open scratch object file."); |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 1060 | if (use_new_cache_) { |
| 1061 | plugin_->nacl_interface()->ReportTranslationFinished( |
| 1062 | plugin_->pp_instance(), |
| 1063 | PP_FALSE); |
| 1064 | } |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1065 | return; |
| 1066 | } |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 1067 | // Open the nexe file for connecting ld and sel_ldr. |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1068 | // Start translation when done with this last step of setup! |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 1069 | if (!use_new_cache_) |
| 1070 | // In the new cache case, the TempFile has already been created. |
| 1071 | temp_nexe_file_.reset(new TempFile(plugin_)); |
| 1072 | |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1073 | pp::CompletionCallback cb = |
| 1074 | callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 1075 | temp_nexe_file_->Open(cb, true); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1076 | } |
| 1077 | |
| 1078 | void PnaclCoordinator::RunTranslate(int32_t pp_error) { |
| 1079 | PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%" |
Ben Murdoch | bbcdd45 | 2013-07-25 10:06:34 +0100 | [diff] [blame] | 1080 | NACL_PRId32 ")\n", pp_error)); |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1081 | // Invoke llc followed by ld off the main thread. This allows use of |
| 1082 | // blocking RPCs that would otherwise block the JavaScript main thread. |
| 1083 | pp::CompletionCallback report_translate_finished = |
| 1084 | callback_factory_.NewCallback(&PnaclCoordinator::TranslateFinished); |
| 1085 | |
| 1086 | CHECK(translate_thread_ != NULL); |
| 1087 | translate_thread_->RunTranslate(report_translate_finished, |
| 1088 | manifest_.get(), |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1089 | obj_file_.get(), |
| 1090 | temp_nexe_file_.get(), |
| 1091 | &error_info_, |
| 1092 | resources_.get(), |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 1093 | &pnacl_options_, |
| 1094 | this, |
Torne (Richard Coles) | 5821806 | 2012-11-14 11:43:16 +0000 | [diff] [blame] | 1095 | plugin_); |
| 1096 | } |
| 1097 | |
| 1098 | } // namespace plugin |