summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
authordmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-29 00:49:51 +0000
committerdmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-29 00:49:51 +0000
commitf54329e5d6a76858c67869e678f9462a964632b7 (patch)
tree4b92fd9b8111a157a4b66049aedf673c0856dfc9 /ppapi
parent0be9392b7cc037c74baa929bc384baf36b0001f3 (diff)
downloadchromium_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
Diffstat (limited to 'ppapi')
-rw-r--r--ppapi/api/ppb_file_mapping.idl2
-rw-r--r--ppapi/c/ppb_file_mapping.h2
-rw-r--r--ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c12
-rw-r--r--ppapi/ppapi_proxy.gypi12
-rw-r--r--ppapi/ppapi_shared.gypi1
-rw-r--r--ppapi/ppapi_sources.gypi3
-rw-r--r--ppapi/proxy/file_io_resource.h5
-rw-r--r--ppapi/proxy/file_mapping_resource.cc160
-rw-r--r--ppapi/proxy/file_mapping_resource.h77
-rw-r--r--ppapi/proxy/file_mapping_resource_posix.cc89
-rw-r--r--ppapi/proxy/file_mapping_resource_win.cc40
-rw-r--r--ppapi/proxy/interface_list.cc1
-rw-r--r--ppapi/proxy/ppb_instance_proxy.cc4
-rw-r--r--ppapi/shared_impl/resource.h1
-rw-r--r--ppapi/shared_impl/singleton_resource_id.h1
-rw-r--r--ppapi/tests/all_c_includes.h1
-rw-r--r--ppapi/tests/test_file_mapping.cc540
-rw-r--r--ppapi/tests/test_file_mapping.h37
-rw-r--r--ppapi/thunk/enter.cc1
-rw-r--r--ppapi/thunk/interfaces_ppb_public_dev_channel.h1
-rw-r--r--ppapi/thunk/ppb_file_mapping_api.h46
-rw-r--r--ppapi/thunk/ppb_file_mapping_thunk.cc77
22 files changed, 1100 insertions, 13 deletions
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