diff options
Diffstat (limited to 'ppapi/proxy/file_mapping_resource.cc')
-rw-r--r-- | ppapi/proxy/file_mapping_resource.cc | 160 |
1 files changed, 160 insertions, 0 deletions
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 |