summaryrefslogtreecommitdiffstats
path: root/mojo/edk/system/shared_buffer_dispatcher.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mojo/edk/system/shared_buffer_dispatcher.cc')
-rw-r--r--mojo/edk/system/shared_buffer_dispatcher.cc270
1 files changed, 270 insertions, 0 deletions
diff --git a/mojo/edk/system/shared_buffer_dispatcher.cc b/mojo/edk/system/shared_buffer_dispatcher.cc
new file mode 100644
index 0000000..bf68eb3
--- /dev/null
+++ b/mojo/edk/system/shared_buffer_dispatcher.cc
@@ -0,0 +1,270 @@
+// 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 "mojo/edk/system/shared_buffer_dispatcher.h"
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/edk/embedder/embedder_internal.h"
+#include "mojo/edk/embedder/platform_support.h"
+#include "mojo/edk/system/configuration.h"
+#include "mojo/edk/system/options_validation.h"
+#include "mojo/public/c/system/macros.h"
+
+namespace mojo {
+namespace edk {
+
+namespace {
+
+struct MOJO_ALIGNAS(8) SerializedSharedBufferDispatcher {
+ size_t num_bytes;
+ size_t platform_handle_index;
+};
+
+} // namespace
+
+// static
+const MojoCreateSharedBufferOptions
+ SharedBufferDispatcher::kDefaultCreateOptions = {
+ static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)),
+ MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE};
+
+// static
+MojoResult SharedBufferDispatcher::ValidateCreateOptions(
+ const MojoCreateSharedBufferOptions* in_options,
+ MojoCreateSharedBufferOptions* out_options) {
+ const MojoCreateSharedBufferOptionsFlags kKnownFlags =
+ MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
+
+ *out_options = kDefaultCreateOptions;
+ if (!in_options)
+ return MOJO_RESULT_OK;
+
+ UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options);
+ if (!reader.is_valid())
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader))
+ return MOJO_RESULT_OK;
+ if ((reader.options().flags & ~kKnownFlags))
+ return MOJO_RESULT_UNIMPLEMENTED;
+ out_options->flags = reader.options().flags;
+
+ // Checks for fields beyond |flags|:
+
+ // (Nothing here yet.)
+
+ return MOJO_RESULT_OK;
+}
+
+// static
+MojoResult SharedBufferDispatcher::Create(
+ PlatformSupport* platform_support,
+ const MojoCreateSharedBufferOptions& /*validated_options*/,
+ uint64_t num_bytes,
+ scoped_refptr<SharedBufferDispatcher>* result) {
+ if (!num_bytes)
+ return MOJO_RESULT_INVALID_ARGUMENT;
+ if (num_bytes > GetConfiguration().max_shared_memory_num_bytes)
+ return MOJO_RESULT_RESOURCE_EXHAUSTED;
+
+ scoped_refptr<PlatformSharedBuffer> shared_buffer(
+ platform_support->CreateSharedBuffer(static_cast<size_t>(num_bytes)));
+ if (!shared_buffer)
+ return MOJO_RESULT_RESOURCE_EXHAUSTED;
+
+ *result = CreateInternal(shared_buffer.Pass());
+ return MOJO_RESULT_OK;
+}
+
+Dispatcher::Type SharedBufferDispatcher::GetType() const {
+ return Type::SHARED_BUFFER;
+}
+
+// static
+scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize(
+ const void* source,
+ size_t size,
+ PlatformHandleVector* platform_handles) {
+
+ if (size != sizeof(SerializedSharedBufferDispatcher)) {
+ LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)";
+ return nullptr;
+ }
+
+ const SerializedSharedBufferDispatcher* serialization =
+ static_cast<const SerializedSharedBufferDispatcher*>(source);
+ size_t num_bytes = serialization->num_bytes;
+ size_t platform_handle_index = serialization->platform_handle_index;
+
+ if (!num_bytes) {
+ LOG(ERROR)
+ << "Invalid serialized shared buffer dispatcher (invalid num_bytes)";
+ return nullptr;
+ }
+
+ if (!platform_handles || platform_handle_index >= platform_handles->size()) {
+ LOG(ERROR)
+ << "Invalid serialized shared buffer dispatcher (missing handles)";
+ return nullptr;
+ }
+
+ // Starts off invalid, which is what we want.
+ PlatformHandle platform_handle;
+ // We take ownership of the handle, so we have to invalidate the one in
+ // |platform_handles|.
+ std::swap(platform_handle, (*platform_handles)[platform_handle_index]);
+
+ // Wrapping |platform_handle| in a |ScopedPlatformHandle| means that it'll be
+ // closed even if creation fails.
+ scoped_refptr<PlatformSharedBuffer> shared_buffer(
+ internal::g_platform_support->CreateSharedBufferFromHandle(
+ num_bytes, ScopedPlatformHandle(platform_handle)));
+ if (!shared_buffer) {
+ LOG(ERROR)
+ << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)";
+ return nullptr;
+ }
+
+ return CreateInternal(shared_buffer.Pass());
+}
+
+SharedBufferDispatcher::SharedBufferDispatcher(
+ scoped_refptr<PlatformSharedBuffer> shared_buffer)
+ : shared_buffer_(shared_buffer) {
+ DCHECK(shared_buffer_);
+}
+
+SharedBufferDispatcher::~SharedBufferDispatcher() {
+}
+
+// static
+MojoResult SharedBufferDispatcher::ValidateDuplicateOptions(
+ const MojoDuplicateBufferHandleOptions* in_options,
+ MojoDuplicateBufferHandleOptions* out_options) {
+ const MojoDuplicateBufferHandleOptionsFlags kKnownFlags =
+ MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE;
+ static const MojoDuplicateBufferHandleOptions kDefaultOptions = {
+ static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)),
+ MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE};
+
+ *out_options = kDefaultOptions;
+ if (!in_options)
+ return MOJO_RESULT_OK;
+
+ UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options);
+ if (!reader.is_valid())
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ if (!OPTIONS_STRUCT_HAS_MEMBER(MojoDuplicateBufferHandleOptions, flags,
+ reader))
+ return MOJO_RESULT_OK;
+ if ((reader.options().flags & ~kKnownFlags))
+ return MOJO_RESULT_UNIMPLEMENTED;
+ out_options->flags = reader.options().flags;
+
+ // Checks for fields beyond |flags|:
+
+ // (Nothing here yet.)
+
+ return MOJO_RESULT_OK;
+}
+
+void SharedBufferDispatcher::CloseImplNoLock() {
+ lock().AssertAcquired();
+ DCHECK(shared_buffer_);
+ shared_buffer_ = nullptr;
+}
+
+scoped_refptr<Dispatcher>
+SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() {
+ lock().AssertAcquired();
+ DCHECK(shared_buffer_);
+ return CreateInternal(shared_buffer_.Pass());
+}
+
+MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock(
+ const MojoDuplicateBufferHandleOptions* options,
+ scoped_refptr<Dispatcher>* new_dispatcher) {
+ lock().AssertAcquired();
+
+ MojoDuplicateBufferHandleOptions validated_options;
+ MojoResult result = ValidateDuplicateOptions(options, &validated_options);
+ if (result != MOJO_RESULT_OK)
+ return result;
+
+ // Note: Since this is "duplicate", we keep our ref to |shared_buffer_|.
+ *new_dispatcher = CreateInternal(shared_buffer_);
+ return MOJO_RESULT_OK;
+}
+
+MojoResult SharedBufferDispatcher::MapBufferImplNoLock(
+ uint64_t offset,
+ uint64_t num_bytes,
+ MojoMapBufferFlags flags,
+ scoped_ptr<PlatformSharedBufferMapping>* mapping) {
+ lock().AssertAcquired();
+ DCHECK(shared_buffer_);
+
+ if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
+ return MOJO_RESULT_INVALID_ARGUMENT;
+ if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ if (!shared_buffer_->IsValidMap(static_cast<size_t>(offset),
+ static_cast<size_t>(num_bytes)))
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ DCHECK(mapping);
+ *mapping = shared_buffer_->MapNoCheck(static_cast<size_t>(offset),
+ static_cast<size_t>(num_bytes));
+ if (!*mapping)
+ return MOJO_RESULT_RESOURCE_EXHAUSTED;
+
+ return MOJO_RESULT_OK;
+}
+
+void SharedBufferDispatcher::StartSerializeImplNoLock(
+ size_t* max_size,
+ size_t* max_platform_handles) {
+ DCHECK(HasOneRef()); // Only one ref => no need to take the lock.
+ *max_size = sizeof(SerializedSharedBufferDispatcher);
+ *max_platform_handles = 1;
+}
+
+bool SharedBufferDispatcher::EndSerializeAndCloseImplNoLock(
+ void* destination,
+ size_t* actual_size,
+ PlatformHandleVector* platform_handles) {
+ DCHECK(HasOneRef()); // Only one ref => no need to take the lock.
+ DCHECK(shared_buffer_);
+
+ SerializedSharedBufferDispatcher* serialization =
+ static_cast<SerializedSharedBufferDispatcher*>(destination);
+ // If there's only one reference to |shared_buffer_|, then it's ours (and no
+ // one else can make any more references to it), so we can just take its
+ // handle.
+ ScopedPlatformHandle platform_handle(
+ shared_buffer_->HasOneRef() ? shared_buffer_->PassPlatformHandle()
+ : shared_buffer_->DuplicatePlatformHandle());
+ if (!platform_handle.is_valid()) {
+ shared_buffer_ = nullptr;
+ return false;
+ }
+
+ serialization->num_bytes = shared_buffer_->GetNumBytes();
+ serialization->platform_handle_index = platform_handles->size();
+ platform_handles->push_back(platform_handle.release());
+ *actual_size = sizeof(SerializedSharedBufferDispatcher);
+
+ shared_buffer_ = nullptr;
+
+ return true;
+}
+
+
+} // namespace edk
+} // namespace mojo