root/ppapi/proxy/file_mapping_resource.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AsPPB_FileMapping_API
  2. Unmap
  3. GetMapPageSize
  4. OnMapCompleted

// 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

/* [<][>][^][v][top][bottom][index][help] */