Index: ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
index 790e0219f33fa3b884411a9e753bdcb59f94dc13..3377b6a6d9918f6cade2f163636d0530aa0d2336 100644 |
--- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
@@ -7,6 +7,7 @@ |
#include <utility> |
#include <vector> |
+#include "native_client/src/include/checked_cast.h" |
#include "native_client/src/include/portability_io.h" |
#include "native_client/src/shared/platform/nacl_check.h" |
#include "native_client/src/trusted/plugin/local_temp_file.h" |
@@ -16,14 +17,15 @@ |
#include "native_client/src/trusted/plugin/pnacl_translate_thread.h" |
#include "native_client/src/trusted/plugin/service_runtime.h" |
#include "native_client/src/trusted/plugin/temporary_file.h" |
-#include "native_client/src/trusted/service_runtime/include/sys/stat.h" |
+#include "ppapi/c/pp_bool.h" |
#include "ppapi/c/pp_errors.h" |
#include "ppapi/c/ppb_file_io.h" |
#include "ppapi/cpp/file_io.h" |
namespace { |
const char kPnaclTempDir[] = "/.pnacl"; |
+const uint32_t kCopyBufSize = 512 << 10; |
} |
namespace plugin { |
@@ -182,8 +184,13 @@ PnaclCoordinator* PnaclCoordinator::BitcodeToNative( |
PnaclCoordinator* coordinator = |
new PnaclCoordinator(plugin, pexe_url, |
cache_identity, translate_notify_callback); |
- PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (manifest=%p)\n", |
- reinterpret_cast<const void*>(coordinator->manifest_.get()))); |
+ coordinator->off_the_record_ = |
+ plugin->nacl_interface()->IsOffTheRecord(); |
+ PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (manifest=%p, " |
+ "off_the_record=%b)\n", |
+ reinterpret_cast<const void*>(coordinator->manifest_.get()), |
+ coordinator->off_the_record_)); |
+ |
// Load llc and ld. |
std::vector<nacl::string> resource_urls; |
resource_urls.push_back(PnaclUrls::GetLlcUrl()); |
@@ -234,7 +241,8 @@ PnaclCoordinator::PnaclCoordinator( |
manifest_(new ExtensionManifest(plugin->url_util())), |
pexe_url_(pexe_url), |
cache_identity_(cache_identity), |
- error_already_reported_(false) { |
+ error_already_reported_(false), |
+ off_the_record_(false) { |
PLUGIN_PRINTF(("PnaclCoordinator::PnaclCoordinator (this=%p, plugin=%p)\n", |
static_cast<void*>(this), static_cast<void*>(plugin))); |
callback_factory_.Initialize(this); |
@@ -294,51 +302,140 @@ void PnaclCoordinator::ReportPpapiError(int32_t pp_error) { |
void PnaclCoordinator::TranslateFinished(int32_t pp_error) { |
PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%" |
NACL_PRId32")\n", pp_error)); |
- // Save the translate error code, and inspect after cleaning up junk files. |
- // Note: If there was a surfaway and the file objects were actually |
- // destroyed, then we are in trouble since the obj_file_, nexe_file_, |
- // etc. may have been destroyed. |
- // TODO(jvoung,sehr): Fix. |
- // If there was an error already set (e.g. pexe load failure) then we want |
- // to use the first one, (which might be something useful) rather than |
- // the one from the compiler, (which is always just PP_ERROR_FAILED) |
- if (translate_finish_error_ == PP_OK) translate_finish_error_ = pp_error; |
- |
- // Close the nexe temporary file. |
- if (nexe_file_ != NULL) { |
- pp::CompletionCallback cb = |
- callback_factory_.NewCallback(&PnaclCoordinator::NexeFileWasClosed); |
- nexe_file_->Close(cb); |
+ // Bail out if there was an earlier error (e.g., pexe load failure). |
+ if (translate_finish_error_ != PP_OK) { |
+ ReportPpapiError(translate_finish_error_); |
+ return; |
+ } |
+ // Bail out if there is an error from the translation thread. |
+ if (pp_error != PP_OK) { |
+ ReportPpapiError(pp_error); |
+ return; |
+ } |
+ |
+ // The nexe is written to the temp_nexe_file_. We must Reset() the file |
+ // pointer to be able to read it again from the beginning. |
+ temp_nexe_file_->Reset(); |
+ |
+ if (cache_identity_ != "" && cached_nexe_file_ != NULL) { |
+ // We are using a cache, but had a cache miss, which is why we did the |
+ // translation. Reset cached_nexe_file_ to have a random name, |
+ // for scratch purposes, before renaming to the final cache_identity_. |
+ cached_nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), |
+ nacl::string(kPnaclTempDir))); |
+ pp::CompletionCallback cb = callback_factory_.NewCallback( |
+ &PnaclCoordinator::CachedNexeOpenedForWrite); |
+ cached_nexe_file_->OpenWrite(cb); |
+ } else { |
+ // For now, tolerate bitcode that is missing a cache identity, and |
+ // tolerate the lack of caching in incognito mode. |
+ PLUGIN_PRINTF(("PnaclCoordinator -- not caching.\n")); |
+ NexeReadDidOpen(PP_OK); |
} |
} |
-void PnaclCoordinator::NexeFileWasClosed(int32_t pp_error) { |
- PLUGIN_PRINTF(("PnaclCoordinator::NexeFileWasClosed (pp_error=%" |
- NACL_PRId32")\n", pp_error)); |
+void PnaclCoordinator::CachedNexeOpenedForWrite(int32_t pp_error) { |
if (pp_error != PP_OK) { |
- ReportPpapiError(pp_error); |
+ ReportPpapiError(pp_error, "Failed to open cache file for write."); |
return; |
} |
- // Now that cleanup of the obj file is done, check the old TranslateFinished |
- // error code to see if we should proceed normally or not. |
- if (translate_finish_error_ != PP_OK) { |
- pp::CompletionCallback cb = |
- callback_factory_.NewCallback(&PnaclCoordinator::NexeFileWasDeleted); |
- nexe_file_->Delete(cb); |
+ |
+ // Copy the contents from temp_nexe_file_ -> cached_nexe_file_, |
+ // then rename the cached_nexe_file_ file to the cache id. |
+ int64_t cur_offset = 0; |
+ nacl::DescWrapper* read_wrapper = temp_nexe_file_->read_wrapper(); |
+ char buf[kCopyBufSize]; |
+ int32_t num_read = |
+ nacl::assert_cast<int32_t>(read_wrapper->Read(buf, sizeof buf)); |
+ // Hit EOF or something. |
+ if (num_read == 0) { |
+ NexeWasCopiedToCache(PP_OK); |
return; |
} |
+ if (num_read < 0) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::CachedNexeOpenedForWrite read failed " |
+ "(error=%"NACL_PRId32")\n", num_read)); |
+ NexeWasCopiedToCache(PP_ERROR_FAILED); |
+ return; |
+ } |
+ pp::CompletionCallback cb = callback_factory_.NewCallback( |
+ &PnaclCoordinator::DidCopyNexeToCachePartial, num_read, cur_offset); |
+ cached_nexe_file_->write_file_io()->Write(cur_offset, buf, num_read, cb); |
+} |
- // Rename the nexe file to the cache id. |
- if (cache_identity_ != "") { |
- pp::CompletionCallback cb = |
- callback_factory_.NewCallback(&PnaclCoordinator::NexeFileWasRenamed); |
- nexe_file_->Rename(cache_identity_, cb); |
- } else { |
- // For now tolerate bitcode that is missing a cache identity. |
- PLUGIN_PRINTF(("PnaclCoordinator -- WARNING: missing cache identity," |
- " not caching.\n")); |
- NexeFileWasRenamed(PP_OK); |
+void PnaclCoordinator::DidCopyNexeToCachePartial(int32_t pp_error, |
+ int32_t num_read_prev, |
+ int64_t cur_offset) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial " |
+ "(pp_error=%"NACL_PRId32", num_read_prev=%"NACL_PRId32"" |
+ ", cur_offset=%"NACL_PRId64").\n", |
+ pp_error, num_read_prev, cur_offset)); |
+ // Assume we are done. |
+ if (pp_error == PP_OK) { |
+ NexeWasCopiedToCache(PP_OK); |
+ return; |
+ } |
+ if (pp_error < PP_OK) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial failed (err=%" |
+ NACL_PRId32")\n", pp_error)); |
+ NexeWasCopiedToCache(pp_error); |
+ return; |
} |
+ |
+ // Check if we wrote as much as we read. |
+ nacl::DescWrapper* read_wrapper = temp_nexe_file_->read_wrapper(); |
+ if (pp_error != num_read_prev) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial partial " |
+ "write (bytes_written=%"NACL_PRId32" vs " |
+ "read=%"NACL_PRId32")\n", pp_error, num_read_prev)); |
+ CHECK(pp_error < num_read_prev); |
+ // Seek back to re-read the bytes that were not written. |
+ nacl_off64_t seek_result = |
+ read_wrapper->Seek(pp_error - num_read_prev, SEEK_CUR); |
+ if (seek_result < 0) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial seek failed " |
+ "(err=%"NACL_PRId64")\n", seek_result)); |
+ NexeWasCopiedToCache(PP_ERROR_FAILED); |
+ return; |
+ } |
+ } |
+ |
+ int64_t next_offset = cur_offset + pp_error; |
+ char buf[kCopyBufSize]; |
+ int32_t num_read = |
+ nacl::assert_cast<int32_t>(read_wrapper->Read(buf, sizeof buf)); |
+ PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial read (bytes=%" |
+ NACL_PRId32")\n", num_read)); |
+ // Hit EOF or something. |
+ if (num_read == 0) { |
+ NexeWasCopiedToCache(PP_OK); |
+ return; |
+ } |
+ if (num_read < 0) { |
+ PLUGIN_PRINTF(("PnaclCoordinator::DidCopyNexeToCachePartial read failed " |
+ "(error=%"NACL_PRId32")\n", num_read)); |
+ NexeWasCopiedToCache(PP_ERROR_FAILED); |
+ return; |
+ } |
+ pp::CompletionCallback cb = callback_factory_.NewCallback( |
+ &PnaclCoordinator::DidCopyNexeToCachePartial, num_read, next_offset); |
+ PLUGIN_PRINTF(("PnaclCoordinator::CopyNexeToCache Writing (" |
+ "bytes=%"NACL_PRId32", buf=%p, file_io=%p)\n", num_read, buf, |
+ cached_nexe_file_->write_file_io())); |
+ cached_nexe_file_->write_file_io()->Write(next_offset, buf, num_read, cb); |
+} |
+ |
+void PnaclCoordinator::NexeWasCopiedToCache(int32_t pp_error) { |
+ if (pp_error != PP_OK) { |
+ // TODO(jvoung): This should probably try to delete the cache file |
+ // before returning... |
+ ReportPpapiError(pp_error, "Failed to copy nexe to cache."); |
+ return; |
+ } |
+ // Rename the cached_nexe_file_ file to the cache id, to finalize. |
+ pp::CompletionCallback cb = |
+ callback_factory_.NewCallback(&PnaclCoordinator::NexeFileWasRenamed); |
+ cached_nexe_file_->Rename(cache_identity_, cb); |
} |
void PnaclCoordinator::NexeFileWasRenamed(int32_t pp_error) { |
@@ -350,11 +447,12 @@ void PnaclCoordinator::NexeFileWasRenamed(int32_t pp_error) { |
ReportPpapiError(pp_error, "Failed to place cached bitcode translation."); |
return; |
} |
- nexe_file_->FinishRename(); |
- // Open the nexe temporary file for reading. |
+ |
+ cached_nexe_file_->FinishRename(); |
+ // Open the cache file for reading. |
pp::CompletionCallback cb = |
callback_factory_.NewCallback(&PnaclCoordinator::NexeReadDidOpen); |
- nexe_file_->OpenRead(cb); |
+ cached_nexe_file_->OpenRead(cb); |
} |
void PnaclCoordinator::NexeReadDidOpen(int32_t pp_error) { |
@@ -364,18 +462,17 @@ void PnaclCoordinator::NexeReadDidOpen(int32_t pp_error) { |
ReportPpapiError(pp_error, "Failed to open translated nexe."); |
return; |
} |
- // Transfer ownership of the nexe wrapper to the coordinator. |
- translated_fd_.reset(nexe_file_->release_read_wrapper()); |
+ |
+ // Transfer ownership of cache/temp file's wrapper to the coordinator. |
+ if (cached_nexe_file_ != NULL) { |
+ translated_fd_.reset(cached_nexe_file_->release_read_wrapper()); |
+ } else { |
+ translated_fd_.reset(temp_nexe_file_->release_read_wrapper()); |
+ } |
plugin_->EnqueueProgressEvent(Plugin::kProgressEventProgress); |
translate_notify_callback_.Run(pp_error); |
} |
-void PnaclCoordinator::NexeFileWasDeleted(int32_t pp_error) { |
- PLUGIN_PRINTF(("PnaclCoordinator::NexeFileWasDeleted (pp_error=%" |
- NACL_PRId32")\n", pp_error)); |
- ReportPpapiError(translate_finish_error_); |
-} |
- |
void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) { |
PLUGIN_PRINTF(("PnaclCoordinator::ResourcesDidLoad (pp_error=%" |
NACL_PRId32")\n", pp_error)); |
@@ -383,12 +480,17 @@ void PnaclCoordinator::ResourcesDidLoad(int32_t pp_error) { |
ReportPpapiError(pp_error, "resources failed to load."); |
return; |
} |
- // Open the local temporary file system to create the temporary files |
- // for the object and nexe. |
- pp::CompletionCallback cb = |
- callback_factory_.NewCallback(&PnaclCoordinator::FileSystemDidOpen); |
- if (!file_system_->Open(0, cb)) { |
- ReportNonPpapiError("failed to open file system."); |
+ |
+ if (!off_the_record_) { |
+ // Open the local temporary FS to see if we get a hit in the cache. |
+ pp::CompletionCallback cb = |
+ callback_factory_.NewCallback(&PnaclCoordinator::FileSystemDidOpen); |
+ if (!file_system_->Open(0, cb)) { |
+ ReportNonPpapiError("failed to open file system."); |
+ } |
+ } else { |
+ // We don't have a cache, so do the non-cached codepath. |
+ CachedFileDidOpen(PP_ERROR_FAILED); |
} |
} |
@@ -399,8 +501,7 @@ void PnaclCoordinator::FileSystemDidOpen(int32_t pp_error) { |
ReportPpapiError(pp_error, "file system didn't open."); |
return; |
} |
- dir_ref_.reset(new pp::FileRef(*file_system_, |
- kPnaclTempDir)); |
+ dir_ref_.reset(new pp::FileRef(*file_system_, kPnaclTempDir)); |
// Attempt to create the directory. |
pp::CompletionCallback cb = |
callback_factory_.NewCallback(&PnaclCoordinator::DirectoryWasCreated); |
@@ -416,12 +517,12 @@ void PnaclCoordinator::DirectoryWasCreated(int32_t pp_error) { |
return; |
} |
if (cache_identity_ != "") { |
- nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), |
- nacl::string(kPnaclTempDir), |
- cache_identity_)); |
+ cached_nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), |
+ nacl::string(kPnaclTempDir), |
+ cache_identity_)); |
pp::CompletionCallback cb = |
callback_factory_.NewCallback(&PnaclCoordinator::CachedFileDidOpen); |
- nexe_file_->OpenRead(cb); |
+ cached_nexe_file_->OpenRead(cb); |
} else { |
// For now, tolerate lack of cache identity... |
CachedFileDidOpen(PP_ERROR_FAILED); |
@@ -467,9 +568,9 @@ void PnaclCoordinator::BitcodeStreamDidFinish(int32_t pp_error) { |
PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamDidFinish (pp_error=%" |
NACL_PRId32")\n", pp_error)); |
if (pp_error != PP_OK) { |
- // Defer reporting the error and obj_file/nexe_file cleanup until after |
- // the translation thread returns, because it may be accessing the |
- // coordinator's objects or writing to the files. |
+ // Defer reporting the error and cleanup until after the translation |
+ // thread returns, because it may be accessing the coordinator's |
+ // objects or writing to the files. |
translate_finish_error_ = pp_error; |
error_info_.SetReport(ERROR_UNKNOWN, |
nacl::string("PnaclCoordinator: pexe load failed.")); |
@@ -499,11 +600,10 @@ void PnaclCoordinator::ObjectFileDidOpen(int32_t pp_error) { |
} |
// Create the nexe file for connecting ld and sel_ldr. |
// Start translation when done with this last step of setup! |
- nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), |
- nacl::string(kPnaclTempDir))); |
+ temp_nexe_file_.reset(new TempFile(plugin_)); |
pp::CompletionCallback cb = |
callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate); |
- nexe_file_->OpenWrite(cb); |
+ temp_nexe_file_->Open(cb); |
} |
void PnaclCoordinator::RunTranslate(int32_t pp_error) { |
@@ -519,7 +619,7 @@ void PnaclCoordinator::RunTranslate(int32_t pp_error) { |
manifest_.get(), |
ld_manifest_.get(), |
obj_file_.get(), |
- nexe_file_.get(), |
+ temp_nexe_file_.get(), |
&error_info_, |
resources_.get(), |
plugin_); |