Mojo: Add a C++-style SharedBuffer API.
Review-Url: https://codereview.chromium.org/2036053002
Cr-Commit-Position: refs/heads/master@{#397957}
CrOS-Libchrome-Original-Commit: a7ee0a2ccde8c99665de2b5859e903087c3d3c31
diff --git a/mojo/mojo_public.gyp b/mojo/mojo_public.gyp
index 2c770cb..7096de5 100644
--- a/mojo/mojo_public.gyp
+++ b/mojo/mojo_public.gyp
@@ -96,6 +96,7 @@
'target_name': 'mojo_cpp_system',
'type': 'static_library',
'sources': [
+ 'public/cpp/system/buffer.cc',
'public/cpp/system/buffer.h',
'public/cpp/system/core.h',
'public/cpp/system/data_pipe.h',
diff --git a/mojo/public/cpp/system/buffer.cc b/mojo/public/cpp/system/buffer.cc
new file mode 100644
index 0000000..c186465
--- /dev/null
+++ b/mojo/public/cpp/system/buffer.cc
@@ -0,0 +1,37 @@
+// Copyright 2016 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 "mojo/public/cpp/system/buffer.h"
+
+namespace mojo {
+
+ScopedSharedBufferHandle SharedBufferHandle::Clone(
+ SharedBufferHandle::AccessMode access_mode) const {
+ ScopedSharedBufferHandle result;
+ if (!is_valid())
+ return result;
+
+ MojoDuplicateBufferHandleOptions options = {
+ sizeof(options), MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE};
+ if (access_mode == AccessMode::READ_ONLY)
+ options.flags |= MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
+ SharedBufferHandle result_handle;
+ MojoDuplicateBufferHandle(value(), &options, result_handle.mutable_value());
+ result.reset(result_handle);
+ return result;
+}
+
+ScopedSharedBufferMapping SharedBufferHandle::Map(uint64_t size) const {
+ return MapAtOffset(size, 0);
+}
+
+ScopedSharedBufferMapping SharedBufferHandle::MapAtOffset(
+ uint64_t size,
+ uint64_t offset) const {
+ void* buffer = nullptr;
+ MojoMapBuffer(value(), offset, size, &buffer, MOJO_MAP_BUFFER_FLAG_NONE);
+ return ScopedSharedBufferMapping(buffer);
+}
+
+} // namespace mojo
diff --git a/mojo/public/cpp/system/buffer.h b/mojo/public/cpp/system/buffer.h
index a2d524e..27ba814 100644
--- a/mojo/public/cpp/system/buffer.h
+++ b/mojo/public/cpp/system/buffer.h
@@ -14,27 +14,61 @@
#include <stdint.h>
+#include <memory>
+
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "mojo/public/c/system/buffer.h"
#include "mojo/public/cpp/system/handle.h"
namespace mojo {
+namespace internal {
+
+struct Unmapper {
+ void operator()(void* buffer) {
+ MojoResult result = MojoUnmapBuffer(buffer);
+ DCHECK_EQ(MOJO_RESULT_OK, result);
+ }
+};
+
+} // namespace internal
+
+using ScopedSharedBufferMapping = std::unique_ptr<void, internal::Unmapper>;
+
+class SharedBufferHandle;
+
+typedef ScopedHandleBase<SharedBufferHandle> ScopedSharedBufferHandle;
// A strongly-typed representation of a |MojoHandle| referring to a shared
// buffer.
class SharedBufferHandle : public Handle {
public:
+ enum class AccessMode {
+ READ_WRITE,
+ READ_ONLY,
+ };
+
SharedBufferHandle() {}
explicit SharedBufferHandle(MojoHandle value) : Handle(value) {}
// Copying and assignment allowed.
+
+ // Clones this shared buffer handle. If |access_mode| is READ_ONLY or this is
+ // a read-only handle, the new handle will be read-only. On failure, this will
+ // return an empty result.
+ ScopedSharedBufferHandle Clone(AccessMode = AccessMode::READ_WRITE) const;
+
+ // Maps |size| bytes of this shared buffer. On failure, this will return a
+ // null mapping.
+ ScopedSharedBufferMapping Map(uint64_t size) const;
+
+ // Maps |size| bytes of this shared buffer, starting |offset| bytes into the
+ // buffer. On failure, this will return a null mapping.
+ ScopedSharedBufferMapping MapAtOffset(uint64_t size, uint64_t offset) const;
};
static_assert(sizeof(SharedBufferHandle) == sizeof(Handle),
"Bad size for C++ SharedBufferHandle");
-
-typedef ScopedHandleBase<SharedBufferHandle> ScopedSharedBufferHandle;
static_assert(sizeof(ScopedSharedBufferHandle) == sizeof(SharedBufferHandle),
"Bad size for C++ ScopedSharedBufferHandle");
diff --git a/mojo/public/cpp/system/handle.h b/mojo/public/cpp/system/handle.h
index d0466b0..f142e8b 100644
--- a/mojo/public/cpp/system/handle.h
+++ b/mojo/public/cpp/system/handle.h
@@ -96,6 +96,7 @@
}
const HandleType& get() const { return handle_; }
+ const HandleType* operator->() const { return &handle_; }
template <typename PassedHandleType>
static ScopedHandleBase<HandleType> From(
diff --git a/mojo/public/cpp/system/tests/core_unittest.cc b/mojo/public/cpp/system/tests/core_unittest.cc
index b500be3..9a95635 100644
--- a/mojo/public/cpp/system/tests/core_unittest.cc
+++ b/mojo/public/cpp/system/tests/core_unittest.cc
@@ -481,6 +481,47 @@
EXPECT_FALSE(buffer2.is_valid());
}
+TEST(CoreCppTest, BasicSharedBuffer) {
+ ScopedSharedBufferHandle h0;
+
+ // Create a shared buffer (|h0|).
+ {
+ SharedBuffer buffer(100);
+ h0 = std::move(buffer.handle);
+ }
+
+ // Map everything.
+ ScopedSharedBufferMapping mapping = h0->Map(100);
+ ASSERT_TRUE(mapping);
+ static_cast<char*>(mapping.get())[50] = 'x';
+
+ // Duplicate |h0| to |h1|.
+ ScopedSharedBufferHandle h1 =
+ h0->Clone(SharedBufferHandle::AccessMode::READ_ONLY);
+ ASSERT_TRUE(h1.is_valid());
+
+ // Close |h0|.
+ h0.reset();
+
+ // The mapping should still be good.
+ static_cast<char*>(mapping.get())[51] = 'y';
+
+ // Unmap it.
+ mapping.reset();
+
+ // Map half of |h1|.
+ mapping = h1->MapAtOffset(50, 50);
+ ASSERT_TRUE(mapping);
+
+ // It should have what we wrote.
+ EXPECT_EQ('x', static_cast<char*>(mapping.get())[0]);
+ EXPECT_EQ('y', static_cast<char*>(mapping.get())[1]);
+
+ // Unmap it.
+ mapping.reset();
+ h1.reset();
+}
+
// TODO(vtl): Write data pipe tests.
} // namespace