diff options
Diffstat (limited to 'mojo/edk/system/shared_buffer_dispatcher.cc')
-rw-r--r-- | mojo/edk/system/shared_buffer_dispatcher.cc | 270 |
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 |