Chromium Code Reviews| 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 |