// 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 MOJO_EDK_EMBEDDER_PLATFORM_SHARED_BUFFER_H_
#define MOJO_EDK_EMBEDDER_PLATFORM_SHARED_BUFFER_H_
#include <stddef.h>
#include <memory>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "base/memory/shared_memory_handle.h"
#include "base/synchronization/lock.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
#include "mojo/edk/system/system_impl_export.h"
namespace mojo {
namespace edk {
class PlatformSharedBufferMapping;
// |PlatformSharedBuffer| is a thread-safe, ref-counted wrapper around
// OS-specific shared memory. It has the following features:
// - A |PlatformSharedBuffer| simply represents a piece of shared memory that
// *may* be mapped and *may* be shared to another process.
// - A single |PlatformSharedBuffer| may be mapped multiple times. The
// lifetime of the mapping (owned by |PlatformSharedBufferMapping|) is
// separate from the lifetime of the |PlatformSharedBuffer|.
// - Sizes/offsets (of the shared memory and mappings) are arbitrary, and not
// restricted by page size. However, more memory may actually be mapped than
// requested.
class MOJO_SYSTEM_IMPL_EXPORT PlatformSharedBuffer
: public base::RefCountedThreadSafe<PlatformSharedBuffer> {
public:
// Creates a shared buffer of size |num_bytes| bytes (initially zero-filled).
// |num_bytes| must be nonzero. Returns null on failure.
static PlatformSharedBuffer* Create(size_t num_bytes);
// Creates a shared buffer of size |num_bytes| from the existing platform
// handle |platform_handle|. Returns null on failure.
static PlatformSharedBuffer* CreateFromPlatformHandle(
size_t num_bytes,
bool read_only,
ScopedPlatformHandle platform_handle);
// Creates a shared buffer of size |num_bytes| from the existing pair of
// read/write and read-only handles |rw_platform_handle| and
// |ro_platform_handle|. Returns null on failure.
static PlatformSharedBuffer* CreateFromPlatformHandlePair(
size_t num_bytes,
ScopedPlatformHandle rw_platform_handle,
ScopedPlatformHandle ro_platform_handle);
// Creates a shared buffer of size |num_bytes| from the existing shared memory
// handle |handle|.
static PlatformSharedBuffer* CreateFromSharedMemoryHandle(
size_t num_bytes,
bool read_only,
base::SharedMemoryHandle handle);
// Gets the size of shared buffer (in number of bytes).
size_t GetNumBytes() const;
// Returns whether this shared buffer is read-only.
bool IsReadOnly() const;
// Maps (some) of the shared buffer into memory; [|offset|, |offset + length|]
// must be contained in [0, |num_bytes|], and |length| must be at least 1.
// Returns null on failure.
std::unique_ptr<PlatformSharedBufferMapping> Map(size_t offset,
size_t length);
// Checks if |offset| and |length| are valid arguments.
bool IsValidMap(size_t offset, size_t length);
// Like |Map()|, but doesn't check its arguments (which should have been
// preflighted using |IsValidMap()|).
std::unique_ptr<PlatformSharedBufferMapping> MapNoCheck(size_t offset,
size_t length);
// Duplicates the underlying platform handle and passes it to the caller.
ScopedPlatformHandle DuplicatePlatformHandle();
// Duplicates the underlying shared memory handle and passes it to the caller.
base::SharedMemoryHandle DuplicateSharedMemoryHandle();
// Passes the underlying platform handle to the caller. This should only be
// called if there's a unique reference to this object (owned by the caller).
// After calling this, this object should no longer be used, but should only
// be disposed of.
ScopedPlatformHandle PassPlatformHandle();
// Create and return a read-only duplicate of this shared buffer. If this
// shared buffer isn't capable of returning a read-only duplicate, then
// nullptr will be returned.
PlatformSharedBuffer* CreateReadOnlyDuplicate();
private:
friend class base::RefCountedThreadSafe<PlatformSharedBuffer>;
PlatformSharedBuffer(size_t num_bytes, bool read_only);
~PlatformSharedBuffer();
// This is called by |Create()| before this object is given to anyone.
bool Init();
// This is like |Init()|, but for |CreateFromPlatformHandle()|. (Note: It
// should verify that |platform_handle| is an appropriate handle for the
// claimed |num_bytes_|.)
bool InitFromPlatformHandle(ScopedPlatformHandle platform_handle);
bool InitFromPlatformHandlePair(ScopedPlatformHandle rw_platform_handle,
ScopedPlatformHandle ro_platform_handle);
void InitFromSharedMemoryHandle(base::SharedMemoryHandle handle);
const size_t num_bytes_;
const bool read_only_;
base::Lock lock_;
std::unique_ptr<base::SharedMemory> shared_memory_;
// A separate read-only shared memory for platforms that need it (i.e. Linux
// with sync broker).
std::unique_ptr<base::SharedMemory> ro_shared_memory_;
DISALLOW_COPY_AND_ASSIGN(PlatformSharedBuffer);
};
// A mapping of a |PlatformSharedBuffer| (compararable to a "file view" in
// Windows); see above. Created by |PlatformSharedBuffer::Map()|. Automatically
// unmaps memory on destruction.
//
// Mappings are NOT thread-safe.
//
// Note: This is an entirely separate class (instead of
// |PlatformSharedBuffer::Mapping|) so that it can be forward-declared.
class MOJO_SYSTEM_IMPL_EXPORT PlatformSharedBufferMapping {
public:
~PlatformSharedBufferMapping();
void* GetBase() const;
size_t GetLength() const;
private:
friend class PlatformSharedBuffer;
PlatformSharedBufferMapping(base::SharedMemoryHandle handle,
bool read_only,
size_t offset,
size_t length)
: offset_(offset),
length_(length),
base_(nullptr),
shared_memory_(handle, read_only) {}
bool Map();
void Unmap();
const size_t offset_;
const size_t length_;
void* base_;
// Since mapping life cycles are separate from PlatformSharedBuffer and a
// buffer can be mapped multiple times, we have our own SharedMemory object
// created from a duplicate handle.
base::SharedMemory shared_memory_;
DISALLOW_COPY_AND_ASSIGN(PlatformSharedBufferMapping);
};
} // namespace edk
} // namespace mojo
#endif // MOJO_EDK_EMBEDDER_PLATFORM_SHARED_BUFFER_H_