summaryrefslogtreecommitdiffstats
path: root/ppapi/native_client
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-22 23:09:52 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-22 23:09:52 +0000
commitd21e4a40ecf63968b03a32b4da6725eb2be7b9f1 (patch)
treef1761eba3783fe4fd1beacd2227dc86e7e063abe /ppapi/native_client
parentbdb0e21c3e8eae56068895c859d887a9a3542468 (diff)
downloadchromium_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')
-rw-r--r--ppapi/native_client/src/trusted/plugin/callback_source.h33
-rw-r--r--ppapi/native_client/src/trusted/plugin/file_downloader.cc179
-rw-r--r--ppapi/native_client/src/trusted/plugin/file_downloader.h125
-rw-r--r--ppapi/native_client/src/trusted/plugin/plugin.gypi1
-rw-r--r--ppapi/native_client/src/trusted/plugin/plugin.h3
-rw-r--r--ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc228
-rw-r--r--ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h38
-rw-r--r--ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.cc23
-rw-r--r--ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h5
-rw-r--r--ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c18
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,