Index: ppapi/proxy/file_mapping_resource.cc |
diff --git a/ppapi/proxy/file_mapping_resource.cc b/ppapi/proxy/file_mapping_resource.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6308286c2ac56f63e8fbee94fdb2ac6f0aecf346 |
--- /dev/null |
+++ b/ppapi/proxy/file_mapping_resource.cc |
@@ -0,0 +1,240 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
teravest
2014/01/23 21:40:58
boring nit: 2014 :(
dmichael (off chromium)
2014/01/24 20:02:50
Done.
|
+// 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" |
+ |
+#if defined(OS_POSIX) |
teravest
2014/01/23 21:40:58
It would be cool if there was an abstraction you c
dmichael (off chromium)
2014/01/24 20:02:50
Yeah... I had already considered it, and was thin
|
+#include <stdio.h> |
+#include <sys/mman.h> |
+#include <unistd.h> |
+#endif |
+ |
+#include <limits> |
+ |
+#include "base/bind.h" |
+#include "base/numerics/safe_conversions.h" |
+#include "base/task_runner_util.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 { |
+ |
+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; |
+ } |
+} |
+ |
+} |
+ |
+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 map_protection, |
+ uint32_t map_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_BADARGUMENT; |
bbudge
2014/01/23 23:01:03
Kind of a gray area, but this could also be PP_ERR
dmichael (off chromium)
2014/01/24 20:02:50
I think of PP_ERROR_FAILED as a more generic, "we
bbudge
2014/01/24 21:41:21
In retrospect, we should probably have defined a P
dmichael (off chromium)
2014/01/24 22:05:13
Okay, I'm convinced. Done.
|
+ if (length < 0 || offset < 0) |
+ return PP_ERROR_BADARGUMENT; |
+ if (!base::IsValueInRangeForNumericType<size_t>(length)) |
+ return PP_ERROR_NOMEMORY; |
teravest
2014/01/23 21:40:58
I'd argue that this should be BADARGUMENT. But eit
dmichael (off chromium)
2014/01/24 20:02:50
This is for platform consistency. On 64-bit, value
|
+ if (!base::IsValueInRangeForNumericType<off_t>(offset)) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ // Ensure no bits that we don't recognize are set. |
+ if (map_protection & |
+ ~(PP_FILEMAPPROTECTION_READ | PP_FILEMAPPROTECTION_WRITE)) { |
+ return PP_ERROR_BADARGUMENT; |
+ } |
+ if (map_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 (!(map_flags & (PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE))) |
+ return PP_ERROR_BADARGUMENT; |
+ // Ensure at most one of SHARED and PRIVATE is set. |
+ if ((map_flags & PP_FILEMAPFLAG_SHARED) && |
+ (map_flags & PP_FILEMAPFLAG_PRIVATE)) { |
+ return PP_ERROR_BADARGUMENT; |
+ } |
+ if (!address) |
+ return PP_ERROR_BADARGUMENT; |
+ |
+ base::Callback<MapResult()> map_op( |
bbudge
2014/01/24 21:41:21
Maybe a better name is map_task or map_cb?
Same fo
|
+ base::Bind(&FileMappingResource::DoMap, file_handle, *address, length, |
+ map_protection, map_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_op.Run(); |
+ } |
+ OnMapCompleted(address, callback, map_result); |
+ return map_result.result; |
+ } else { |
+ base::PostTaskAndReplyWithResult( |
+ PpapiGlobals::Get()->GetFileTaskRunner(), |
+ FROM_HERE, |
+ map_op, |
+ RunWhileLocked(Bind(&FileMappingResource::OnMapCompleted, |
+ this, |
+ base::Unretained(address), |
+ 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_op( |
+ base::Bind(&FileMappingResource::DoUnmap, address, length)); |
+ if (callback->is_blocking()) { |
+ // Release the proxy lock while making a potentially slow file call. |
+ ProxyAutoUnlock unlock; |
+ return unmap_op.Run(); |
+ } else { |
+ base::PostTaskAndReplyWithResult( |
+ PpapiGlobals::Get()->GetFileTaskRunner(), |
+ FROM_HERE, |
+ unmap_op, |
+ RunWhileLocked(Bind(&TrackedCallback::Run, callback))); |
+ return PP_OK_COMPLETIONPENDING; |
+ } |
+} |
+ |
+int64_t FileMappingResource::GetMapPageSize(PP_Instance /* instance */) { |
+ // TODO(dmichael): It might be better to port sys_info_posix.cc to NaCl and |
+ // call Sysinfo::VMAllocationGranularity. |
+#if defined(OS_POSIX) |
+ return getpagesize(); |
+#else // defined(OS_POSIX) |
+ NOTREACHED(); |
bbudge
2014/01/23 23:01:03
NOTIMPLEMENTED()?
dmichael (off chromium)
2014/01/24 20:02:50
Oops, the other Windows functions just return PP_E
bbudge
2014/01/24 21:41:21
No big deal.
|
+ return 0; |
+#endif |
+} |
+ |
+// static |
+FileMappingResource::MapResult FileMappingResource::DoMap( |
+ scoped_refptr<FileIOResource::FileHandleHolder> handle, |
+ void* address_hint, |
+ int64_t length, |
+ uint32_t map_protection, |
+ uint32_t map_flags, |
+ int64_t offset) { |
+#if defined(OS_POSIX) |
+ 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); |
bbudge
2014/01/23 23:01:03
nit: Seems like you could access this inside Errno
dmichael (off chromium)
2014/01/24 20:02:50
Yeah... I thought about that, but I already hate
bbudge
2014/01/24 21:41:21
OK
|
+ return map_result; |
+#else // defined(OS_POSIX) |
+ // TODO(dmichael): Implement for Windows (crbug.com/83774). |
+ MapResult map_result; |
+ map_result.result = PP_ERROR_NOTSUPPORTED; |
+ return map_result; |
+#endif |
+} |
+ |
+void FileMappingResource::OnMapCompleted( |
+ void** mapped_address_out_param, |
+ scoped_refptr<TrackedCallback> callback, |
+ const MapResult& map_result) { |
+ // TODO(dmichael): If the callback is aborted, should we unmap? |
teravest
2014/01/23 21:40:58
I think we should unmap when the callback is abort
dmichael (off chromium)
2014/01/24 20:02:50
Good point... they do get a PP_ERROR_ABORTED callb
|
+ if (callback->aborted()) |
+ return; |
+ if (map_result.result == 0) |
bbudge
2014/01/23 23:01:03
Since this is logically a PP_Error, PP_OK?
dmichael (off chromium)
2014/01/24 20:02:50
Done.
|
+ *mapped_address_out_param = map_result.address; |
+ if (!callback->is_blocking()) |
+ callback->Run(map_result.result); |
+} |
+ |
+// static |
+int32_t FileMappingResource::DoUnmap(const void* address, int64_t length) { |
+#if defined(OS_POSIX) |
+ int result = munmap(const_cast<void*>(address), static_cast<size_t>(length)); |
+ if (result) |
+ return ErrnoToPPError(errno); |
+ return PP_OK; |
+#else |
+ // TODO(dmichael): Implement for Windows (crbug.com/83774). |
+ return PP_ERROR_NOTSUPPORTED; |
+#endif |
+} |
+ |
+} // namespace proxy |
+} // namespace ppapi |