diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-22 23:09:52 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-22 23:09:52 +0000 |
commit | d21e4a40ecf63968b03a32b4da6725eb2be7b9f1 (patch) | |
tree | f1761eba3783fe4fd1beacd2227dc86e7e063abe /ppapi/native_client | |
parent | bdb0e21c3e8eae56068895c859d887a9a3542468 (diff) | |
download | chromium_src-d21e4a40ecf63968b03a32b4da6725eb2be7b9f1.zip chromium_src-d21e4a40ecf63968b03a32b4da6725eb2be7b9f1.tar.gz chromium_src-d21e4a40ecf63968b03a32b4da6725eb2be7b9f1.tar.bz2 |
Revert 284684 "Pepper: Delete FileDownloader in trusted plugin."
Reverting as broke chrome and chromeos dbg builders:
http://build.chromium.org/p/chromium.linux/builders/Linux%20Tests%20%28dbg%29%281%29/builds/32615/steps/browser_tests/logs/SuccessfulLoadUMA
[ RUN ] NaClBrowserTestPnacl.SuccessfulLoadUMA
Xlib: extension "RANDR" missing on display ":9".
Xlib: extension "RANDR" missing on display ":9".
[18889:18889:0722/130648:WARNING:password_store_factory.cc(215)] Using
basic (unencrypted) store for password storage. See
http://code.google.com/p/chromium/wiki/LinuxPasswordStorage for more
information about password storage options.
HTTP server started on http://127.0.0.1:56115...
sending server_data: {"host": "127.0.0.1", "port": 56115} (36 bytes)
[9:10:0722/130650:ERROR:pnacl_translation_resource_host.cc(135)] Got
invalid platformfilefortransit
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/debug/vector:461:
error: attempt to insert into container with an iterator from a
different container.
Objects involved in the operation:
sequence "this" @ 0x0x392ba6c93260 {
}
iterator "__position" @ 0x0x7fff9ff24e20 {
state = past-the-end;
references sequence @ 0x0x7fff9ff24e20
}
[18889:18938:0722/130651:WARNING:raw_channel_posix.cc(214)] recvmsg:
Connection reset by peer
BrowserTestBase signal handler received SIGTERM. Backtrace:
#0 0x7fe4bf491cee base::debug::StackTrace::StackTrace()
#1 0x000004af93fa content::(anonymous
namespace)::DumpStackTraceSignalHandler()
#2 0x7fe4b68074a0 \u003Cunknown>
#3 0x7fe4b68b9a43 __poll
#4 0x7fe4b76faff6 \u003Cunknown>
#5 0x7fe4b76fb124 g_main_context_iteration
#6 0x7fe4bf44ff75 base::MessagePumpGlib::Run()
#7 0x7fe4bf54b1f0 base::MessageLoop::RunHandler()
#8 0x7fe4bf5b18e2 base::RunLoop::Run()
#9 0x000004b63969 content::RunThisRunLoop()
#10 0x000004b638fa content::RunMessageLoop()
#11 0x000004b0ea15 content::JavascriptTestObserver::Run()
#12 0x000001312927 NaClBrowserTestBase::RunJavascriptTest()
#13 0x000001312a48 NaClBrowserTestBase::RunLoadTest()
#14 0x00000130f514 (anonymous
namespace)::NaClBrowserTestPnacl_SuccessfulLoadUMA_Test::RunTestOnMai
...
> Pepper: Delete FileDownloader in trusted plugin.
>
> This simplifies PnaclCoordinator considerably and reduces the total
> amount of code in the trusted plugin.
>
> BUG=239656
>
> Review URL: https://codereview.chromium.org/393693004
TBR=teravest@chromium.org
Review URL: https://codereview.chromium.org/406323003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284791 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/native_client')
10 files changed, 530 insertions, 123 deletions
diff --git a/ppapi/native_client/src/trusted/plugin/callback_source.h b/ppapi/native_client/src/trusted/plugin/callback_source.h new file mode 100644 index 0000000..928a577 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/callback_source.h @@ -0,0 +1,33 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_CALLBACK_SOURCE_H +#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_CALLBACK_SOURCE_H + +#include "ppapi/cpp/completion_callback.h" + +namespace plugin { + +// Classes that implement this interface can be used with FileDownloader's +// DOWNLOAD_STREAM mode. For each chunk of the file as it downloads, +// The FileDownloader will get a callback of type +// pp::CompletionCallbackWithOutput<std::vector<char>*> using the +// GetCallback function, and call it immediately, passing a pointer to a +// vector with the data as the output field. The class is templatized just +// in case there are any other use cases in the future. +// This class really only exists as a way to get callbacks +// bound to an object (i.e. we don't need the asynchronous behavior of PPAPI) +// All we really need is tr1::function or base::bind or some such, but we don't +// have those in the plugin. + +template<class T> +class CallbackSource { + public: + virtual ~CallbackSource(); + // Returns a callback from callback_factory's NewCallbackWithOutput, + // bound to the implementing object. + virtual pp::CompletionCallbackWithOutput<T> GetCallback() = 0; +}; +} +#endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_CALLBACK_SOURCE_H diff --git a/ppapi/native_client/src/trusted/plugin/file_downloader.cc b/ppapi/native_client/src/trusted/plugin/file_downloader.cc new file mode 100644 index 0000000..ccddfe8 --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/file_downloader.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/native_client/src/trusted/plugin/file_downloader.h" + +#include <stdio.h> +#include <string.h> +#include <string> + +#include "native_client/src/include/portability_io.h" +#include "native_client/src/shared/platform/nacl_check.h" +#include "native_client/src/shared/platform/nacl_time.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/cpp/url_request_info.h" +#include "ppapi/cpp/url_response_info.h" +#include "ppapi/native_client/src/trusted/plugin/callback_source.h" +#include "ppapi/native_client/src/trusted/plugin/plugin.h" +#include "ppapi/native_client/src/trusted/plugin/utility.h" + +namespace plugin { + +FileDownloader::FileDownloader(Plugin* instance) + : instance_(instance), + file_open_notify_callback_(pp::BlockUntilComplete()), + stream_finish_callback_(pp::BlockUntilComplete()), + mode_(DOWNLOAD_NONE), + data_stream_callback_source_(NULL) { + callback_factory_.Initialize(this); + temp_buffer_.resize(kTempBufferSize); +} + +bool FileDownloader::OpenStream( + const nacl::string& url, + const pp::CompletionCallback& callback, + StreamCallbackSource* stream_callback_source) { + data_stream_callback_source_ = stream_callback_source; + PLUGIN_PRINTF(("FileDownloader::Open (url=%s)\n", url.c_str())); + if (callback.pp_completion_callback().func == NULL || instance_ == NULL) + return false; + + status_code_ = -1; + file_open_notify_callback_ = callback; + mode_ = DOWNLOAD_TO_BUFFER_AND_STREAM; + pp::URLRequestInfo url_request(instance_); + + // Allow CORS. + // Note that "SetAllowCrossOriginRequests" (currently) has the side effect of + // preventing credentials from being sent on same-origin requests. We + // therefore avoid setting this flag unless we know for sure it is a + // cross-origin request, resulting in behavior similar to XMLHttpRequest. + if (!instance_->DocumentCanRequest(url)) + url_request.SetAllowCrossOriginRequests(true); + + if (!extra_request_headers_.empty()) + url_request.SetHeaders(extra_request_headers_); + + // Reset the url loader and file reader. + // Note that we have the only reference to the underlying objects, so + // this will implicitly close any pending IO and destroy them. + url_loader_ = pp::URLLoader(instance_); + url_request.SetRecordDownloadProgress(true); + + // Prepare the url request. + url_request.SetURL(url); + + // Request asynchronous download of the url providing an on-load callback. + // As long as this step is guaranteed to be asynchronous, we can call + // synchronously all other internal callbacks that eventually result in the + // invocation of the user callback. The user code will not be reentered. + pp::CompletionCallback onload_callback = + callback_factory_.NewCallback(&FileDownloader::URLLoadStartNotify); + int32_t pp_error = url_loader_.Open(url_request, onload_callback); + PLUGIN_PRINTF(("FileDownloader::Open (pp_error=%" NACL_PRId32 ")\n", + pp_error)); + CHECK(pp_error == PP_OK_COMPLETIONPENDING); + return true; +} + +bool FileDownloader::InitialResponseIsValid() { + // Process the response, validating the headers to confirm successful loading. + url_response_ = url_loader_.GetResponseInfo(); + if (url_response_.is_null()) { + PLUGIN_PRINTF(( + "FileDownloader::InitialResponseIsValid (url_response_=NULL)\n")); + return false; + } + + pp::Var full_url = url_response_.GetURL(); + if (!full_url.is_string()) { + PLUGIN_PRINTF(( + "FileDownloader::InitialResponseIsValid (url is not a string)\n")); + return false; + } + full_url_ = full_url.AsString(); + + status_code_ = url_response_.GetStatusCode(); + PLUGIN_PRINTF(("FileDownloader::InitialResponseIsValid (" + "response status_code=%" NACL_PRId32 ")\n", status_code_)); + return status_code_ == NACL_HTTP_STATUS_OK; +} + +void FileDownloader::URLLoadStartNotify(int32_t pp_error) { + PLUGIN_PRINTF(("FileDownloader::URLLoadStartNotify (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error != PP_OK) { + file_open_notify_callback_.RunAndClear(pp_error); + return; + } + + if (!InitialResponseIsValid()) { + file_open_notify_callback_.RunAndClear(PP_ERROR_FAILED); + return; + } + + file_open_notify_callback_.RunAndClear(PP_OK); +} + +void FileDownloader::BeginStreaming( + const pp::CompletionCallback& callback) { + stream_finish_callback_ = callback; + + // Finish streaming the body providing an optional callback. + pp::CompletionCallback onread_callback = + callback_factory_.NewOptionalCallback( + &FileDownloader::URLReadBodyNotify); + int32_t temp_size = static_cast<int32_t>(temp_buffer_.size()); + int32_t pp_error = url_loader_.ReadResponseBody(&temp_buffer_[0], + temp_size, + onread_callback); + if (pp_error != PP_OK_COMPLETIONPENDING) + onread_callback.RunAndClear(pp_error); +} + +void FileDownloader::URLReadBodyNotify(int32_t pp_error) { + PLUGIN_PRINTF(("FileDownloader::URLReadBodyNotify (pp_error=%" + NACL_PRId32")\n", pp_error)); + if (pp_error < PP_OK) { + stream_finish_callback_.RunAndClear(pp_error); + } else if (pp_error == PP_OK) { + data_stream_callback_source_->GetCallback().RunAndClear(PP_OK); + stream_finish_callback_.RunAndClear(PP_OK); + } else { + PLUGIN_PRINTF(("Running data_stream_callback, temp_buffer_=%p\n", + &temp_buffer_[0])); + StreamCallback cb = data_stream_callback_source_->GetCallback(); + *(cb.output()) = &temp_buffer_; + cb.RunAndClear(pp_error); + + pp::CompletionCallback onread_callback = + callback_factory_.NewOptionalCallback( + &FileDownloader::URLReadBodyNotify); + int32_t temp_size = static_cast<int32_t>(temp_buffer_.size()); + pp_error = url_loader_.ReadResponseBody(&temp_buffer_[0], + temp_size, + onread_callback); + if (pp_error != PP_OK_COMPLETIONPENDING) + onread_callback.RunAndClear(pp_error); + } +} + +bool FileDownloader::GetDownloadProgress( + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) const { + return url_loader_.GetDownloadProgress(bytes_received, + total_bytes_to_be_received); +} + +nacl::string FileDownloader::GetResponseHeaders() const { + pp::Var headers = url_response_.GetHeaders(); + if (!headers.is_string()) { + PLUGIN_PRINTF(( + "FileDownloader::GetResponseHeaders (headers are not a string)\n")); + return nacl::string(); + } + return headers.AsString(); +} + +} // namespace plugin diff --git a/ppapi/native_client/src/trusted/plugin/file_downloader.h b/ppapi/native_client/src/trusted/plugin/file_downloader.h new file mode 100644 index 0000000..4a1a71a --- /dev/null +++ b/ppapi/native_client/src/trusted/plugin/file_downloader.h @@ -0,0 +1,125 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_DOWNLOADER_H_ +#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_DOWNLOADER_H_ + +#include <deque> + +#include "native_client/src/include/nacl_macros.h" +#include "native_client/src/include/nacl_string.h" +#include "native_client/src/public/nacl_file_info.h" +#include "ppapi/c/private/ppb_nacl_private.h" +#include "ppapi/cpp/file_io.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/url_loader.h" +#include "ppapi/cpp/url_response_info.h" +#include "ppapi/native_client/src/trusted/plugin/callback_source.h" +#include "ppapi/utility/completion_callback_factory.h" + +namespace plugin { + +class Plugin; + +typedef enum { + DOWNLOAD_TO_BUFFER_AND_STREAM = 0, + DOWNLOAD_NONE +} DownloadMode; + +typedef std::vector<char>* FileStreamData; +typedef CallbackSource<FileStreamData> StreamCallbackSource; +typedef pp::CompletionCallbackWithOutput<FileStreamData> StreamCallback; + +// A class that wraps PPAPI URLLoader and FileIO functionality for downloading +// the url into a file and providing an open file descriptor. +class FileDownloader { + public: + explicit FileDownloader(Plugin* instance); + ~FileDownloader() {} + + // Issues a GET on |url| to start downloading the response into a file, + // and finish streaming it. |callback| will be run after streaming is + // done or if an error prevents streaming from completing. + // Returns true when callback is scheduled to be called on success or failure. + // Returns false if callback is NULL, or if the PPB_FileIO_Trusted interface + // is not available. + // If |record_progress| is true, then download progress will be recorded, + // and can be polled through GetDownloadProgress(). + // If |progress_callback| is not NULL and |record_progress| is true, + // then the callback will be invoked for every progress update received + // by the loader. + + // Similar to Open(), but used for streaming the |url| data directly to the + // caller without writing to a temporary file. The callbacks provided by + // |stream_callback_source| are expected to copy the data before returning. + // |callback| is called once the response headers are received, + // and streaming must be completed separately via BeginStreaming(). + bool OpenStream(const nacl::string& url, + const pp::CompletionCallback& callback, + StreamCallbackSource* stream_callback_source); + + // Finish streaming the response body for a URL request started by either + // OpenStream(). Runs the given |callback| when streaming is done. + void BeginStreaming(const pp::CompletionCallback& callback); + + // Once the GET request has finished, and the contents of the file + // represented by |url_| are available, |full_url_| is the full URL including + // the scheme, host and full path. + // Returns an empty string before the GET request has finished. + const nacl::string& full_url() const { return full_url_; } + + // GetDownloadProgress() returns the current download progress, which is + // meaningful after Open() has been called. Progress only refers to the + // response body and does not include the headers. + // + // This data is only available if the |record_progress| true in the + // Open() call. If progress is being recorded, then |bytes_received| + // will be set to the number of bytes received thus far, + // and |total_bytes_to_be_received| will be set to the total number + // of bytes to be received. The total bytes to be received may be unknown, + // in which case |total_bytes_to_be_received| will be set to -1. + bool GetDownloadProgress(int64_t* bytes_received, + int64_t* total_bytes_to_be_received) const; + + int status_code() const { return status_code_; } + nacl::string GetResponseHeaders() const; + + void set_request_headers(const nacl::string& extra_request_headers) { + extra_request_headers_ = extra_request_headers; + } + + private: + NACL_DISALLOW_COPY_AND_ASSIGN(FileDownloader); + + // For DOWNLOAD_TO_BUFFER_AND_STREAM, the process is very similar: + // 1) Ask the browser to start streaming |url_| to an internal buffer. + // 2) Ask the browser to finish streaming to |temp_buffer_| on success. + // 3) Wait for streaming to finish, passing the data directly to the user. + // Each step is done asynchronously using callbacks. We create callbacks + // through a factory to take advantage of ref-counting. + // The public Open*() functions start step 1), and the public BeginStreaming + // function proceeds to step 2) and 3). + bool InitialResponseIsValid(); + void URLLoadStartNotify(int32_t pp_error); + void URLReadBodyNotify(int32_t pp_error); + + Plugin* instance_; + nacl::string full_url_; + + nacl::string extra_request_headers_; + pp::URLResponseInfo url_response_; + pp::CompletionCallback file_open_notify_callback_; + pp::CompletionCallback stream_finish_callback_; + pp::URLLoader url_loader_; + pp::CompletionCallbackFactory<FileDownloader> callback_factory_; + int32_t status_code_; + DownloadMode mode_; + static const uint32_t kTempBufferSize = 16384; + std::vector<char> temp_buffer_; + StreamCallbackSource* data_stream_callback_source_; +}; + +} // namespace plugin + +#endif // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_FILE_DOWNLOADER_H_ diff --git a/ppapi/native_client/src/trusted/plugin/plugin.gypi b/ppapi/native_client/src/trusted/plugin/plugin.gypi index a29fac1..38bcd5c 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.gypi +++ b/ppapi/native_client/src/trusted/plugin/plugin.gypi @@ -6,6 +6,7 @@ 'variables': { 'chromium_code': 1, # Use higher warning level. 'common_sources': [ + 'file_downloader.cc', 'module_ppapi.cc', 'nacl_subprocess.cc', 'plugin.cc', diff --git a/ppapi/native_client/src/trusted/plugin/plugin.h b/ppapi/native_client/src/trusted/plugin/plugin.h index 721018c..29409c4 100644 --- a/ppapi/native_client/src/trusted/plugin/plugin.h +++ b/ppapi/native_client/src/trusted/plugin/plugin.h @@ -28,13 +28,12 @@ #include "ppapi/cpp/var.h" #include "ppapi/cpp/view.h" +#include "ppapi/native_client/src/trusted/plugin/file_downloader.h" #include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h" #include "ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h" #include "ppapi/native_client/src/trusted/plugin/service_runtime.h" #include "ppapi/native_client/src/trusted/plugin/utility.h" -#include "ppapi/utility/completion_callback_factory.h" - namespace nacl { class DescWrapper; class DescWrapperFactory; diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc index 6ce3646..3669159 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc @@ -63,35 +63,13 @@ nacl::string GetArchitectureAttributes(Plugin* plugin) { return attrs_var.AsString(); } -void DidCacheHit(void* user_data, PP_FileHandle nexe_file_handle) { - PnaclCoordinator* coordinator = static_cast<PnaclCoordinator*>(user_data); - coordinator->BitcodeStreamCacheHit(nexe_file_handle); -} - -void DidCacheMiss(void* user_data, int64_t expected_pexe_size) { - PnaclCoordinator* coordinator = static_cast<PnaclCoordinator*>(user_data); - coordinator->BitcodeStreamCacheMiss(expected_pexe_size); -} - -void DidStreamData(void* user_data, const void* stream_data, int32_t length) { - PnaclCoordinator* coordinator = static_cast<PnaclCoordinator*>(user_data); - coordinator->BitcodeStreamGotData(stream_data, length); -} - -void DidFinishStream(void* user_data, int32_t pp_error) { - PnaclCoordinator* coordinator = static_cast<PnaclCoordinator*>(user_data); - coordinator->BitcodeStreamDidFinish(pp_error); -} - -PPP_PexeStreamHandler kPexeStreamHandler = { - &DidCacheHit, - &DidCacheMiss, - &DidStreamData, - &DidFinishStream -}; - } // namespace +// Out-of-line destructor to keep it from getting put in every .o where +// callback_source.h is included +template<> +CallbackSource<FileStreamData>::~CallbackSource() {} + PnaclCoordinator* PnaclCoordinator::BitcodeToNative( Plugin* plugin, const nacl::string& pexe_url, @@ -129,6 +107,7 @@ PnaclCoordinator::PnaclCoordinator( pnacl_options_(pnacl_options), architecture_attributes_(GetArchitectureAttributes(plugin)), split_module_count_(1), + is_cache_hit_(PP_FALSE), error_already_reported_(false), pexe_size_(0), pexe_bytes_compiled_(0), @@ -286,6 +265,44 @@ void PnaclCoordinator::NexeReadDidOpen(int32_t pp_error) { } void PnaclCoordinator::OpenBitcodeStream() { + // Now open the pexe stream. + streaming_downloader_.reset(new FileDownloader(plugin_)); + // Mark the request as requesting a PNaCl bitcode file, + // so that component updater can detect this user action. + streaming_downloader_->set_request_headers( + "Accept: application/x-pnacl, */*"); + + // Even though we haven't started downloading, create the translation + // thread object immediately. This ensures that any pieces of the file + // that get downloaded before the compilation thread is accepting + // SRPCs won't get dropped. + translate_thread_.reset(new PnaclTranslateThread()); + if (translate_thread_ == NULL) { + ReportNonPpapiError( + PP_NACL_ERROR_PNACL_THREAD_CREATE, + "PnaclCoordinator: could not allocate translation thread."); + return; + } + + pp::CompletionCallback cb = + callback_factory_.NewCallback(&PnaclCoordinator::BitcodeStreamDidOpen); + if (!streaming_downloader_->OpenStream(pexe_url_, cb, this)) { + ReportNonPpapiError( + PP_NACL_ERROR_PNACL_PEXE_FETCH_OTHER, + nacl::string("PnaclCoordinator: failed to open stream ") + pexe_url_); + return; + } +} + +void PnaclCoordinator::BitcodeStreamDidOpen(int32_t pp_error) { + if (pp_error != PP_OK) { + BitcodeStreamDidFinish(pp_error); + // We have not spun up the translation process yet, so we need to call + // TranslateFinished here. + TranslateFinished(pp_error); + return; + } + // The component updater's resource throttles + OnDemand update/install // should block the URL request until the compiler is present. Now we // can load the resources (e.g. llc and ld nexes). @@ -309,73 +326,87 @@ void PnaclCoordinator::OpenBitcodeStream() { return; } - // Even though we haven't started downloading, create the translation - // thread object immediately. This ensures that any pieces of the file - // that get downloaded before the compilation thread is accepting - // SRPCs won't get dropped. - translate_thread_.reset(new PnaclTranslateThread()); - if (translate_thread_ == NULL) { - ReportNonPpapiError( - PP_NACL_ERROR_PNACL_THREAD_CREATE, - "PnaclCoordinator: could not allocate translation thread."); - return; - } + // Okay, now that we've started the HTTP request for the pexe + // and we've ensured that the PNaCl compiler + metadata is installed, + // get the cache key from the response headers and from the + // compiler's version metadata. + nacl::string headers = streaming_downloader_->GetResponseHeaders(); - GetNaClInterface()->StreamPexe(plugin_->pp_instance(), - pexe_url_.c_str(), - pnacl_options_.opt_level, - &kPexeStreamHandler, - this); + temp_nexe_file_.reset(new TempFile(plugin_)); + pp::CompletionCallback cb = + callback_factory_.NewCallback(&PnaclCoordinator::NexeFdDidOpen); + int32_t nexe_fd_err = + plugin_->nacl_interface()->GetNexeFd( + plugin_->pp_instance(), + streaming_downloader_->full_url().c_str(), + // TODO(dschuff): Get this value from the pnacl json file after it + // rolls in from NaCl. + 1, + pnacl_options_.opt_level, + headers.c_str(), + architecture_attributes_.c_str(), // Extra compile flags. + &is_cache_hit_, + temp_nexe_file_->internal_handle(), + cb.pp_completion_callback()); + if (nexe_fd_err < PP_OK_COMPLETIONPENDING) { + ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP, nexe_fd_err, + nacl::string("Call to GetNexeFd failed")); + } } -void PnaclCoordinator::BitcodeStreamCacheHit(PP_FileHandle handle) { - HistogramEnumerateTranslationCache(plugin_->uma_interface(), true); - if (handle == PP_kInvalidFileHandle) { +void PnaclCoordinator::NexeFdDidOpen(int32_t pp_error) { + PLUGIN_PRINTF(("PnaclCoordinator::NexeFdDidOpen (pp_error=%" + NACL_PRId32 ", hit=%d)\n", pp_error, + is_cache_hit_ == PP_TRUE)); + if (pp_error < PP_OK) { + ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP, pp_error, + nacl::string("GetNexeFd failed")); + return; + } + + if (*temp_nexe_file_->internal_handle() == PP_kInvalidFileHandle) { ReportNonPpapiError( PP_NACL_ERROR_PNACL_CREATE_TEMP, nacl::string( "PnaclCoordinator: Got bad temp file handle from GetNexeFd")); - BitcodeStreamDidFinish(PP_ERROR_FAILED); return; } - *temp_nexe_file_->internal_handle() = handle; - // Open it for reading as the cached nexe file. - NexeReadDidOpen(temp_nexe_file_->Open(false)); -} - -void PnaclCoordinator::BitcodeStreamCacheMiss(int64_t expected_pexe_size) { - HistogramEnumerateTranslationCache(plugin_->uma_interface(), false); - expected_pexe_size_ = expected_pexe_size; + HistogramEnumerateTranslationCache(plugin_->uma_interface(), is_cache_hit_); - // Open an object file first so the translator can start writing to it - // during streaming translation. - temp_nexe_file_.reset(new TempFile(plugin_)); - - for (int i = 0; i < split_module_count_; i++) { - nacl::scoped_ptr<TempFile> temp_file(new TempFile(plugin_)); - int32_t pp_error = temp_file->Open(true); - if (pp_error != PP_OK) { - ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP, - pp_error, - "Failed to open scratch object file."); - return; - } else { - obj_files_.push_back(temp_file.release()); + if (is_cache_hit_ == PP_TRUE) { + // Cache hit -- no need to stream the rest of the file. + streaming_downloader_.reset(NULL); + // Open it for reading as the cached nexe file. + NexeReadDidOpen(temp_nexe_file_->Open(false)); + } else { + // Open an object file first so the translator can start writing to it + // during streaming translation. + for (int i = 0; i < split_module_count_; i++) { + nacl::scoped_ptr<TempFile> temp_file(new TempFile(plugin_)); + int32_t pp_error = temp_file->Open(true); + if (pp_error != PP_OK) { + ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP, + pp_error, + "Failed to open scratch object file."); + return; + } else { + obj_files_.push_back(temp_file.release()); + } } + invalid_desc_wrapper_.reset(plugin_->wrapper_factory()->MakeInvalid()); + + // Meanwhile, a miss means we know we need to stream the bitcode, so stream + // the rest of it now. (Calling BeginStreaming means that the downloader + // will begin handing data to the coordinator, which is safe any time after + // the translate_thread_ object has been initialized). + pp::CompletionCallback finish_cb = callback_factory_.NewCallback( + &PnaclCoordinator::BitcodeStreamDidFinish); + streaming_downloader_->BeginStreaming(finish_cb); + + // Open the nexe file for connecting ld and sel_ldr. + // Start translation when done with this last step of setup! + RunTranslate(temp_nexe_file_->Open(true)); } - invalid_desc_wrapper_.reset(plugin_->wrapper_factory()->MakeInvalid()); - - // Open the nexe file for connecting ld and sel_ldr. - // Start translation when done with this last step of setup! - RunTranslate(temp_nexe_file_->Open(true)); -} - -void PnaclCoordinator::BitcodeStreamGotData(const void* data, int32_t length) { - DCHECK(translate_thread_.get()); - - translate_thread_->PutBytes(data, length); - if (data && length > 0) - pexe_size_ += length; } void PnaclCoordinator::BitcodeStreamDidFinish(int32_t pp_error) { @@ -398,24 +429,47 @@ void PnaclCoordinator::BitcodeStreamDidFinish(int32_t pp_error) { ss << "PnaclCoordinator: pexe load failed (pp_error=" << pp_error << ")."; error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_OTHER, ss.str()); } - - if (translate_thread_->started()) - translate_thread_->AbortSubprocesses(); - else - TranslateFinished(pp_error); + translate_thread_->AbortSubprocesses(); } else { // Compare download completion pct (100% now), to compile completion pct. HistogramRatio(plugin_->uma_interface(), "NaCl.Perf.PNaClLoadTime.PctCompiledWhenFullyDownloaded", pexe_bytes_compiled_, pexe_size_); + } +} + +void PnaclCoordinator::BitcodeStreamGotData(int32_t pp_error, + FileStreamData data) { + PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamGotData (pp_error=%" + NACL_PRId32 ", data=%p)\n", pp_error, data ? &(*data)[0] : 0)); + DCHECK(translate_thread_.get()); + + // When we have received data, pp_error is set to the number of bytes + // received. + if (pp_error > 0) { + CHECK(data); + translate_thread_->PutBytes(data, pp_error); + pexe_size_ += pp_error; + } else { translate_thread_->EndStream(); } } +StreamCallback PnaclCoordinator::GetCallback() { + return callback_factory_.NewCallbackWithOutput( + &PnaclCoordinator::BitcodeStreamGotData); +} + void PnaclCoordinator::BitcodeGotCompiled(int32_t pp_error, int64_t bytes_compiled) { DCHECK(pp_error == PP_OK); pexe_bytes_compiled_ += bytes_compiled; + // If we don't know the expected total yet, ask. + if (expected_pexe_size_ == -1) { + int64_t amount_downloaded; // dummy variable. + streaming_downloader_->GetDownloadProgress(&amount_downloaded, + &expected_pexe_size_); + } // Hold off reporting the last few bytes of progress, since we don't know // when they are actually completely compiled. "bytes_compiled" only means // that bytes were sent to the compiler. diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h index ac1a330..44a1d54 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h @@ -17,12 +17,12 @@ #include "ppapi/cpp/completion_callback.h" +#include "ppapi/native_client/src/trusted/plugin/callback_source.h" +#include "ppapi/native_client/src/trusted/plugin/file_downloader.h" #include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h" #include "ppapi/native_client/src/trusted/plugin/plugin_error.h" #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h" -#include "ppapi/utility/completion_callback_factory.h" - struct PP_PNaClOptions; namespace plugin { @@ -51,7 +51,7 @@ class TempFile; // Translation proceeds in two steps: // (1) llc translates the bitcode in pexe_url_ to an object in obj_file_. // (2) ld links the object code in obj_file_ and produces a nexe in nexe_file_. -class PnaclCoordinator { +class PnaclCoordinator: public CallbackSource<FileStreamData> { public: // Maximum number of object files passable to the translator. Cannot be // changed without changing the RPC signatures. @@ -69,6 +69,12 @@ class PnaclCoordinator { // BitcodeToNative has completed (and the finish_callback called). PP_FileHandle TakeTranslatedFileHandle(); + // Implement FileDownloader's template of the CallbackSource interface. + // This method returns a callback which will be called by the FileDownloader + // to stream the bitcode data as it arrives. The callback + // (BitcodeStreamGotData) passes it to llc over SRPC. + StreamCallback GetCallback(); + // Return a callback that should be notified when |bytes_compiled| bytes // have been compiled. pp::CompletionCallback GetCompileProgressCallback(int64_t bytes_compiled); @@ -86,16 +92,6 @@ class PnaclCoordinator { expected_pexe_size_) < kProgressEventSlopPct; } - - void BitcodeStreamCacheHit(PP_FileHandle handle); - void BitcodeStreamCacheMiss(int64_t expected_pexe_size); - - // Invoked when a pexe data chunk arrives (when using streaming translation) - void BitcodeStreamGotData(const void* data, int32_t length); - - // Invoked when the pexe download finishes (using streaming translation) - void BitcodeStreamDidFinish(int32_t pp_error); - private: NACL_DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator); @@ -108,9 +104,19 @@ class PnaclCoordinator { // Invoke to issue a GET request for bitcode. void OpenBitcodeStream(); + // Invoked when we've started an URL fetch for the pexe to check for + // caching metadata. + void BitcodeStreamDidOpen(int32_t pp_error); + // Invoked when we've gotten a temp FD for the nexe, either with the nexe + // data, or a writeable fd to save to. + void NexeFdDidOpen(int32_t pp_error); + // Invoked when a pexe data chunk arrives (when using streaming translation) + void BitcodeStreamGotData(int32_t pp_error, FileStreamData data); // Invoked when a pexe data chunk is compiled. void BitcodeGotCompiled(int32_t pp_error, int64_t bytes_compiled); + // Invoked when the pexe download finishes (using streaming translation) + void BitcodeStreamDidFinish(int32_t pp_error); // Once llc and ld nexes have been loaded and the two temporary files have // been created, this starts the translation. Translation starts two // subprocesses, one for llc and one for ld. @@ -174,6 +180,12 @@ class PnaclCoordinator { // Translated nexe file, produced by the linker. nacl::scoped_ptr<TempFile> temp_nexe_file_; + // Passed to the browser, which sets it to true if there is a translation + // cache hit. + PP_Bool is_cache_hit_; + + // Downloader for streaming translation + nacl::scoped_ptr<FileDownloader> streaming_downloader_; // Used to report information when errors (PPAPI or otherwise) are reported. ErrorInfo error_info_; diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc index 8fb07ad..fff5382 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc +++ b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc @@ -111,16 +111,27 @@ void PnaclTranslateThread::RunTranslate( } // Called from main thread to send bytes to the translator. -void PnaclTranslateThread::PutBytes(const void* bytes, int32_t count) { +void PnaclTranslateThread::PutBytes(std::vector<char>* bytes, int count) { + PLUGIN_PRINTF(("PutBytes (this=%p, bytes=%p, size=%" NACL_PRIuS + ", count=%d)\n", + this, bytes, bytes ? bytes->size() : 0, count)); + size_t buffer_size = 0; CHECK(bytes != NULL); + // Ensure that the buffer we send to the translation thread is the right size + // (count can be < the buffer size). This can be done without the lock. + buffer_size = bytes->size(); + bytes->resize(count); + NaClXMutexLock(&cond_mu_); - std::vector<char> v; - data_buffers_.push_back(v); - data_buffers_.back().insert(v.end(), - static_cast<const char*>(bytes), - static_cast<const char*>(bytes) + count); + + data_buffers_.push_back(std::vector<char>()); + bytes->swap(data_buffers_.back()); // Avoid copying the buffer data. + NaClXCondVarSignal(&buffer_cond_); NaClXMutexUnlock(&cond_mu_); + + // Ensure the buffer we send back to the coordinator is the expected size + bytes->resize(buffer_size); } void PnaclTranslateThread::EndStream() { diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h index 60c1cba..ed0c7d7 100644 --- a/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h +++ b/ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h @@ -61,7 +61,7 @@ class PnaclTranslateThread { void AbortSubprocesses(); // Send bitcode bytes to the translator. Called from the main thread. - void PutBytes(const void* data, int count); + void PutBytes(std::vector<char>* data, int count); // Notify the translator that the end of the bitcode stream has been reached. // Called from the main thread. @@ -69,9 +69,6 @@ class PnaclTranslateThread { int64_t GetCompileTime() const { return compile_time_; } - // Returns true if RunTranslate() has been called, false otherwise. - bool started() const { return plugin_ != NULL; } - private: // Helper thread entry point for translation. Takes a pointer to // PnaclTranslateThread and calls DoTranslate(). diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c index c5e36d4..f1fc368 100644 --- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c +++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c @@ -3322,6 +3322,11 @@ static PP_Bool Pnacl_M25_PPB_NaCl_Private_IsNonSFIModeEnabled(void) { return iface->IsNonSFIModeEnabled(); } +static int32_t Pnacl_M25_PPB_NaCl_Private_GetNexeFd(PP_Instance instance, const char* pexe_url, uint32_t abi_version, uint32_t opt_level, const char* headers, const char* extra_flags, PP_Bool* is_hit, PP_FileHandle* nexe_handle, struct PP_CompletionCallback* callback) { + const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface; + return iface->GetNexeFd(instance, pexe_url, abi_version, opt_level, headers, extra_flags, is_hit, nexe_handle, *callback); +} + static void Pnacl_M25_PPB_NaCl_Private_ReportTranslationFinished(PP_Instance instance, PP_Bool success, int32_t opt_level, int64_t pexe_size, int64_t compile_time_us) { const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface; iface->ReportTranslationFinished(instance, success, opt_level, pexe_size, compile_time_us); @@ -3472,11 +3477,6 @@ static void Pnacl_M25_PPB_NaCl_Private_SetPNaClStartTime(PP_Instance instance) { iface->SetPNaClStartTime(instance); } -static void Pnacl_M25_PPB_NaCl_Private_StreamPexe(PP_Instance instance, const char* pexe_url, int32_t opt_level, const struct PPP_PexeStreamHandler_1_0* stream_handler, void* stream_handler_user_data) { - const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface; - iface->StreamPexe(instance, pexe_url, opt_level, stream_handler, stream_handler_user_data); -} - /* End wrapper methods for PPB_NaCl_Private_1_0 */ /* Begin wrapper methods for PPB_NetAddress_Private_0_1 */ @@ -4331,8 +4331,6 @@ static struct PP_Var Pnacl_M18_PPP_Instance_Private_GetInstanceObject(PP_Instanc /* End wrapper methods for PPP_Instance_Private_0_1 */ -/* Not generating wrapper methods for PPP_PexeStreamHandler_1_0 */ - /* Not generating wrapper interface for PPB_Audio_1_0 */ /* Not generating wrapper interface for PPB_Audio_1_1 */ @@ -5230,6 +5228,7 @@ static const struct PPB_NaCl_Private_1_0 Pnacl_Wrappers_PPB_NaCl_Private_1_0 = { .CreateTemporaryFile = (PP_FileHandle (*)(PP_Instance instance))&Pnacl_M25_PPB_NaCl_Private_CreateTemporaryFile, .GetNumberOfProcessors = (int32_t (*)(void))&Pnacl_M25_PPB_NaCl_Private_GetNumberOfProcessors, .IsNonSFIModeEnabled = (PP_Bool (*)(void))&Pnacl_M25_PPB_NaCl_Private_IsNonSFIModeEnabled, + .GetNexeFd = (int32_t (*)(PP_Instance instance, const char* pexe_url, uint32_t abi_version, uint32_t opt_level, const char* headers, const char* extra_flags, PP_Bool* is_hit, PP_FileHandle* nexe_handle, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_NaCl_Private_GetNexeFd, .ReportTranslationFinished = (void (*)(PP_Instance instance, PP_Bool success, int32_t opt_level, int64_t pexe_size, int64_t compile_time_us))&Pnacl_M25_PPB_NaCl_Private_ReportTranslationFinished, .DispatchEvent = (void (*)(PP_Instance instance, PP_NaClEventType event_type, const char* resource_url, PP_Bool length_is_computable, uint64_t loaded_bytes, uint64_t total_bytes))&Pnacl_M25_PPB_NaCl_Private_DispatchEvent, .ReportLoadSuccess = (void (*)(PP_Instance instance, uint64_t loaded_bytes, uint64_t total_bytes))&Pnacl_M25_PPB_NaCl_Private_ReportLoadSuccess, @@ -5259,8 +5258,7 @@ static const struct PPB_NaCl_Private_1_0 Pnacl_Wrappers_PPB_NaCl_Private_1_0 = { .ReportSelLdrStatus = (void (*)(PP_Instance instance, int32_t load_status, int32_t max_status))&Pnacl_M25_PPB_NaCl_Private_ReportSelLdrStatus, .LogTranslateTime = (void (*)(const char* histogram_name, int64_t time_us))&Pnacl_M25_PPB_NaCl_Private_LogTranslateTime, .OpenManifestEntry = (void (*)(PP_Instance instance, PP_Bool is_helper_process, const char* key, struct PP_NaClFileInfo* file_info, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_NaCl_Private_OpenManifestEntry, - .SetPNaClStartTime = (void (*)(PP_Instance instance))&Pnacl_M25_PPB_NaCl_Private_SetPNaClStartTime, - .StreamPexe = (void (*)(PP_Instance instance, const char* pexe_url, int32_t opt_level, const struct PPP_PexeStreamHandler_1_0* stream_handler, void* stream_handler_user_data))&Pnacl_M25_PPB_NaCl_Private_StreamPexe + .SetPNaClStartTime = (void (*)(PP_Instance instance))&Pnacl_M25_PPB_NaCl_Private_SetPNaClStartTime }; static const struct PPB_NetAddress_Private_0_1 Pnacl_Wrappers_PPB_NetAddress_Private_0_1 = { @@ -5483,8 +5481,6 @@ static const struct PPP_Instance_Private_0_1 Pnacl_Wrappers_PPP_Instance_Private .GetInstanceObject = &Pnacl_M18_PPP_Instance_Private_GetInstanceObject }; -/* Not generating wrapper interface for PPP_PexeStreamHandler_1_0 */ - static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Compositor_0_1 = { .iface_macro = PPB_COMPOSITOR_INTERFACE_0_1, .wrapped_iface = (const void *) &Pnacl_Wrappers_PPB_Compositor_0_1, |