diff options
author | dmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-29 00:49:51 +0000 |
---|---|---|
committer | dmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-29 00:49:51 +0000 |
commit | f54329e5d6a76858c67869e678f9462a964632b7 (patch) | |
tree | 4b92fd9b8111a157a4b66049aedf673c0856dfc9 | |
parent | 0be9392b7cc037c74baa929bc384baf36b0001f3 (diff) | |
download | chromium_src-f54329e5d6a76858c67869e678f9462a964632b7.zip chromium_src-f54329e5d6a76858c67869e678f9462a964632b7.tar.gz chromium_src-f54329e5d6a76858c67869e678f9462a964632b7.tar.bz2 |
PPAPI: Implement PPB_FileMapping on POSIX
BUG=83774
R=bbudge@chromium.org
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=247473
Review URL: https://codereview.chromium.org/69663002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247546 0039d316-1c4b-4281-b951-d872f2087c98
26 files changed, 1113 insertions, 13 deletions
diff --git a/chrome/browser/component_updater/ppapi_utils.cc b/chrome/browser/component_updater/ppapi_utils.cc index bebb9a5..ddbf36d 100644 --- a/chrome/browser/component_updater/ppapi_utils.cc +++ b/chrome/browser/component_updater/ppapi_utils.cc @@ -41,6 +41,7 @@ #include "ppapi/c/ppb_console.h" #include "ppapi/c/ppb_core.h" #include "ppapi/c/ppb_file_io.h" +#include "ppapi/c/ppb_file_mapping.h" #include "ppapi/c/ppb_file_ref.h" #include "ppapi/c/ppb_file_system.h" #include "ppapi/c/ppb_fullscreen.h" diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc index 6fc80e5..2e0c8b8 100644 --- a/chrome/test/ppapi/ppapi_browsertest.cc +++ b/chrome/test/ppapi/ppapi_browsertest.cc @@ -971,6 +971,16 @@ IN_PROC_BROWSER_TEST_F(PPAPIPrivateNaClPNaClTest, MAYBE_PNaCl_FileIO_Private) { ); } +// PPB_FileMapping is only implemented on POSIX currently. +// http://crbug.com/83774 +#if defined(OS_WIN) +#define MAYBE_FileMapping DISABLED_FileMapping +#else +#define MAYBE_FileMapping FileMapping +#endif +TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(MAYBE_FileMapping) +TEST_PPAPI_NACL(MAYBE_FileMapping) + // Note, the FileRef tests are split into two, because all of them together // sometimes take too long on windows: crbug.com/336999 IN_PROC_BROWSER_TEST_F(PPAPITest, FileRef1) { diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 2069bc4..09b3a3d 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc @@ -2402,6 +2402,7 @@ ppapi::Resource* PepperPluginInstanceImpl::GetSingletonResource( case ppapi::BROKER_SINGLETON_ID: case ppapi::BROWSER_FONT_SINGLETON_ID: case ppapi::EXTENSIONS_COMMON_SINGLETON_ID: + case ppapi::FILE_MAPPING_SINGLETON_ID: case ppapi::FLASH_CLIPBOARD_SINGLETON_ID: case ppapi::FLASH_FILE_SINGLETON_ID: case ppapi::FLASH_FULLSCREEN_SINGLETON_ID: diff --git a/content/renderer/pepper/plugin_module.cc b/content/renderer/pepper/plugin_module.cc index 60de434..2ce03af 100644 --- a/content/renderer/pepper/plugin_module.cc +++ b/content/renderer/pepper/plugin_module.cc @@ -66,6 +66,7 @@ #include "ppapi/c/ppb_console.h" #include "ppapi/c/ppb_core.h" #include "ppapi/c/ppb_file_io.h" +#include "ppapi/c/ppb_file_mapping.h" #include "ppapi/c/ppb_file_ref.h" #include "ppapi/c/ppb_file_system.h" #include "ppapi/c/ppb_fullscreen.h" diff --git a/ppapi/api/ppb_file_mapping.idl b/ppapi/api/ppb_file_mapping.idl index 2a10946..7037955 100644 --- a/ppapi/api/ppb_file_mapping.idl +++ b/ppapi/api/ppb_file_mapping.idl @@ -9,6 +9,8 @@ * memory. */ +[generate_thunk] + label Chrome { [channel=dev] M34 = 0.1 }; diff --git a/ppapi/c/ppb_file_mapping.h b/ppapi/c/ppb_file_mapping.h index 6887bfd..3c1f87b 100644 --- a/ppapi/c/ppb_file_mapping.h +++ b/ppapi/c/ppb_file_mapping.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* From ppb_file_mapping.idl modified Wed Jan 22 12:25:44 2014. */ +/* From ppb_file_mapping.idl modified Mon Jan 27 11:00:43 2014. */ #ifndef PPAPI_C_PPB_FILE_MAPPING_H_ #define PPAPI_C_PPB_FILE_MAPPING_H_ 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 9e7a8b6..b1cbbd8 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 @@ -421,14 +421,14 @@ static int32_t Pnacl_M34_PPB_FileMapping_Map(PP_Instance instance, PP_Resource f return iface->Map(instance, file_io, length, map_protection, map_flags, offset, address, *callback); } -static int32_t Pnacl_M34_PPB_FileMapping_Unmap(PP_Instance file_io, const void* address, int64_t length, struct PP_CompletionCallback* callback) { +static int32_t Pnacl_M34_PPB_FileMapping_Unmap(PP_Instance instance, const void* address, int64_t length, struct PP_CompletionCallback* callback) { const struct PPB_FileMapping_0_1 *iface = Pnacl_WrapperInfo_PPB_FileMapping_0_1.real_iface; - return iface->Unmap(file_io, address, length, *callback); + return iface->Unmap(instance, address, length, *callback); } -static int64_t Pnacl_M34_PPB_FileMapping_GetMapPageSize(PP_Instance file_io) { +static int64_t Pnacl_M34_PPB_FileMapping_GetMapPageSize(PP_Instance instance) { const struct PPB_FileMapping_0_1 *iface = Pnacl_WrapperInfo_PPB_FileMapping_0_1.real_iface; - return iface->GetMapPageSize(file_io); + return iface->GetMapPageSize(instance); } /* End wrapper methods for PPB_FileMapping_0_1 */ @@ -4231,8 +4231,8 @@ static struct PPB_FileIO_1_1 Pnacl_Wrappers_PPB_FileIO_1_1 = { static struct PPB_FileMapping_0_1 Pnacl_Wrappers_PPB_FileMapping_0_1 = { .Map = (int32_t (*)(PP_Instance instance, PP_Resource file_io, int64_t length, uint32_t map_protection, uint32_t map_flags, int64_t offset, void** address, struct PP_CompletionCallback callback))&Pnacl_M34_PPB_FileMapping_Map, - .Unmap = (int32_t (*)(PP_Instance file_io, const void* address, int64_t length, struct PP_CompletionCallback callback))&Pnacl_M34_PPB_FileMapping_Unmap, - .GetMapPageSize = (int64_t (*)(PP_Instance file_io))&Pnacl_M34_PPB_FileMapping_GetMapPageSize + .Unmap = (int32_t (*)(PP_Instance instance, const void* address, int64_t length, struct PP_CompletionCallback callback))&Pnacl_M34_PPB_FileMapping_Unmap, + .GetMapPageSize = (int64_t (*)(PP_Instance instance))&Pnacl_M34_PPB_FileMapping_GetMapPageSize }; static struct PPB_FileRef_1_0 Pnacl_Wrappers_PPB_FileRef_1_0 = { diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi index 1edd49a..fe357d7 100644 --- a/ppapi/ppapi_proxy.gypi +++ b/ppapi/ppapi_proxy.gypi @@ -39,8 +39,16 @@ 'proxy/extensions_common_resource.h', 'proxy/file_chooser_resource.cc', 'proxy/file_chooser_resource.h', + 'proxy/file_io_resource.cc', + 'proxy/file_io_resource.h', + 'proxy/file_mapping_resource.cc', + 'proxy/file_mapping_resource.h', + 'proxy/file_mapping_resource_posix.cc', + 'proxy/file_mapping_resource_win.cc', 'proxy/file_ref_resource.cc', 'proxy/file_ref_resource.h', + 'proxy/file_system_resource.cc', + 'proxy/file_system_resource.h', 'proxy/flash_clipboard_resource.cc', 'proxy/flash_clipboard_resource.h', 'proxy/flash_drm_resource.cc', @@ -55,10 +63,6 @@ 'proxy/flash_menu_resource.h', 'proxy/flash_resource.cc', 'proxy/flash_resource.h', - 'proxy/file_io_resource.cc', - 'proxy/file_io_resource.h', - 'proxy/file_system_resource.cc', - 'proxy/file_system_resource.h', 'proxy/gamepad_resource.cc', 'proxy/gamepad_resource.h', 'proxy/graphics_2d_resource.cc', diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi index eda3de1..926dc02 100644 --- a/ppapi/ppapi_shared.gypi +++ b/ppapi/ppapi_shared.gypi @@ -163,6 +163,7 @@ 'thunk/ppb_file_io_api.h', 'thunk/ppb_file_io_private_thunk.cc', 'thunk/ppb_file_io_thunk.cc', + 'thunk/ppb_file_mapping_thunk.cc', 'thunk/ppb_file_ref_api.h', 'thunk/ppb_file_ref_thunk.cc', 'thunk/ppb_file_system_api.h', diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi index c231418..6d78038 100644 --- a/ppapi/ppapi_sources.gypi +++ b/ppapi/ppapi_sources.gypi @@ -30,6 +30,7 @@ 'c/ppb_console.h', 'c/ppb_core.h', 'c/ppb_file_io.h', + 'c/ppb_file_mapping.h', 'c/ppb_file_ref.h', 'c/ppb_file_system.h', 'c/ppb_fullscreen.h', @@ -433,6 +434,8 @@ 'tests/test_empty.h', 'tests/test_file_io.cc', 'tests/test_file_io.h', + 'tests/test_file_mapping.cc', + 'tests/test_file_mapping.h', 'tests/test_file_ref.cc', 'tests/test_file_ref.h', 'tests/test_file_system.cc', diff --git a/ppapi/proxy/file_io_resource.h b/ppapi/proxy/file_io_resource.h index d6465fd..5d58035 100644 --- a/ppapi/proxy/file_io_resource.h +++ b/ppapi/proxy/file_io_resource.h @@ -69,7 +69,6 @@ class PPAPI_PROXY_EXPORT FileIOResource PP_FileHandle* handle, scoped_refptr<TrackedCallback> callback) OVERRIDE; - private: // FileHandleHolder is used to guarantee that file operations will have a // valid FD to operate on, even if they're in a different thread. // If instead we just passed the raw FD, the FD could be closed before the @@ -102,7 +101,11 @@ class PPAPI_PROXY_EXPORT FileIOResource ~FileHandleHolder(); PP_FileHandle raw_handle_; }; + scoped_refptr<FileHandleHolder> file_handle() { + return file_handle_; + } + private: // Class to perform file query operations across multiple threads. class QueryOp : public base::RefCountedThreadSafe<QueryOp> { public: diff --git a/ppapi/proxy/file_mapping_resource.cc b/ppapi/proxy/file_mapping_resource.cc new file mode 100644 index 0000000..5b18dbb --- /dev/null +++ b/ppapi/proxy/file_mapping_resource.cc @@ -0,0 +1,160 @@ +// Copyright 2014 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/proxy/file_mapping_resource.h" + +#include "base/bind.h" +#include "base/numerics/safe_conversions.h" +#include "base/task_runner_util.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_file_io_api.h" + +namespace ppapi { +namespace proxy { + +FileMappingResource::FileMappingResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance) { +} + +FileMappingResource::~FileMappingResource() { +} + +thunk::PPB_FileMapping_API* FileMappingResource::AsPPB_FileMapping_API() { + return this; +} + +int32_t FileMappingResource::Map(PP_Instance /* instance */, + PP_Resource file_io, + int64_t length, + uint32_t protection, + uint32_t flags, + int64_t offset, + void** address, + scoped_refptr<TrackedCallback> callback) { + thunk::EnterResourceNoLock<thunk::PPB_FileIO_API> enter(file_io, true); + if (enter.failed()) + return PP_ERROR_BADARGUMENT; + FileIOResource* file_io_resource = + static_cast<FileIOResource*>(enter.object()); + scoped_refptr<FileIOResource::FileHandleHolder> file_handle = + file_io_resource->file_handle(); + if (!FileIOResource::FileHandleHolder::IsValid(file_handle)) + return PP_ERROR_FAILED; + if (length < 0 || offset < 0 || + !base::IsValueInRangeForNumericType<off_t>(offset)) { + return PP_ERROR_BADARGUMENT; + } + if (!base::IsValueInRangeForNumericType<size_t>(length)) { + return PP_ERROR_NOMEMORY; + } + + // Ensure any bits we don't recognize are zero. + if (protection & + ~(PP_FILEMAPPROTECTION_READ | PP_FILEMAPPROTECTION_WRITE)) { + return PP_ERROR_BADARGUMENT; + } + if (flags & + ~(PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE | + PP_FILEMAPFLAG_FIXED)) { + return PP_ERROR_BADARGUMENT; + } + // Ensure at least one of SHARED and PRIVATE is set. + if (!(flags & (PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE))) + return PP_ERROR_BADARGUMENT; + // Ensure at most one of SHARED and PRIVATE is set. + if ((flags & PP_FILEMAPFLAG_SHARED) && + (flags & PP_FILEMAPFLAG_PRIVATE)) { + return PP_ERROR_BADARGUMENT; + } + if (!address) + return PP_ERROR_BADARGUMENT; + + base::Callback<MapResult()> map_cb( + base::Bind(&FileMappingResource::DoMapBlocking, file_handle, *address, + length, protection, flags, offset)); + if (callback->is_blocking()) { + // The plugin could release its reference to this instance when we release + // the proxy lock below. + scoped_refptr<FileMappingResource> protect(this); + MapResult map_result; + { + // Release the proxy lock while making a potentially slow file call. + ProxyAutoUnlock unlock; + map_result = map_cb.Run(); + } + OnMapCompleted(address, length, callback, map_result); + return map_result.result; + } else { + base::PostTaskAndReplyWithResult( + PpapiGlobals::Get()->GetFileTaskRunner(), + FROM_HERE, + map_cb, + RunWhileLocked(Bind(&FileMappingResource::OnMapCompleted, + this, + base::Unretained(address), + length, + callback))); + return PP_OK_COMPLETIONPENDING; + } +} + +int32_t FileMappingResource::Unmap(PP_Instance /* instance */, + const void* address, + int64_t length, + scoped_refptr<TrackedCallback> callback) { + if (!address) + return PP_ERROR_BADARGUMENT; + if (!base::IsValueInRangeForNumericType<size_t>(length)) + return PP_ERROR_BADARGUMENT; + + base::Callback<int32_t()> unmap_cb( + base::Bind(&FileMappingResource::DoUnmapBlocking, address, length)); + if (callback->is_blocking()) { + // Release the proxy lock while making a potentially slow file call. + ProxyAutoUnlock unlock; + return unmap_cb.Run(); + } else { + base::PostTaskAndReplyWithResult( + PpapiGlobals::Get()->GetFileTaskRunner(), + FROM_HERE, + unmap_cb, + RunWhileLocked(Bind(&TrackedCallback::Run, callback))); + return PP_OK_COMPLETIONPENDING; + } +} + +int64_t FileMappingResource::GetMapPageSize(PP_Instance /* instance */) { + return DoGetMapPageSize(); +} + +void FileMappingResource::OnMapCompleted( + void** mapped_address_out_param, + int64_t length, + scoped_refptr<TrackedCallback> callback, + const MapResult& map_result) { + if (callback->aborted()) { + if (map_result.result == PP_OK) { + // If the Map operation was successful, we need to Unmap to avoid leaks. + // The plugin won't get the address, so doesn't have a chance to do the + // Unmap. + PpapiGlobals::Get()->GetFileTaskRunner()->PostTask( + FROM_HERE, + base::Bind(base::IgnoreResult(&FileMappingResource::DoUnmapBlocking), + map_result.address, + length)); + } + return; + } + if (map_result.result == PP_OK) + *mapped_address_out_param = map_result.address; + if (!callback->is_blocking()) + callback->Run(map_result.result); +} + +} // namespace proxy +} // namespace ppapi diff --git a/ppapi/proxy/file_mapping_resource.h b/ppapi/proxy/file_mapping_resource.h new file mode 100644 index 0000000..240da21 --- /dev/null +++ b/ppapi/proxy/file_mapping_resource.h @@ -0,0 +1,77 @@ +// Copyright 2014 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 PPAPI_PROXY_FILE_MAPPING_RESOURCE_H_ +#define PPAPI_PROXY_FILE_MAPPING_RESOURCE_H_ + +#include "ppapi/proxy/file_io_resource.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/thunk/ppb_file_mapping_api.h" + +namespace ppapi { +namespace proxy { + +// The proxy-side resource for PPB_FileMapping. +class PPAPI_PROXY_EXPORT FileMappingResource + : public PluginResource, + public thunk::PPB_FileMapping_API { + public: + FileMappingResource(Connection connection, PP_Instance instance); + + private: + virtual ~FileMappingResource(); + + // Resource implementation. + virtual thunk::PPB_FileMapping_API* AsPPB_FileMapping_API() OVERRIDE; + + // PPB_FileMapping_API implementation. + virtual int32_t Map(PP_Instance instance, + PP_Resource file_io, + int64_t length, + uint32_t protection, + uint32_t flags, + int64_t offset, + void** address, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Unmap(PP_Instance instance, + const void* address, + int64_t length, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int64_t GetMapPageSize(PP_Instance instance) OVERRIDE; + + struct MapResult { + MapResult() : result(PP_ERROR_FAILED), address(NULL) { + } + int32_t result; + void* address; + }; + void OnMapCompleted(void** mapped_address_out_param, + int64_t length, + scoped_refptr<TrackedCallback> callback, + const MapResult& map_result); + + // These functions perform potentially blocking operations so they should not + // be called on the main thread or while we hold the proxy lock. Their + // implementation is platform specific. See file_mapping_resource_posix.cc and + // file_mapping_resource_win.cc. + static MapResult DoMapBlocking( + scoped_refptr<FileIOResource::FileHandleHolder> handle, + void* address_hint, + int64_t length, + uint32_t protection, + uint32_t flags, + int64_t offset); + static int32_t DoUnmapBlocking(const void* address, int64_t length); + // DoGetMapPageSize is platform-specific, but fast enough that we can call it + // on the main thread with the lock. + static int64_t DoGetMapPageSize(); + + DISALLOW_COPY_AND_ASSIGN(FileMappingResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_FILE_MAPPING_RESOURCE_H_ diff --git a/ppapi/proxy/file_mapping_resource_posix.cc b/ppapi/proxy/file_mapping_resource_posix.cc new file mode 100644 index 0000000..b1aff77 --- /dev/null +++ b/ppapi/proxy/file_mapping_resource_posix.cc @@ -0,0 +1,89 @@ +// Copyright 2014 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/proxy/file_mapping_resource.h" + +#include <stdio.h> +#include <sys/mman.h> +#include <unistd.h> + +#include "ppapi/c/pp_errors.h" + +namespace ppapi { +namespace proxy { + +namespace { + +int32_t ErrnoToPPError(int error_code) { + switch (error_code) { + case EACCES: + return PP_ERROR_NOACCESS; + case EAGAIN: + return PP_ERROR_NOMEMORY; + case EINVAL: + return PP_ERROR_BADARGUMENT; + case ENFILE: + case ENOMEM: + return PP_ERROR_NOMEMORY; + default: + return PP_ERROR_FAILED; + } +} + +} // namespace + +// static +FileMappingResource::MapResult FileMappingResource::DoMapBlocking( + scoped_refptr<FileIOResource::FileHandleHolder> handle, + void* address_hint, + int64_t length, + uint32_t map_protection, + uint32_t map_flags, + int64_t offset) { + int prot_for_mmap = 0; + if (map_protection & PP_FILEMAPPROTECTION_READ) + prot_for_mmap |= PROT_READ; + if (map_protection & PP_FILEMAPPROTECTION_WRITE) + prot_for_mmap |= PROT_WRITE; + if (prot_for_mmap == 0) + prot_for_mmap = PROT_NONE; + + int flags_for_mmap = 0; + if (map_flags & PP_FILEMAPFLAG_SHARED) + flags_for_mmap |= MAP_SHARED; + if (map_flags & PP_FILEMAPFLAG_PRIVATE) + flags_for_mmap |= MAP_PRIVATE; + if (map_flags & PP_FILEMAPFLAG_FIXED) + flags_for_mmap |= MAP_FIXED; + + MapResult map_result; + map_result.address = + mmap(address_hint, + static_cast<size_t>(length), + prot_for_mmap, + flags_for_mmap, + handle->raw_handle(), + static_cast<off_t>(offset)); + if (map_result.address != MAP_FAILED) + map_result.result = PP_OK; + else + map_result.result = ErrnoToPPError(errno); + return map_result; +} + +// static +int32_t FileMappingResource::DoUnmapBlocking(const void* address, + int64_t length) { + if (munmap(const_cast<void*>(address), static_cast<size_t>(length))) + return ErrnoToPPError(errno); + return PP_OK; +} + +// static +int64_t FileMappingResource::DoGetMapPageSize() { + return getpagesize(); +} + +} // namespace proxy +} // namespace ppapi diff --git a/ppapi/proxy/file_mapping_resource_win.cc b/ppapi/proxy/file_mapping_resource_win.cc new file mode 100644 index 0000000..70c3d20 --- /dev/null +++ b/ppapi/proxy/file_mapping_resource_win.cc @@ -0,0 +1,40 @@ +// Copyright 2014 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/proxy/file_mapping_resource.h" + +#include "ppapi/c/pp_errors.h" + +namespace ppapi { +namespace proxy { + +// static +FileMappingResource::MapResult FileMappingResource::DoMapBlocking( + scoped_refptr<FileIOResource::FileHandleHolder> handle, + void* address_hint, + int64_t length, + uint32_t map_protection, + uint32_t map_flags, + int64_t offset) { + // TODO(dmichael): Implement for Windows (crbug.com/83774). + MapResult map_result; + map_result.result = PP_ERROR_NOTSUPPORTED; + return map_result; +} + +// static +int32_t FileMappingResource::DoUnmapBlocking(const void* address, + int64_t length) { + // TODO(dmichael): Implement for Windows (crbug.com/83774). + return PP_ERROR_NOTSUPPORTED; +} + +// static +int64_t FileMappingResource::DoGetMapPageSize() { + // TODO(dmichael): Implement for Windows (crbug.com/83774). + return 0; +} + +} // namespace proxy +} // namespace ppapi diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc index 4044b27b..79789d7 100644 --- a/ppapi/proxy/interface_list.cc +++ b/ppapi/proxy/interface_list.cc @@ -35,6 +35,7 @@ #include "ppapi/c/ppb_console.h" #include "ppapi/c/ppb_core.h" #include "ppapi/c/ppb_file_io.h" +#include "ppapi/c/ppb_file_mapping.h" #include "ppapi/c/ppb_file_ref.h" #include "ppapi/c/ppb_file_system.h" #include "ppapi/c/ppb_fullscreen.h" diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc index 6429f50..80715ad 100644 --- a/ppapi/proxy/ppb_instance_proxy.cc +++ b/ppapi/proxy/ppb_instance_proxy.cc @@ -19,6 +19,7 @@ #include "ppapi/proxy/content_decryptor_private_serializer.h" #include "ppapi/proxy/enter_proxy.h" #include "ppapi/proxy/extensions_common_resource.h" +#include "ppapi/proxy/file_mapping_resource.h" #include "ppapi/proxy/flash_clipboard_resource.h" #include "ppapi/proxy/flash_file_resource.h" #include "ppapi/proxy/flash_fullscreen_resource.h" @@ -363,6 +364,9 @@ Resource* PPB_Instance_Proxy::GetSingletonResource(PP_Instance instance, case EXTENSIONS_COMMON_SINGLETON_ID: new_singleton = new ExtensionsCommonResource(connection, instance); break; + case FILE_MAPPING_SINGLETON_ID: + new_singleton = new FileMappingResource(connection, instance); + break; case GAMEPAD_SINGLETON_ID: new_singleton = new GamepadResource(connection, instance); break; diff --git a/ppapi/shared_impl/resource.h b/ppapi/shared_impl/resource.h index 8d15cd2..8446f92 100644 --- a/ppapi/shared_impl/resource.h +++ b/ppapi/shared_impl/resource.h @@ -34,6 +34,7 @@ F(PPB_Ext_CrxFileSystem_Private_API) \ F(PPB_FileChooser_API) \ F(PPB_FileIO_API) \ + F(PPB_FileMapping_API) \ F(PPB_FileRef_API) \ F(PPB_FileSystem_API) \ F(PPB_Find_API) \ diff --git a/ppapi/shared_impl/singleton_resource_id.h b/ppapi/shared_impl/singleton_resource_id.h index 1094c69..6441a2b 100644 --- a/ppapi/shared_impl/singleton_resource_id.h +++ b/ppapi/shared_impl/singleton_resource_id.h @@ -16,6 +16,7 @@ enum SingletonResourceID { BROKER_SINGLETON_ID, BROWSER_FONT_SINGLETON_ID, EXTENSIONS_COMMON_SINGLETON_ID, + FILE_MAPPING_SINGLETON_ID, FLASH_CLIPBOARD_SINGLETON_ID, FLASH_FILE_SINGLETON_ID, FLASH_FULLSCREEN_SINGLETON_ID, diff --git a/ppapi/tests/all_c_includes.h b/ppapi/tests/all_c_includes.h index 12da721..47a3d7d 100644 --- a/ppapi/tests/all_c_includes.h +++ b/ppapi/tests/all_c_includes.h @@ -69,6 +69,7 @@ #include "ppapi/c/ppb_console.h" #include "ppapi/c/ppb_core.h" #include "ppapi/c/ppb_file_io.h" +#include "ppapi/c/ppb_file_mapping.h" #include "ppapi/c/ppb_file_ref.h" #include "ppapi/c/ppb_file_system.h" #include "ppapi/c/ppb_fullscreen.h" diff --git a/ppapi/tests/test_file_mapping.cc b/ppapi/tests/test_file_mapping.cc new file mode 100644 index 0000000..8781a33 --- /dev/null +++ b/ppapi/tests/test_file_mapping.cc @@ -0,0 +1,540 @@ +// Copyright 2014 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/tests/test_file_mapping.h" + +#include <string.h> + +#include <limits> +#include <string> + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_file_io.h" +#include "ppapi/c/ppb_file_mapping.h" +#include "ppapi/cpp/file_io.h" +#include "ppapi/cpp/file_ref.h" +#include "ppapi/cpp/file_system.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" +#include "ppapi/tests/test_utils.h" + +REGISTER_TEST_CASE(FileMapping); + +namespace { + +// TODO(dmichael): Move these to test_utils so we can share them? +int32_t ReadEntireFile(PP_Instance instance, + pp::FileIO* file_io, + int32_t offset, + std::string* data, + CallbackType callback_type) { + TestCompletionCallback callback(instance, callback_type); + char buf[256]; + int32_t read_offset = offset; + + for (;;) { + callback.WaitForResult( + file_io->Read(read_offset, buf, sizeof(buf), callback.GetCallback())); + if (callback.result() < 0) + return callback.result(); + if (callback.result() == 0) + break; + read_offset += callback.result(); + data->append(buf, callback.result()); + } + + return PP_OK; +} + +int32_t WriteEntireBuffer(PP_Instance instance, + pp::FileIO* file_io, + int32_t offset, + const std::string& data, + CallbackType callback_type) { + TestCompletionCallback callback(instance, callback_type); + int32_t write_offset = offset; + const char* buf = data.c_str(); + int32_t size = data.size(); + + while (write_offset < offset + size) { + callback.WaitForResult(file_io->Write(write_offset, + &buf[write_offset - offset], + size - write_offset + offset, + callback.GetCallback())); + if (callback.result() < 0) + return callback.result(); + if (callback.result() == 0) + return PP_ERROR_FAILED; + write_offset += callback.result(); + } + callback.WaitForResult(file_io->Flush(callback.GetCallback())); + return callback.result(); +} + +} // namespace + +std::string TestFileMapping::MapAndCheckResults(uint32_t prot, + uint32_t flags) { + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + + pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); + pp::FileRef file_ref(file_system, "/mapped_file"); + + callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); + ASSERT_EQ(PP_OK, callback.result()); + + const int64_t page_size = + file_mapping_if_->GetMapPageSize(instance_->pp_instance()); + const int64_t kNumPages = 4; + // Make a string that's big enough that it spans all of the first |n-1| pages, + // plus a little bit of the |nth| page. + std::string file_contents((page_size * (kNumPages - 1)) + 128, 'a'); + + pp::FileIO file_io(instance_); + callback.WaitForResult(file_io.Open(file_ref, + PP_FILEOPENFLAG_CREATE | + PP_FILEOPENFLAG_TRUNCATE | + PP_FILEOPENFLAG_READ | + PP_FILEOPENFLAG_WRITE, + callback.GetCallback())); + ASSERT_EQ(PP_OK, callback.result()); + ASSERT_EQ(PP_OK, WriteEntireBuffer(instance_->pp_instance(), + &file_io, + 0, + file_contents, + callback_type())); + + // TODO(dmichael): Use C++ interface. + void* address = NULL; + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io.pp_resource(), + kNumPages * page_size, + prot, + flags, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + ASSERT_NE(NULL, address); + + if (prot & PP_FILEMAPPROTECTION_READ) { + // Make sure we can read. + std::string mapped_data(static_cast<char*>(address), file_contents.size()); + // The initial data should match. + ASSERT_EQ(file_contents, mapped_data); + + // Now write some data and flush it. + const std::string file_contents2(file_contents.size(), 'x'); + ASSERT_EQ(PP_OK, WriteEntireBuffer(instance_->pp_instance(), + &file_io, + 0, + file_contents2, + callback_type())); + // If the region was mapped SHARED, it should get updated. + std::string mapped_data2(static_cast<char*>(address), file_contents.size()); + if (flags & PP_FILEMAPFLAG_SHARED) + ASSERT_EQ(file_contents2, mapped_data2); + // In POSIX, it is unspecified in the PRIVATE case whether changes to the + // file are visible to the mapped region. So we can't really test anything + // here in that case. + // TODO(dmichael): Make sure our Pepper documentation reflects this. + } + if (prot & PP_FILEMAPPROTECTION_WRITE) { + std::string old_file_contents; + ASSERT_EQ(PP_OK, ReadEntireFile(instance_->pp_instance(), + &file_io, + 0, + &old_file_contents, + callback_type())); + // Write something else to the mapped region, then unmap, and see if it + // gets written to the file. (Note we have to Unmap to make sure that the + // write is committed). + memset(address, 'y', file_contents.size()); + // Note, we might not have read access to the mapped region here, so we + // make a string with the same contents without actually reading. + std::string mapped_data3(file_contents.size(), 'y'); + callback.WaitForResult( + file_mapping_if_->Unmap( + instance_->pp_instance(), address, file_contents.size(), + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + std::string new_file_contents; + ASSERT_EQ(PP_OK, ReadEntireFile(instance_->pp_instance(), + &file_io, + 0, + &new_file_contents, + callback_type())); + + // Sanity-check that the data we wrote isn't the same as what was already + // there, otherwise our test is invalid. + ASSERT_NE(mapped_data3, old_file_contents); + // If it's SHARED, the file should match what we wrote to the mapped region. + // Otherwise, it should not have changed. + if (flags & PP_FILEMAPFLAG_SHARED) + ASSERT_EQ(mapped_data3, new_file_contents); + else + ASSERT_EQ(old_file_contents, new_file_contents); + } else { + // We didn't do the "WRITE" test, but we still want to Unmap. + callback.WaitForResult( + file_mapping_if_->Unmap( + instance_->pp_instance(), address, file_contents.size(), + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + } + PASS(); +} + +bool TestFileMapping::Init() { + // TODO(dmichael): Use unversioned string when this goes to stable? + file_mapping_if_ = static_cast<const PPB_FileMapping_0_1*>( + pp::Module::Get()->GetBrowserInterface(PPB_FILEMAPPING_INTERFACE_0_1)); + return !!file_mapping_if_ && CheckTestingInterface() && + EnsureRunningOverHTTP(); +} + +void TestFileMapping::RunTests(const std::string& filter) { + RUN_CALLBACK_TEST(TestFileMapping, BadParameters, filter); + RUN_CALLBACK_TEST(TestFileMapping, Map, filter); + RUN_CALLBACK_TEST(TestFileMapping, PartialRegions, filter); +} + +std::string TestFileMapping::TestBadParameters() { + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + + pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); + pp::FileRef file_ref(file_system, "/mapped_file"); + + callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); + ASSERT_EQ(PP_OK, callback.result()); + + const int64_t page_size = + file_mapping_if_->GetMapPageSize(instance_->pp_instance()); + // const int64_t kNumPages = 4; + // Make a string that's big enough that it spans 3 pages, plus a little extra. + //std::string file_contents((page_size * (kNumPages - 1)) + 128, 'a'); + std::string file_contents(page_size, 'a'); + + pp::FileIO file_io(instance_); + callback.WaitForResult(file_io.Open(file_ref, + PP_FILEOPENFLAG_CREATE | + PP_FILEOPENFLAG_TRUNCATE | + PP_FILEOPENFLAG_READ | + PP_FILEOPENFLAG_WRITE, + callback.GetCallback())); + ASSERT_EQ(PP_OK, callback.result()); + ASSERT_EQ(PP_OK, WriteEntireBuffer(instance_->pp_instance(), + &file_io, + 0, + file_contents, + callback_type())); + + // Bad instance. + void* address = NULL; + callback.WaitForResult( + file_mapping_if_->Map( + PP_Instance(0xbadbad), + file_io.pp_resource(), + page_size, + PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_PRIVATE, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + ASSERT_EQ(NULL, address); + + // Bad resource. + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + PP_Resource(0xbadbad), + page_size, + PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_PRIVATE, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + ASSERT_EQ(NULL, address); + + // Length too big. + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io.pp_resource(), + std::numeric_limits<int64_t>::max(), + PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_PRIVATE, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_NOMEMORY, callback.result()); + ASSERT_EQ(NULL, address); + + // Length too small. + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io.pp_resource(), + -1, + PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_PRIVATE, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + ASSERT_EQ(NULL, address); + // TODO(dmichael): Check & test length that is not a multiple of page size??? + + // Bad protection. + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io.pp_resource(), + page_size, + ~PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_PRIVATE, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + ASSERT_EQ(NULL, address); + + // No flags. + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io.pp_resource(), + page_size, + PP_FILEMAPPROTECTION_READ, + 0, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + ASSERT_EQ(NULL, address); + + // Both flags. + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io.pp_resource(), + page_size, + PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + ASSERT_EQ(NULL, address); + + // Bad flags. + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io.pp_resource(), + page_size, + PP_FILEMAPPROTECTION_READ, + ~PP_FILEMAPFLAG_SHARED, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + ASSERT_EQ(NULL, address); + + // Bad offset; not a multiple of page size. + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io.pp_resource(), + page_size, + PP_FILEMAPPROTECTION_READ, + ~PP_FILEMAPFLAG_SHARED, + 1, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + ASSERT_EQ(NULL, address); + + // Unmap NULL. + callback.WaitForResult( + file_mapping_if_->Unmap( + instance_->pp_instance(), + NULL, + page_size, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + + // Unmap bad address. + callback.WaitForResult( + file_mapping_if_->Unmap( + instance_->pp_instance(), + reinterpret_cast<const void*>(0xdeadbeef), + page_size, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); + + PASS(); +} + +std::string TestFileMapping::TestMap() { + ASSERT_SUBTEST_SUCCESS(MapAndCheckResults(PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_SHARED)); + ASSERT_SUBTEST_SUCCESS(MapAndCheckResults(PP_FILEMAPPROTECTION_WRITE, + PP_FILEMAPFLAG_SHARED)); + ASSERT_SUBTEST_SUCCESS( + MapAndCheckResults(PP_FILEMAPPROTECTION_WRITE | PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_SHARED)); + ASSERT_SUBTEST_SUCCESS(MapAndCheckResults(PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_PRIVATE)); + ASSERT_SUBTEST_SUCCESS(MapAndCheckResults(PP_FILEMAPPROTECTION_WRITE, + PP_FILEMAPFLAG_PRIVATE)); + ASSERT_SUBTEST_SUCCESS( + MapAndCheckResults(PP_FILEMAPPROTECTION_WRITE | PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_PRIVATE)); + PASS(); +} + +std::string TestFileMapping::TestPartialRegions() { + TestCompletionCallback callback(instance_->pp_instance(), callback_type()); + + pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); + pp::FileRef file_ref1(file_system, "/mapped_file1"); + pp::FileRef file_ref2(file_system, "/mapped_file2"); + + callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); + ASSERT_EQ(PP_OK, callback.result()); + + const int64_t page_size = + file_mapping_if_->GetMapPageSize(instance_->pp_instance()); + const int64_t kNumPages = 3; + std::string file_contents1(kNumPages * page_size, 'a'); + + pp::FileIO file_io1(instance_); + callback.WaitForResult(file_io1.Open(file_ref1, + PP_FILEOPENFLAG_CREATE | + PP_FILEOPENFLAG_TRUNCATE | + PP_FILEOPENFLAG_READ | + PP_FILEOPENFLAG_WRITE, + callback.GetCallback())); + ASSERT_EQ(PP_OK, callback.result()); + ASSERT_EQ(PP_OK, WriteEntireBuffer(instance_->pp_instance(), + &file_io1, + 0, + file_contents1, + callback_type())); + + // TODO(dmichael): Use C++ interface. + void* address = NULL; + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io1.pp_resource(), + kNumPages * page_size, + PP_FILEMAPPROTECTION_WRITE | PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_SHARED, + 0, + &address, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + ASSERT_NE(NULL, address); + + // Unmap only the middle page. + void* address_of_middle_page = + reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(address) + page_size); + callback.WaitForResult( + file_mapping_if_->Unmap( + instance_->pp_instance(), + address_of_middle_page, + page_size, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + + // Write another file, map it in to the middle hole that was left above. + pp::FileIO file_io2(instance_); + callback.WaitForResult(file_io2.Open(file_ref2, + PP_FILEOPENFLAG_CREATE | + PP_FILEOPENFLAG_TRUNCATE | + PP_FILEOPENFLAG_READ | + PP_FILEOPENFLAG_WRITE, + callback.GetCallback())); + ASSERT_EQ(PP_OK, callback.result()); + // This second file will have 1 page worth of data. + std::string file_contents2(page_size, 'b'); + ASSERT_EQ(PP_OK, WriteEntireBuffer(instance_->pp_instance(), + &file_io2, + 0, + file_contents2, + callback_type())); + callback.WaitForResult( + file_mapping_if_->Map( + instance_->pp_instance(), + file_io2.pp_resource(), + page_size, + PP_FILEMAPPROTECTION_WRITE | PP_FILEMAPPROTECTION_READ, + PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_FIXED, + 0, + &address_of_middle_page, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + PASS(); + + // Write something else to the mapped region, then unmap, and see if it + // gets written to both files. (Note we have to Unmap to make sure that the + // write is committed). + memset(address, 'c', kNumPages * page_size); + callback.WaitForResult( + file_mapping_if_->Unmap( + instance_->pp_instance(), address, kNumPages * page_size, + callback.GetCallback().pp_completion_callback())); + CHECK_CALLBACK_BEHAVIOR(callback); + ASSERT_EQ(PP_OK, callback.result()); + // The first and third page should have been written with 'c', but the + // second page should be untouched. + std::string expected_file_contents1 = std::string(page_size, 'c') + + std::string(page_size, 'a') + + std::string(page_size, 'c'); + std::string new_file_contents1; + ASSERT_EQ(PP_OK, ReadEntireFile(instance_->pp_instance(), + &file_io1, + 0, + &new_file_contents1, + callback_type())); + ASSERT_EQ(expected_file_contents1, new_file_contents1); + + // The second file should have been entirely over-written. + std::string expected_file_contents2 = std::string(page_size, 'c'); + std::string new_file_contents2; + ASSERT_EQ(PP_OK, ReadEntireFile(instance_->pp_instance(), + &file_io2, + 0, + &new_file_contents2, + callback_type())); + ASSERT_EQ(expected_file_contents2, new_file_contents2); + + // TODO(dmichael): Test non-zero offset + + PASS(); +} + diff --git a/ppapi/tests/test_file_mapping.h b/ppapi/tests/test_file_mapping.h new file mode 100644 index 0000000..bb83d26 --- /dev/null +++ b/ppapi/tests/test_file_mapping.h @@ -0,0 +1,37 @@ +// Copyright 2014 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 PAPPI_TESTS_TEST_FILE_MAPPING_H_ +#define PAPPI_TESTS_TEST_FILE_MAPPING_H_ + +#include <string> + +#include "ppapi/tests/test_case.h" + +struct PPB_FileMapping_0_1; + +class TestFileMapping : public TestCase { + public: + explicit TestFileMapping(TestingInstance* instance) + : TestCase(instance), + file_mapping_if_(NULL) { + } + virtual ~TestFileMapping() {} + + private: + // TestCase implementation. + virtual bool Init(); + virtual void RunTests(const std::string& filter); + + std::string MapAndCheckResults(uint32_t prot, uint32_t flags); + + std::string TestBadParameters(); + std::string TestMap(); + std::string TestPartialRegions(); + + // TODO(dmichael): Use unversioned struct when it goes stable. + const PPB_FileMapping_0_1* file_mapping_if_; +}; + +#endif // PAPPI_TESTS_TEST_FILE_MAPPING_H_ diff --git a/ppapi/thunk/enter.cc b/ppapi/thunk/enter.cc index 2adc7f2..03937c9b 100644 --- a/ppapi/thunk/enter.cc +++ b/ppapi/thunk/enter.cc @@ -59,7 +59,6 @@ EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id, const PP_CompletionCallback& callback) : resource_(GetSingletonResource(instance, resource_id)), retval_(PP_OK) { - DCHECK(resource_ || !instance); if (!resource_) retval_ = PP_ERROR_BADARGUMENT; callback_ = new TrackedCallback(resource_, callback); diff --git a/ppapi/thunk/interfaces_ppb_public_dev_channel.h b/ppapi/thunk/interfaces_ppb_public_dev_channel.h index 34e5de4..7269c4e 100644 --- a/ppapi/thunk/interfaces_ppb_public_dev_channel.h +++ b/ppapi/thunk/interfaces_ppb_public_dev_channel.h @@ -9,6 +9,7 @@ // Interfaces go here. PROXIED_IFACE(PPB_AUDIOFRAME_INTERFACE_0_1, PPB_AudioFrame_0_1) +PROXIED_IFACE(PPB_FILEMAPPING_INTERFACE_0_1, PPB_FileMapping_0_1) PROXIED_IFACE(PPB_FILEREF_INTERFACE_1_2, PPB_FileRef_1_2) PROXIED_IFACE(PPB_MEDIASTREAMAUDIOTRACK_INTERFACE_0_1, PPB_MediaStreamAudioTrack_0_1) diff --git a/ppapi/thunk/ppb_file_mapping_api.h b/ppapi/thunk/ppb_file_mapping_api.h new file mode 100644 index 0000000..530d04b --- /dev/null +++ b/ppapi/thunk/ppb_file_mapping_api.h @@ -0,0 +1,46 @@ +// Copyright 2014 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 PPAPI_THUNK_PPB_FILE_MAPPING_API_H_ +#define PPAPI_THUNK_PPB_FILE_MAPPING_API_H_ + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/ppb_file_mapping.h" +#include "ppapi/shared_impl/singleton_resource_id.h" +#include "ppapi/thunk/ppapi_thunk_export.h" + +namespace ppapi { + +class TrackedCallback; + +namespace thunk { + +class PPAPI_THUNK_EXPORT PPB_FileMapping_API { + public: + virtual ~PPB_FileMapping_API() {} + + virtual int32_t Map(PP_Instance instance, + PP_Resource file_io, + int64_t length, + uint32_t map_protection, + uint32_t map_flags, + int64_t offset, + void** address, + scoped_refptr<TrackedCallback> callback) = 0; + virtual int32_t Unmap(PP_Instance instance, + const void* address, + int64_t length, + scoped_refptr<TrackedCallback> callback) = 0; + virtual int64_t GetMapPageSize(PP_Instance instance) = 0; + + static const SingletonResourceID kSingletonResourceID = + FILE_MAPPING_SINGLETON_ID; +}; + +} // namespace thunk +} // namespace ppapi + +#endif // PPAPI_THUNK_PPB_FILE_MAPPING_API_H_ diff --git a/ppapi/thunk/ppb_file_mapping_thunk.cc b/ppapi/thunk/ppb_file_mapping_thunk.cc new file mode 100644 index 0000000..bdf29ca --- /dev/null +++ b/ppapi/thunk/ppb_file_mapping_thunk.cc @@ -0,0 +1,77 @@ +// Copyright 2014 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. + +// From ppb_file_mapping.idl modified Mon Jan 27 11:00:43 2014. + +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_file_mapping.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppapi_thunk_export.h" +#include "ppapi/thunk/ppb_file_mapping_api.h" + +namespace ppapi { +namespace thunk { + +namespace { + +int32_t Map(PP_Instance instance, + PP_Resource file_io, + int64_t length, + uint32_t map_protection, + uint32_t map_flags, + int64_t offset, + void** address, + struct PP_CompletionCallback callback) { + VLOG(4) << "PPB_FileMapping::Map()"; + EnterInstanceAPI<PPB_FileMapping_API> enter(instance, callback); + if (enter.failed()) + return enter.retval(); + return enter.SetResult(enter.functions()->Map(instance, + file_io, + length, + map_protection, + map_flags, + offset, + address, + enter.callback())); +} + +int32_t Unmap(PP_Instance instance, + const void* address, + int64_t length, + struct PP_CompletionCallback callback) { + VLOG(4) << "PPB_FileMapping::Unmap()"; + EnterInstanceAPI<PPB_FileMapping_API> enter(instance, callback); + if (enter.failed()) + return enter.retval(); + return enter.SetResult(enter.functions()->Unmap(instance, + address, + length, + enter.callback())); +} + +int64_t GetMapPageSize(PP_Instance instance) { + VLOG(4) << "PPB_FileMapping::GetMapPageSize()"; + EnterInstanceAPI<PPB_FileMapping_API> enter(instance); + if (enter.failed()) + return 0; + return enter.functions()->GetMapPageSize(instance); +} + +const PPB_FileMapping_0_1 g_ppb_filemapping_thunk_0_1 = { + &Map, + &Unmap, + &GetMapPageSize +}; + +} // namespace + +PPAPI_THUNK_EXPORT const PPB_FileMapping_0_1* GetPPB_FileMapping_0_1_Thunk() { + return &g_ppb_filemapping_thunk_0_1; +} + +} // namespace thunk +} // namespace ppapi |