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
5#ifndef NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_
6#define NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_
7
8#include <vector>
9
10#include "native_client/src/include/nacl_macros.h"
11#include "native_client/src/shared/platform/nacl_sync_raii.h"
12#include "native_client/src/shared/srpc/nacl_srpc.h"
13#include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
14
15#include "ppapi/cpp/completion_callback.h"
16
17#include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h"
18#include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
19#include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h"
20
21#include "ppapi/utility/completion_callback_factory.h"
22
23struct PP_PNaClOptions;
24
25namespace plugin {
26
27class Plugin;
28class PnaclCoordinator;
29class PnaclTranslateThread;
30class TempFile;
31
32// A class invoked by Plugin to handle PNaCl client-side translation.
33// Usage:
34// (1) Invoke the factory method, e.g.,
35//     PnaclCoordinator* coord = BitcodeToNative(plugin,
36//                                               "http://foo.com/my.pexe",
37//                                               pnacl_options,
38//                                               TranslateNotifyCallback);
39// (2) TranslateNotifyCallback gets invoked when translation is complete.
40//     If the translation was successful, the pp_error argument is PP_OK.
41//     Other values indicate errors.
42// (3) After finish_callback runs, get the file descriptor of the translated
43//     nexe, e.g.,
44//     fd = coord->ReleaseTranslatedFD();
45// (4) Load the nexe from "fd".
46// (5) delete coord.
47//
48// Translation proceeds in two steps:
49// (1) llc translates the bitcode in pexe_url_ to an object in obj_file_.
50// (2) ld links the object code in obj_file_ and produces a nexe in nexe_file_.
51class PnaclCoordinator {
52 public:
53  // Maximum number of object files passable to the translator. Cannot be
54  // changed without changing the RPC signatures.
55  const static size_t kMaxTranslatorObjectFiles = 16;
56  virtual ~PnaclCoordinator();
57
58  // The factory method for translations.
59  static PnaclCoordinator* BitcodeToNative(
60      Plugin* plugin,
61      const std::string& pexe_url,
62      const PP_PNaClOptions& pnacl_options,
63      const pp::CompletionCallback& translate_notify_callback);
64
65  // Call this to take ownership of the FD of the translated nexe after
66  // BitcodeToNative has completed (and the finish_callback called).
67  PP_FileHandle TakeTranslatedFileHandle();
68
69  // Return a callback that should be notified when |bytes_compiled| bytes
70  // have been compiled.
71  pp::CompletionCallback GetCompileProgressCallback(int64_t bytes_compiled);
72
73  // Get the last known load progress.
74  void GetCurrentProgress(int64_t* bytes_loaded, int64_t* bytes_total);
75
76  // Return true if we should delay the progress event reporting.
77  // This delay approximates:
78  // - the size of the buffer of bytes sent but not-yet-compiled by LLC.
79  // - the linking time.
80  bool ShouldDelayProgressEvent() {
81    const uint32_t kProgressEventSlopPct = 5;
82    return ((expected_pexe_size_ - pexe_bytes_compiled_) * 100 /
83            expected_pexe_size_) < kProgressEventSlopPct;
84  }
85
86
87  void BitcodeStreamCacheHit(PP_FileHandle handle);
88  void BitcodeStreamCacheMiss(int64_t expected_pexe_size,
89                              PP_FileHandle handle);
90
91  // Invoked when a pexe data chunk arrives (when using streaming translation)
92  void BitcodeStreamGotData(const void* data, int32_t length);
93
94  // Invoked when the pexe download finishes (using streaming translation)
95  void BitcodeStreamDidFinish(int32_t pp_error);
96
97 private:
98  NACL_DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator);
99
100  // BitcodeToNative is the factory method for PnaclCoordinators.
101  // Therefore the constructor is private.
102  PnaclCoordinator(Plugin* plugin,
103                   const std::string& pexe_url,
104                   const PP_PNaClOptions& pnacl_options,
105                   const pp::CompletionCallback& translate_notify_callback);
106
107  // Invoke to issue a GET request for bitcode.
108  void OpenBitcodeStream();
109
110  // Invoked when a pexe data chunk is compiled.
111  void BitcodeGotCompiled(int32_t pp_error, int64_t bytes_compiled);
112  // Once llc and ld nexes have been loaded and the two temporary files have
113  // been created, this starts the translation.  Translation starts two
114  // subprocesses, one for llc and one for ld.
115  void RunTranslate(int32_t pp_error);
116
117  // Invoked when translation is finished.
118  void TranslateFinished(int32_t pp_error);
119
120  // Invoked when the read descriptor for nexe_file_ is created.
121  void NexeReadDidOpen(int32_t pp_error);
122
123  // Bring control back to the plugin by invoking the
124  // |translate_notify_callback_|.  This does not set the ErrorInfo report,
125  // it is assumed that it was already set.
126  void ExitWithError();
127  // Run |translate_notify_callback_| with an error condition that is not
128  // PPAPI specific.  Also set ErrorInfo report.
129  void ReportNonPpapiError(PP_NaClError err, const std::string& message);
130  // Run when faced with a PPAPI error condition. Bring control back to the
131  // plugin by invoking the |translate_notify_callback_|.
132  // Also set ErrorInfo report.
133  void ReportPpapiError(PP_NaClError err,
134                        int32_t pp_error, const std::string& message);
135
136
137  // Keeps track of the pp_error upon entry to TranslateFinished,
138  // for inspection after cleanup.
139  int32_t translate_finish_error_;
140
141  // The plugin owning the nexe for which we are doing translation.
142  Plugin* plugin_;
143
144  pp::CompletionCallback translate_notify_callback_;
145  // Set to true when the translation (if applicable) is finished and the nexe
146  // file is loaded, (or when there was an error), and the browser has been
147  // notified via ReportTranslationFinished. If it is not set before
148  // plugin/coordinator destruction, the destructor will call
149  // ReportTranslationFinished.
150  bool translation_finished_reported_;
151  // Threadsafety is required to support file lookups.
152  pp::CompletionCallbackFactory<PnaclCoordinator,
153                                pp::ThreadSafeThreadTraits> callback_factory_;
154
155  // An auxiliary class that manages downloaded resources (llc and ld nexes).
156  nacl::scoped_ptr<PnaclResources> resources_;
157
158  // The URL for the pexe file.
159  std::string pexe_url_;
160  // Options for translation.
161  PP_PNaClOptions pnacl_options_;
162  // Architecture-specific attributes used for translation. These are
163  // supplied by Chrome, not the developer, and are therefore different
164  // from PNaCl options.
165  std::string architecture_attributes_;
166
167  // Object file, produced by the translator and consumed by the linker.
168  std::vector<TempFile*> obj_files_;
169  nacl::scoped_ptr<nacl::DescWrapper> invalid_desc_wrapper_;
170  // Number of split modules (threads) for llc
171  int split_module_count_;
172
173  // Translated nexe file, produced by the linker.
174  nacl::scoped_ptr<TempFile> temp_nexe_file_;
175
176  // Used to report information when errors (PPAPI or otherwise) are reported.
177  ErrorInfo error_info_;
178
179  // True if an error was already reported, and translate_notify_callback_
180  // was already run/consumed.
181  bool error_already_reported_;
182
183  // State for timing and size information for UMA stats.
184  int64_t pexe_size_;  // Count as we stream -- will converge to pexe size.
185  int64_t pexe_bytes_compiled_;  // Count as we compile.
186  int64_t expected_pexe_size_;   // Expected download total (-1 if unknown).
187
188  // The helper thread used to do translations via SRPC.
189  // It accesses fields of PnaclCoordinator so it must have a
190  // shorter lifetime.
191  nacl::scoped_ptr<PnaclTranslateThread> translate_thread_;
192};
193
194//----------------------------------------------------------------------
195
196}  // namespace plugin;
197#endif  // NATIVE_CLIENT_SRC_TRUSTED_PLUGIN_PNACL_COORDINATOR_H_
198