diff options
Diffstat (limited to 'mojo/public/cpp')
36 files changed, 2077 insertions, 13 deletions
diff --git a/mojo/public/cpp/bindings/DEPS b/mojo/public/cpp/bindings/DEPS deleted file mode 100644 index ba2a571..0000000 --- a/mojo/public/cpp/bindings/DEPS +++ /dev/null @@ -1,4 +0,0 @@ -include_rules = [ - # TODO(vtl): Temporary, until we move lib here. - "+mojo/public/bindings/lib", -] diff --git a/mojo/public/cpp/bindings/allocation_scope.h b/mojo/public/cpp/bindings/allocation_scope.h index e372457..110c9b3 100644 --- a/mojo/public/cpp/bindings/allocation_scope.h +++ b/mojo/public/cpp/bindings/allocation_scope.h @@ -5,7 +5,7 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_ALLOCATION_SCOPE_H_ #define MOJO_PUBLIC_CPP_BINDINGS_ALLOCATION_SCOPE_H_ -#include "mojo/public/bindings/lib/scratch_buffer.h" +#include "mojo/public/cpp/bindings/lib/scratch_buffer.h" #include "mojo/public/cpp/system/macros.h" namespace mojo { diff --git a/mojo/public/cpp/bindings/array.h b/mojo/public/cpp/bindings/array.h index 601eedc..72aa56d 100644 --- a/mojo/public/cpp/bindings/array.h +++ b/mojo/public/cpp/bindings/array.h @@ -11,7 +11,7 @@ #include <string> #include <vector> -#include "mojo/public/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/lib/array_internal.h" #include "mojo/public/cpp/bindings/type_converter.h" namespace mojo { diff --git a/mojo/public/cpp/bindings/callback.h b/mojo/public/cpp/bindings/callback.h index 766c9c3..4192f89 100644 --- a/mojo/public/cpp/bindings/callback.h +++ b/mojo/public/cpp/bindings/callback.h @@ -11,8 +11,8 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ #define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ -#include "mojo/public/bindings/lib/callback_internal.h" -#include "mojo/public/bindings/lib/shared_ptr.h" +#include "mojo/public/cpp/bindings/lib/callback_internal.h" +#include "mojo/public/cpp/bindings/lib/shared_ptr.h" namespace mojo { diff --git a/mojo/public/cpp/bindings/callback.h.pump b/mojo/public/cpp/bindings/callback.h.pump index 998324f..5452abb 100644 --- a/mojo/public/cpp/bindings/callback.h.pump +++ b/mojo/public/cpp/bindings/callback.h.pump @@ -14,8 +14,8 @@ $var MAX_ARITY = 7 #ifndef MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ #define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ -#include "mojo/public/bindings/lib/callback_internal.h" -#include "mojo/public/bindings/lib/shared_ptr.h" +#include "mojo/public/cpp/bindings/lib/callback_internal.h" +#include "mojo/public/cpp/bindings/lib/shared_ptr.h" namespace mojo { diff --git a/mojo/public/cpp/bindings/lib/DEPS b/mojo/public/cpp/bindings/lib/DEPS new file mode 100644 index 0000000..b809b58 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/DEPS @@ -0,0 +1,5 @@ +include_rules = [ + "+mojo/public/cpp/bindings", + "+mojo/public/cpp/environment", + "+mojo/public/cpp/system", +] diff --git a/mojo/public/cpp/bindings/lib/TODO b/mojo/public/cpp/bindings/lib/TODO new file mode 100644 index 0000000..318edcf --- /dev/null +++ b/mojo/public/cpp/bindings/lib/TODO @@ -0,0 +1,7 @@ +TODOs: + - Ensure validation checks are solid + - Add tests of validation logic + - Optimize Buffer classes? + - Make "Clone" method public? + - Add compile-time asserts to verify object packing and padding. + - Investigate making arrays of objects not be arrays of pointers. diff --git a/mojo/public/cpp/bindings/lib/array.cc b/mojo/public/cpp/bindings/lib/array.cc new file mode 100644 index 0000000..6745adc --- /dev/null +++ b/mojo/public/cpp/bindings/lib/array.cc @@ -0,0 +1,38 @@ +// Copyright 2013 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/bindings/array.h" + +namespace mojo { + +// static +String TypeConverter<String, std::string>::ConvertFrom(const std::string& input, + Buffer* buf) { + String::Builder result(input.size(), buf); + if (!input.empty()) + memcpy(&result[0], input.data(), input.size()); + return result.Finish(); +} +// static +std::string TypeConverter<String, std::string>::ConvertTo(const String& input) { + if (input.is_null() || input.size() == 0) + return std::string(); + + return std::string(&input[0], &input[0] + input.size()); +} + +// static +String TypeConverter<String, const char*>::ConvertFrom(const char* input, + Buffer* buf) { + if (!input) + return String(); + + size_t size = strlen(input); + String::Builder result(size, buf); + if (size != 0) + memcpy(&result[0], input, size); + return result.Finish(); +} + +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/array_internal.cc b/mojo/public/cpp/bindings/lib/array_internal.cc new file mode 100644 index 0000000..efdda8c --- /dev/null +++ b/mojo/public/cpp/bindings/lib/array_internal.cc @@ -0,0 +1,59 @@ +// Copyright 2013 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/bindings/lib/array_internal.h" + +namespace mojo { +namespace internal { + +ArrayDataTraits<bool>::BitRef::~BitRef() { +} + +ArrayDataTraits<bool>::BitRef::BitRef(uint8_t* storage, uint8_t mask) + : storage_(storage), + mask_(mask) { +} + +ArrayDataTraits<bool>::BitRef& +ArrayDataTraits<bool>::BitRef::operator=(bool value) { + if (value) { + *storage_ |= mask_; + } else { + *storage_ &= ~mask_; + } + return *this; +} + +ArrayDataTraits<bool>::BitRef& +ArrayDataTraits<bool>::BitRef::operator=(const BitRef& value) { + return (*this) = static_cast<bool>(value); +} + +ArrayDataTraits<bool>::BitRef::operator bool() const { + return (*storage_ & mask_) != 0; +} + +// static +void ArraySerializationHelper<Handle>::EncodePointersAndHandles( + const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + EncodeHandle(&elements[i], handles); +} + +// static +bool ArraySerializationHelper<Handle>::DecodePointersAndHandles( + const ArrayHeader* header, + ElementType* elements, + Message* message) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!DecodeHandle(&elements[i], message->mutable_handles())) + return false; + } + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/array_internal.h b/mojo/public/cpp/bindings/lib/array_internal.h new file mode 100644 index 0000000..978dca3 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/array_internal.h @@ -0,0 +1,372 @@ +// Copyright 2013 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_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ + +#include <new> + +#include "mojo/public/cpp/bindings/buffer.h" +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/passable.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +template <typename T> class Array; + +namespace internal { + +template <typename T> +struct ArrayDataTraits { + typedef T StorageType; + typedef Array<T> Wrapper; + typedef T& Ref; + typedef T const& ConstRef; + + static size_t GetStorageSize(size_t num_elements) { + return sizeof(StorageType) * num_elements; + } + static Ref ToRef(StorageType* storage, size_t offset) { + return storage[offset]; + } + static ConstRef ToConstRef(const StorageType* storage, size_t offset) { + return storage[offset]; + } +}; + +template <typename P> +struct ArrayDataTraits<P*> { + typedef StructPointer<P> StorageType; + typedef Array<typename P::Wrapper> Wrapper; + typedef P*& Ref; + typedef P* const& ConstRef; + + static size_t GetStorageSize(size_t num_elements) { + return sizeof(StorageType) * num_elements; + } + static Ref ToRef(StorageType* storage, size_t offset) { + return storage[offset].ptr; + } + static ConstRef ToConstRef(const StorageType* storage, size_t offset) { + return storage[offset].ptr; + } +}; + +// Specialization of Arrays for bools, optimized for space. It has the +// following differences from a generalized Array: +// * Each element takes up a single bit of memory. +// * Accessing a non-const single element uses a helper class |BitRef|, which +// emulates a reference to a bool. +template <> +struct ArrayDataTraits<bool> { + // Helper class to emulate a reference to a bool, used for direct element + // access. + class BitRef { + public: + ~BitRef(); + BitRef& operator=(bool value); + BitRef& operator=(const BitRef& value); + operator bool() const; + private: + friend struct ArrayDataTraits<bool>; + BitRef(uint8_t* storage, uint8_t mask); + BitRef(); + uint8_t* storage_; + uint8_t mask_; + }; + + typedef uint8_t StorageType; + typedef Array<bool> Wrapper; + typedef BitRef Ref; + typedef bool ConstRef; + + static size_t GetStorageSize(size_t num_elements) { + return ((num_elements + 7) / 8); + } + static BitRef ToRef(StorageType* storage, size_t offset) { + return BitRef(&storage[offset / 8], 1 << (offset % 8)); + } + static bool ToConstRef(const StorageType* storage, size_t offset) { + return (storage[offset / 8] & (1 << (offset % 8))) != 0; + } +}; + +// What follows is code to support the serialization of Array_Data<T>. There +// are two interesting cases: arrays of primitives and arrays of objects. +// Arrays of objects are represented as arrays of pointers to objects. + +template <typename T> +struct ArraySerializationHelper { + typedef T ElementType; + + static size_t ComputeSizeOfElements(const ArrayHeader* header, + const ElementType* elements) { + return 0; + } + + static void CloneElements(const ArrayHeader* header, + ElementType* elements, + Buffer* buf) { + } + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + } + + static bool DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + Message* message) { + return true; + } +}; + +template <> +struct ArraySerializationHelper<Handle> { + typedef Handle ElementType; + + static size_t ComputeSizeOfElements(const ArrayHeader* header, + const ElementType* elements) { + return 0; + } + + static void CloneElements(const ArrayHeader* header, + ElementType* elements, + Buffer* buf) { + } + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles); + + static bool DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + Message* message); +}; + +template <typename P> +struct ArraySerializationHelper<P*> { + typedef StructPointer<P> ElementType; + + static size_t ComputeSizeOfElements(const ArrayHeader* header, + const ElementType* elements) { + size_t result = 0; + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (elements[i].ptr) + result += elements[i].ptr->ComputeSize(); + } + return result; + } + + static void CloneElements(const ArrayHeader* header, + ElementType* elements, + Buffer* buf) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (elements[i].ptr) + elements[i].ptr = elements[i].ptr->Clone(buf); + } + } + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + Encode(&elements[i], handles); + } + + static bool DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + Message* message) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!Decode(&elements[i], message)) + return false; + } + return true; + } +}; + +template <typename T> +class Array_Data { + public: + typedef ArrayDataTraits<T> Traits; + typedef typename Traits::StorageType StorageType; + typedef typename Traits::Wrapper Wrapper; + typedef typename Traits::Ref Ref; + typedef typename Traits::ConstRef ConstRef; + + static Array_Data<T>* New(size_t num_elements, Buffer* buf) { + size_t num_bytes = sizeof(Array_Data<T>) + + Traits::GetStorageSize(num_elements); + return new (buf->Allocate(num_bytes)) Array_Data<T>(num_bytes, + num_elements); + } + + size_t size() const { return header_.num_elements; } + + Ref at(size_t offset) { + assert(offset < static_cast<size_t>(header_.num_elements)); + return Traits::ToRef(storage(), offset); + } + + ConstRef at(size_t offset) const { + assert(offset < static_cast<size_t>(header_.num_elements)); + return Traits::ToConstRef(storage(), offset); + } + + StorageType* storage() { + return reinterpret_cast<StorageType*>( + reinterpret_cast<char*>(this) + sizeof(*this)); + } + + const StorageType* storage() const { + return reinterpret_cast<const StorageType*>( + reinterpret_cast<const char*>(this) + sizeof(*this)); + } + + size_t ComputeSize() const { + return Align(header_.num_bytes) + + ArraySerializationHelper<T>::ComputeSizeOfElements(&header_, storage()); + } + + Array_Data<T>* Clone(Buffer* buf) const { + Array_Data<T>* clone = New(header_.num_elements, buf); + memcpy(clone->storage(), + storage(), + header_.num_bytes - sizeof(Array_Data<T>)); + + ArraySerializationHelper<T>::CloneElements(&clone->header_, + clone->storage(), buf); + return clone; + } + + void CloseHandles() { + // TODO(darin): Implement! + } + + void EncodePointersAndHandles(std::vector<Handle>* handles) { + ArraySerializationHelper<T>::EncodePointersAndHandles(&header_, storage(), + handles); + } + + bool DecodePointersAndHandles(Message* message) { + return ArraySerializationHelper<T>::DecodePointersAndHandles(&header_, + storage(), + message); + } + + private: + Array_Data(size_t num_bytes, size_t num_elements) { + header_.num_bytes = static_cast<uint32_t>(num_bytes); + header_.num_elements = static_cast<uint32_t>(num_elements); + } + ~Array_Data() {} + + internal::ArrayHeader header_; + + // Elements of type internal::ArrayDataTraits<T>::StorageType follow. +}; +MOJO_COMPILE_ASSERT(sizeof(Array_Data<char>) == 8, bad_sizeof_Array_Data); + +// UTF-8 encoded +typedef Array_Data<char> String_Data; + +template <typename T, bool kIsObject> struct ArrayTraits {}; + +template <typename T> struct ArrayTraits<T, true> { + typedef Array_Data<typename T::Data*> DataType; + typedef const T& ConstRef; + typedef T& Ref; + static typename T::Data* ToArrayElement(const T& value) { + return Unwrap(value); + } + // Something sketchy is indeed happening here... + static Ref ToRef(typename T::Data*& data) { + return *reinterpret_cast<T*>(&data); + } + static ConstRef ToConstRef(typename T::Data* const& data) { + return *reinterpret_cast<const T*>(&data); + } +}; + +template <typename T> struct ArrayTraits<T, false> { + typedef Array_Data<T> DataType; + typedef const T& ConstRef; + typedef T& Ref; + static T ToArrayElement(const T& value) { + return value; + } + static Ref ToRef(T& data) { return data; } + static ConstRef ToConstRef(const T& data) { return data; } +}; + +template <> struct ArrayTraits<bool, false> { + typedef Array_Data<bool> DataType; + typedef bool ConstRef; + typedef ArrayDataTraits<bool>::Ref Ref; + static bool ToArrayElement(const bool& value) { + return value; + } + static Ref ToRef(const Ref& data) { return data; } + static ConstRef ToConstRef(ConstRef data) { return data; } +}; + +template <> struct ArrayTraits<Handle, false> { + typedef Array_Data<Handle> DataType; + typedef Passable<Handle> ConstRef; + typedef AssignableAndPassable<Handle> Ref; + static Handle ToArrayElement(const Handle& value) { + return value; + } + static Ref ToRef(Handle& data) { return Ref(&data); } + static ConstRef ToConstRef(const Handle& data) { + return ConstRef(const_cast<Handle*>(&data)); + } +}; + +template <> struct ArrayTraits<DataPipeConsumerHandle, false> { + typedef Array_Data<DataPipeConsumerHandle> DataType; + typedef Passable<DataPipeConsumerHandle> ConstRef; + typedef AssignableAndPassable<DataPipeConsumerHandle> Ref; + static DataPipeConsumerHandle ToArrayElement( + const DataPipeConsumerHandle& value) { + return value; + } + static Ref ToRef(DataPipeConsumerHandle& data) { return Ref(&data); } + static ConstRef ToConstRef(const DataPipeConsumerHandle& data) { + return ConstRef(const_cast<DataPipeConsumerHandle*>(&data)); + } +}; + +template <> struct ArrayTraits<DataPipeProducerHandle, false> { + typedef Array_Data<DataPipeProducerHandle> DataType; + typedef Passable<DataPipeProducerHandle> ConstRef; + typedef AssignableAndPassable<DataPipeProducerHandle> Ref; + static DataPipeProducerHandle ToArrayElement( + const DataPipeProducerHandle& value) { + return value; + } + static Ref ToRef(DataPipeProducerHandle& data) { return Ref(&data); } + static ConstRef ToConstRef(const DataPipeProducerHandle& data) { + return ConstRef(const_cast<DataPipeProducerHandle*>(&data)); + } +}; + +template <> struct ArrayTraits<MessagePipeHandle, false> { + typedef Array_Data<MessagePipeHandle> DataType; + typedef Passable<MessagePipeHandle> ConstRef; + typedef AssignableAndPassable<MessagePipeHandle> Ref; + static MessagePipeHandle ToArrayElement(const MessagePipeHandle& value) { + return value; + } + static Ref ToRef(MessagePipeHandle& data) { return Ref(&data); } + static ConstRef ToConstRef(const MessagePipeHandle& data) { + return ConstRef(const_cast<MessagePipeHandle*>(&data)); + } +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ diff --git a/mojo/public/cpp/bindings/lib/bindings_internal.h b/mojo/public/cpp/bindings/lib/bindings_internal.h new file mode 100644 index 0000000..ef6fc47 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/bindings_internal.h @@ -0,0 +1,141 @@ +// Copyright 2013 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_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +namespace internal { +template <typename T> class Array_Data; + +#pragma pack(push, 1) + +struct StructHeader { + uint32_t num_bytes; + uint32_t num_fields; +}; +MOJO_COMPILE_ASSERT(sizeof(StructHeader) == 8, bad_sizeof_StructHeader); + +struct ArrayHeader { + uint32_t num_bytes; + uint32_t num_elements; +}; +MOJO_COMPILE_ASSERT(sizeof(ArrayHeader) == 8, bad_sizeof_ArrayHeader); + +template <typename T> +union StructPointer { + uint64_t offset; + T* ptr; +}; +MOJO_COMPILE_ASSERT(sizeof(StructPointer<char>) == 8, bad_sizeof_StructPointer); + +template <typename T> +union ArrayPointer { + uint64_t offset; + Array_Data<T>* ptr; +}; +MOJO_COMPILE_ASSERT(sizeof(ArrayPointer<char>) == 8, bad_sizeof_ArrayPointer); + +union StringPointer { + uint64_t offset; + Array_Data<char>* ptr; +}; +MOJO_COMPILE_ASSERT(sizeof(StringPointer) == 8, bad_sizeof_StringPointer); + +#pragma pack(pop) + +template <typename T> +void ResetIfNonNull(T* ptr) { + if (ptr) + *ptr = T(); +} + +template <typename T> +T FetchAndReset(T* ptr) { + T temp = *ptr; + *ptr = T(); + return temp; +} + +template <typename T> +class WrapperHelper { + public: + static const T Wrap(const typename T::Data* data) { + return T(typename T::Wrap(), const_cast<typename T::Data*>(data)); + } + static typename T::Data* Unwrap(const T& object) { + return const_cast<typename T::Data*>(object.data_); + } +}; + +template <typename Data> +inline const typename Data::Wrapper Wrap(const Data* data) { + return WrapperHelper<typename Data::Wrapper>::Wrap(data); +} + +template <typename T> +inline typename T::Data* Unwrap(const T& object) { + return WrapperHelper<T>::Unwrap(object); +} + +template <typename T> struct TypeTraits { + static const bool kIsObject = true; +}; +template <> struct TypeTraits<bool> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<char> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<int8_t> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<int16_t> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<int32_t> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<int64_t> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<uint8_t> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<uint16_t> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<uint32_t> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<uint64_t> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<float> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<double> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<Handle> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<DataPipeConsumerHandle> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<DataPipeProducerHandle> { + static const bool kIsObject = false; +}; +template <> struct TypeTraits<MessagePipeHandle> { + static const bool kIsObject = false; +}; + +template <typename T> class ObjectTraits {}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ diff --git a/mojo/public/cpp/bindings/lib/bindings_serialization.cc b/mojo/public/cpp/bindings/lib/bindings_serialization.cc new file mode 100644 index 0000000..ff06d95 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/bindings_serialization.cc @@ -0,0 +1,73 @@ +// Copyright 2013 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/bindings/lib/bindings_serialization.h" + +#include <assert.h> + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" + +namespace mojo { +namespace internal { + +size_t Align(size_t size) { + const size_t kAlignment = 8; + return size + (kAlignment - (size % kAlignment)) % kAlignment; +} + +void EncodePointer(const void* ptr, uint64_t* offset) { + if (!ptr) { + *offset = 0; + return; + } + + const char* p_obj = reinterpret_cast<const char*>(ptr); + const char* p_slot = reinterpret_cast<const char*>(offset); + assert(p_obj > p_slot); + + *offset = static_cast<uint64_t>(p_obj - p_slot); +} + +const void* DecodePointerRaw(const uint64_t* offset) { + if (!*offset) + return NULL; + return reinterpret_cast<const char*>(offset) + *offset; +} + +bool ValidatePointer(const void* ptr, const Message& message) { + const uint8_t* data = static_cast<const uint8_t*>(ptr); + if (reinterpret_cast<ptrdiff_t>(data) % 8 != 0) + return false; + + const uint8_t* data_start = message.data(); + const uint8_t* data_end = data_start + message.data_num_bytes(); + + return data >= data_start && data < data_end; +} + +void EncodeHandle(Handle* handle, std::vector<Handle>* handles) { + if (handle->is_valid()) { + handles->push_back(*handle); + handle->set_value(static_cast<MojoHandle>(handles->size() - 1)); + } else { + // Encode -1 to mean the invalid handle. + handle->set_value(static_cast<MojoHandle>(-1)); + } +} + +bool DecodeHandle(Handle* handle, std::vector<Handle>* handles) { + // Decode -1 to mean the invalid handle. + if (handle->value() == static_cast<MojoHandle>(-1)) { + *handle = Handle(); + return true; + } + if (handle->value() >= handles->size()) + return false; + // Just leave holes in the vector so we don't screw up other indices. + *handle = FetchAndReset(&handles->at(handle->value())); + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/bindings_serialization.h b/mojo/public/cpp/bindings/lib/bindings_serialization.h new file mode 100644 index 0000000..a860b14 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/bindings_serialization.h @@ -0,0 +1,67 @@ +// Copyright 2013 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_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ + +#include <vector> + +#include "mojo/public/cpp/bindings/buffer.h" +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { +namespace internal { + +size_t Align(size_t size); + +// Pointers are encoded as relative offsets. The offsets are relative to the +// address of where the offset value is stored, such that the pointer may be +// recovered with the expression: +// +// ptr = reinterpret_cast<char*>(offset) + *offset +// +// A null pointer is encoded as an offset value of 0. +// +void EncodePointer(const void* ptr, uint64_t* offset); +const void* DecodePointerRaw(const uint64_t* offset); + +template <typename T> +inline void DecodePointer(const uint64_t* offset, T** ptr) { + *ptr = reinterpret_cast<T*>(const_cast<void*>(DecodePointerRaw(offset))); +} + +// Check that the given pointer references memory contained within the message. +bool ValidatePointer(const void* ptr, const Message& message); + +// Handles are encoded as indices into a vector of handles. These functions +// manipulate the value of |handle|, mapping it to and from an index. +void EncodeHandle(Handle* handle, std::vector<Handle>* handles); +bool DecodeHandle(Handle* handle, std::vector<Handle>* handles); + +// The following 2 functions are used to encode/decode all objects (structs and +// arrays) in a consistent manner. + +template <typename T> +inline void Encode(T* obj, std::vector<Handle>* handles) { + if (obj->ptr) + obj->ptr->EncodePointersAndHandles(handles); + EncodePointer(obj->ptr, &obj->offset); +} + +template <typename T> +inline bool Decode(T* obj, Message* message) { + DecodePointer(&obj->offset, &obj->ptr); + if (obj->ptr) { + if (!ValidatePointer(obj->ptr, *message)) + return false; + if (!obj->ptr->DecodePointersAndHandles(message)) + return false; + } + return true; +} + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ diff --git a/mojo/public/cpp/bindings/lib/buffer.cc b/mojo/public/cpp/bindings/lib/buffer.cc new file mode 100644 index 0000000..4404df8 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/buffer.cc @@ -0,0 +1,27 @@ +// Copyright 2013 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/bindings/buffer.h" + +#include <assert.h> + +#include "mojo/public/cpp/environment/buffer_tls.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +Buffer::Buffer() { + previous_ = internal::SetCurrentBuffer(this); +} + +Buffer::~Buffer() { + Buffer* buf MOJO_ALLOW_UNUSED = internal::SetCurrentBuffer(previous_); + assert(buf == this); +} + +Buffer* Buffer::current() { + return internal::GetCurrentBuffer(); +} + +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/callback_internal.h b/mojo/public/cpp/bindings/lib/callback_internal.h new file mode 100644 index 0000000..4802e43 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/callback_internal.h @@ -0,0 +1,55 @@ +// 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_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_ + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" + +namespace mojo { +namespace internal { + +template <typename T, bool is_object_type = TypeTraits<T>::kIsObject> +struct Callback_ParamTraits {}; + +template <typename T> +struct Callback_ParamTraits<T, true> { + typedef const T& ForwardType; + static const bool kIsScopedHandle = false; +}; + +template <typename T> +struct Callback_ParamTraits<T, false> { + typedef T ForwardType; + static const bool kIsScopedHandle = false; +}; + +template <typename H> +struct Callback_ParamTraits<ScopedHandleBase<H>, true> { + typedef ScopedHandleBase<H> ForwardType; + static const bool kIsScopedHandle = true; +}; + +template<bool B, typename T = void> +struct EnableIf {}; + +template<typename T> +struct EnableIf<true, T> { typedef T type; }; + +template <typename T> +typename EnableIf<!Callback_ParamTraits<T>::kIsScopedHandle, T>::type& + Callback_Forward(T& t) { + return t; +} + +template <typename T> +typename EnableIf<Callback_ParamTraits<T>::kIsScopedHandle, T>::type + Callback_Forward(T& t) { + return t.Pass(); +} + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_ diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc new file mode 100644 index 0000000..319631c --- /dev/null +++ b/mojo/public/cpp/bindings/lib/connector.cc @@ -0,0 +1,130 @@ +// Copyright 2013 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/bindings/lib/connector.h" + +#include <assert.h> +#include <stdlib.h> + +#include "mojo/public/cpp/bindings/error_handler.h" + +namespace mojo { +namespace internal { + +// ---------------------------------------------------------------------------- + +Connector::Connector(ScopedMessagePipeHandle message_pipe, + MojoAsyncWaiter* waiter) + : error_handler_(NULL), + waiter_(waiter), + message_pipe_(message_pipe.Pass()), + incoming_receiver_(NULL), + async_wait_id_(0), + error_(false), + drop_writes_(false) { + // Even though we don't have an incoming receiver, we still want to monitor + // the message pipe to know if is closed or encounters an error. + WaitToReadMore(); +} + +Connector::~Connector() { + if (async_wait_id_) + waiter_->CancelWait(waiter_, async_wait_id_); +} + +void Connector::CloseMessagePipe() { + Close(message_pipe_.Pass()); +} + +bool Connector::Accept(Message* message) { + if (error_) + return false; + + if (drop_writes_) + return true; + + MojoResult rv = WriteMessageRaw( + message_pipe_.get(), + message->data(), + message->data_num_bytes(), + message->mutable_handles()->empty() ? NULL : + reinterpret_cast<const MojoHandle*>( + &message->mutable_handles()->front()), + static_cast<uint32_t>(message->mutable_handles()->size()), + MOJO_WRITE_MESSAGE_FLAG_NONE); + + switch (rv) { + case MOJO_RESULT_OK: + // The handles were successfully transferred, so we don't need the message + // to track their lifetime any longer. + message->mutable_handles()->clear(); + break; + case MOJO_RESULT_FAILED_PRECONDITION: + // There's no point in continuing to write to this pipe since the other + // end is gone. Avoid writing any future messages. Hide write failures + // from the caller since we'd like them to continue consuming any backlog + // of incoming messages before regarding the message pipe as closed. + drop_writes_ = true; + break; + default: + // This particular write was rejected, presumably because of bad input. + // The pipe is not necessarily in a bad state. + return false; + } + return true; +} + +bool Connector::AcceptWithResponder(Message* message, + MessageReceiver* responder) { + // TODO(darin): Implement this! + assert(false); + return false; +} + +// static +void Connector::CallOnHandleReady(void* closure, MojoResult result) { + Connector* self = static_cast<Connector*>(closure); + self->OnHandleReady(result); +} + +void Connector::OnHandleReady(MojoResult result) { + async_wait_id_ = 0; + + if (result == MOJO_RESULT_OK) { + ReadMore(); + } else { + error_ = true; + } + + if (error_ && error_handler_) + error_handler_->OnError(); +} + +void Connector::WaitToReadMore() { + async_wait_id_ = waiter_->AsyncWait(waiter_, + message_pipe_.get().value(), + MOJO_WAIT_FLAG_READABLE, + MOJO_DEADLINE_INDEFINITE, + &Connector::CallOnHandleReady, + this); +} + +void Connector::ReadMore() { + while (true) { + MojoResult rv; + + rv = ReadAndDispatchMessage(message_pipe_.get(), incoming_receiver_, NULL); + if (rv == MOJO_RESULT_SHOULD_WAIT) { + WaitToReadMore(); + break; + } + if (rv != MOJO_RESULT_OK) { + error_ = true; + break; + } + } +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/connector.h b/mojo/public/cpp/bindings/lib/connector.h new file mode 100644 index 0000000..21107d5 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/connector.h @@ -0,0 +1,80 @@ +// Copyright 2013 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_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ + +#include "mojo/public/cpp/bindings/lib/message_queue.h" +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/environment/default_async_waiter.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +class ErrorHandler; + +namespace internal { + +// The Connector class is responsible for performing read/write operations on a +// MessagePipe. It writes messages it receives through the MessageReceiver +// interface that it subclasses, and it forwards messages it reads through the +// MessageReceiver interface assigned as its incoming receiver. +// +// NOTE: MessagePipe I/O is non-blocking. +// +class Connector : public MessageReceiver { + public: + // The Connector takes ownership of |message_pipe|. + explicit Connector(ScopedMessagePipeHandle message_pipe, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()); + virtual ~Connector(); + + // Sets the receiver to handle messages read from the message pipe. The + // Connector will read messages from the pipe regardless of whether or not an + // incoming receiver has been set. + void set_incoming_receiver(MessageReceiver* receiver) { + incoming_receiver_ = receiver; + } + + // Sets the error handler to receive notifications when an error is + // encountered while reading from the pipe or waiting to read from the pipe. + void set_error_handler(ErrorHandler* error_handler) { + error_handler_ = error_handler; + } + + // Returns true if an error was encountered while reading from the pipe or + // waiting to read from the pipe. + bool encountered_error() const { return error_; } + + // Closes the pipe, triggering the error state. + void CloseMessagePipe(); + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) + MOJO_OVERRIDE; + + private: + static void CallOnHandleReady(void* closure, MojoResult result); + void OnHandleReady(MojoResult result); + + void WaitToReadMore(); + void ReadMore(); + + ErrorHandler* error_handler_; + MojoAsyncWaiter* waiter_; + + ScopedMessagePipeHandle message_pipe_; + MessageReceiver* incoming_receiver_; + + MojoAsyncWaitID async_wait_id_; + bool error_; + bool drop_writes_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Connector); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.cc b/mojo/public/cpp/bindings/lib/fixed_buffer.cc new file mode 100644 index 0000000..7e19ae2 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/fixed_buffer.cc @@ -0,0 +1,54 @@ +// 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/public/cpp/bindings/lib/fixed_buffer.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <algorithm> + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" + +namespace mojo { +namespace internal { + +FixedBuffer::FixedBuffer(size_t size) + : ptr_(NULL), + cursor_(0), + size_(internal::Align(size)) { + ptr_ = static_cast<char*>(calloc(size_, 1)); +} + +FixedBuffer::~FixedBuffer() { + free(ptr_); +} + +void* FixedBuffer::Allocate(size_t delta, Destructor dtor) { + assert(!dtor); + + delta = internal::Align(delta); + + if (delta == 0 || delta > size_ - cursor_) { + assert(false); + return NULL; + } + + char* result = ptr_ + cursor_; + cursor_ += delta; + + return result; +} + +void* FixedBuffer::Leak() { + char* ptr = ptr_; + ptr_ = NULL; + cursor_ = 0; + size_ = 0; + return ptr; +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.h b/mojo/public/cpp/bindings/lib/fixed_buffer.h new file mode 100644 index 0000000..f4a9905 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/fixed_buffer.h @@ -0,0 +1,68 @@ +// 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_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_ + +#include "mojo/public/cpp/bindings/buffer.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +// FixedBuffer provides a simple way to allocate objects within a fixed chunk +// of memory. Objects are allocated by calling the |Allocate| method, which +// extends the buffer accordingly. Objects allocated in this way are not freed +// explicitly. Instead, they remain valid so long as the FixedBuffer remains +// valid. The Leak method may be used to steal the underlying memory from the +// FixedBuffer. +// +// Typical usage: +// +// { +// FixedBuffer buf(8 + 8); +// +// int* a = static_cast<int*>(buf->Allocate(sizeof(int))); +// *a = 2; +// +// double* b = static_cast<double*>(buf->Allocate(sizeof(double))); +// *b = 3.14f; +// +// void* data = buf.Leak(); +// Process(data); +// +// free(data); +// } +// +class FixedBuffer : public Buffer { + public: + explicit FixedBuffer(size_t size); + virtual ~FixedBuffer(); + + // Grows the buffer by |num_bytes| and returns a pointer to the start of the + // addition. The resulting address is 8-byte aligned, and the content of the + // memory is zero-filled. + virtual void* Allocate(size_t num_bytes, Destructor func = NULL) + MOJO_OVERRIDE; + + size_t size() const { return size_; } + + // Returns the internal memory owned by the Buffer to the caller. The Buffer + // relinquishes its pointer, effectively resetting the state of the Buffer + // and leaving the caller responsible for freeing the returned memory address + // when no longer needed. + void* Leak(); + + private: + char* ptr_; + size_t cursor_; + size_t size_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(FixedBuffer); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_FIXED_BUFFER_H_ diff --git a/mojo/public/cpp/bindings/lib/interface.cc b/mojo/public/cpp/bindings/lib/interface.cc new file mode 100644 index 0000000..3b552be --- /dev/null +++ b/mojo/public/cpp/bindings/lib/interface.cc @@ -0,0 +1,19 @@ +// 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/public/cpp/bindings/interface.h" + +namespace mojo { + +bool NoInterfaceStub::Accept(Message* message) { + return false; +} + +bool NoInterfaceStub::AcceptWithResponder(Message* message, + MessageReceiver* responder) { + return false; +} + +} // namespace mojo + diff --git a/mojo/public/cpp/bindings/lib/message.cc b/mojo/public/cpp/bindings/lib/message.cc new file mode 100644 index 0000000..8ec188e2 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/message.cc @@ -0,0 +1,84 @@ +// Copyright 2013 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/bindings/message.h" + +#include <assert.h> +#include <stdlib.h> + +#include <algorithm> + +namespace mojo { + +Message::Message() + : data_num_bytes_(0), + data_(NULL) { +} + +Message::~Message() { + free(data_); + + for (std::vector<Handle>::iterator it = handles_.begin(); + it != handles_.end(); ++it) { + if (it->is_valid()) + CloseRaw(*it); + } +} + +void Message::AllocUninitializedData(uint32_t num_bytes) { + assert(!data_); + data_num_bytes_ = num_bytes; + data_ = static_cast<internal::MessageData*>(malloc(num_bytes)); +} + +void Message::AdoptData(uint32_t num_bytes, internal::MessageData* data) { + assert(!data_); + data_num_bytes_ = num_bytes; + data_ = data; +} + +void Message::Swap(Message* other) { + std::swap(data_num_bytes_, other->data_num_bytes_); + std::swap(data_, other->data_); + std::swap(handles_, other->handles_); +} + +MojoResult ReadAndDispatchMessage(MessagePipeHandle handle, + MessageReceiver* receiver, + bool* receiver_result) { + MojoResult rv; + + uint32_t num_bytes = 0, num_handles = 0; + rv = ReadMessageRaw(handle, + NULL, + &num_bytes, + NULL, + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + if (rv != MOJO_RESULT_RESOURCE_EXHAUSTED) + return rv; + + Message message; + message.AllocUninitializedData(num_bytes); + message.mutable_handles()->resize(num_handles); + + rv = ReadMessageRaw(handle, + message.mutable_data(), + &num_bytes, + message.mutable_handles()->empty() + ? NULL + : reinterpret_cast<MojoHandle*>( + &message.mutable_handles()->front()), + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + if (receiver && rv == MOJO_RESULT_OK) { + bool result = receiver->Accept(&message); + if (receiver_result) + *receiver_result = result; + } + + return rv; +} + +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/message_builder.cc b/mojo/public/cpp/bindings/lib/message_builder.cc new file mode 100644 index 0000000..c746644 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/message_builder.cc @@ -0,0 +1,52 @@ +// Copyright 2013 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/bindings/lib/message_builder.h" + +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { +namespace internal { + +template <typename Header> +void Allocate(Buffer* buf, Header** header) { + *header = static_cast<Header*>(buf->Allocate(sizeof(Header))); + (*header)->num_bytes = sizeof(Header); +} + +MessageBuilder::MessageBuilder(uint32_t name, size_t payload_size) + : buf_(sizeof(MessageHeader) + payload_size) { + MessageHeader* header; + Allocate(&buf_, &header); + header->num_fields = 2; + header->name = name; +} + +MessageBuilder::~MessageBuilder() { +} + +void MessageBuilder::Finish(Message* message) { + uint32_t num_bytes = static_cast<uint32_t>(buf_.size()); + message->AdoptData(num_bytes, static_cast<MessageData*>(buf_.Leak())); +} + +MessageBuilder::MessageBuilder(size_t size) + : buf_(size) { +} + +MessageWithRequestIDBuilder::MessageWithRequestIDBuilder(uint32_t name, + size_t payload_size, + uint32_t flags, + uint64_t request_id) + : MessageBuilder(sizeof(MessageHeaderWithRequestID) + payload_size) { + MessageHeaderWithRequestID* header; + Allocate(&buf_, &header); + header->num_fields = 3; + header->name = name; + header->flags = flags; + header->request_id = request_id; +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/message_builder.h b/mojo/public/cpp/bindings/lib/message_builder.h new file mode 100644 index 0000000..b4988ff9 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/message_builder.h @@ -0,0 +1,63 @@ +// Copyright 2013 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_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_ + +#include <stdint.h> + +#include "mojo/public/cpp/bindings/lib/fixed_buffer.h" +#include "mojo/public/cpp/bindings/lib/message_internal.h" + +namespace mojo { +class Message; + +namespace internal { + +class MessageBuilder { + public: + MessageBuilder(uint32_t name, size_t payload_size); + ~MessageBuilder(); + + Buffer* buffer() { return &buf_; } + + // Call Finish when done making allocations in |buffer()|. Upon return, + // |message| will contain the message data, and |buffer()| will no longer be + // valid to reference. + void Finish(Message* message); + + protected: + explicit MessageBuilder(size_t size); + FixedBuffer buf_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(MessageBuilder); +}; + +class MessageWithRequestIDBuilder : public MessageBuilder { + public: + MessageWithRequestIDBuilder(uint32_t name, size_t payload_size, + uint32_t flags, uint64_t request_id); +}; + +class RequestMessageBuilder : public MessageWithRequestIDBuilder { + public: + RequestMessageBuilder(uint32_t name, size_t payload_size) + : MessageWithRequestIDBuilder(name, payload_size, kMessageExpectsResponse, + 0) { + } +}; + +class ResponseMessageBuilder : public MessageWithRequestIDBuilder { + public: + ResponseMessageBuilder(uint32_t name, size_t payload_size, + uint64_t request_id) + : MessageWithRequestIDBuilder(name, payload_size, kMessageIsResponse, + request_id) { + } +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_BUILDER_H_ diff --git a/mojo/public/cpp/bindings/lib/message_internal.h b/mojo/public/cpp/bindings/lib/message_internal.h new file mode 100644 index 0000000..3c67902 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/message_internal.h @@ -0,0 +1,44 @@ +// 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_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_ + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" + +namespace mojo { +namespace internal { + +#pragma pack(push, 1) + +enum { + kMessageExpectsResponse = 1 << 0, + kMessageIsResponse = 1 << 1 +}; + +struct MessageHeader : internal::StructHeader { + uint32_t name; + uint32_t flags; +}; +MOJO_COMPILE_ASSERT(sizeof(MessageHeader) == 16, bad_sizeof_MessageHeader); + +struct MessageHeaderWithRequestID : MessageHeader { + uint64_t request_id; +}; +MOJO_COMPILE_ASSERT(sizeof(MessageHeaderWithRequestID) == 24, + bad_sizeof_MessageHeaderWithRequestID); + +struct MessageData { + MessageHeader header; +}; + +MOJO_COMPILE_ASSERT(sizeof(MessageData) == sizeof(MessageHeader), + bad_sizeof_MessageData); + +#pragma pack(pop) + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_INTERNAL_H_ diff --git a/mojo/public/cpp/bindings/lib/message_queue.cc b/mojo/public/cpp/bindings/lib/message_queue.cc new file mode 100644 index 0000000..1982ccb --- /dev/null +++ b/mojo/public/cpp/bindings/lib/message_queue.cc @@ -0,0 +1,50 @@ +// Copyright 2013 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/bindings/lib/message_queue.h" + +#include <assert.h> +#include <stddef.h> + +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { +namespace internal { + +MessageQueue::MessageQueue() { +} + +MessageQueue::~MessageQueue() { + while (!queue_.empty()) + Pop(); +} + +bool MessageQueue::IsEmpty() const { + return queue_.empty(); +} + +Message* MessageQueue::Peek() { + assert(!queue_.empty()); + return queue_.front(); +} + +void MessageQueue::Push(Message* message) { + queue_.push(new Message()); + queue_.back()->Swap(message); +} + +void MessageQueue::Pop(Message* message) { + assert(!queue_.empty()); + queue_.front()->Swap(message); + Pop(); +} + +void MessageQueue::Pop() { + assert(!queue_.empty()); + delete queue_.front(); + queue_.pop(); +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/message_queue.h b/mojo/public/cpp/bindings/lib/message_queue.h new file mode 100644 index 0000000..4e46b54 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/message_queue.h @@ -0,0 +1,47 @@ +// Copyright 2013 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_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_ + +#include <queue> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +class Message; + +namespace internal { + +// A queue for Message objects. +class MessageQueue { + public: + MessageQueue(); + ~MessageQueue(); + + bool IsEmpty() const; + Message* Peek(); + + // This method transfers ownership of |message->data| and |message->handles| + // to the message queue, resetting |message| in the process. + void Push(Message* message); + + // Removes the next message from the queue, transferring ownership of its + // data and handles to the given |message|. + void Pop(Message* message); + + // Removes the next message from the queue, discarding its data and handles. + // This is meant to be used in conjunction with |Peek|. + void Pop(); + + private: + std::queue<Message*> queue_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(MessageQueue); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_QUEUE_H_ diff --git a/mojo/public/cpp/bindings/lib/router.cc b/mojo/public/cpp/bindings/lib/router.cc new file mode 100644 index 0000000..594addc --- /dev/null +++ b/mojo/public/cpp/bindings/lib/router.cc @@ -0,0 +1,137 @@ +// 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/public/cpp/bindings/lib/router.h" + +namespace mojo { +namespace internal { + +// ---------------------------------------------------------------------------- + +class ResponderThunk : public MessageReceiver { + public: + explicit ResponderThunk(const SharedData<Router*>& router) + : router_(router) { + } + virtual ~ResponderThunk() { + } + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE { + assert(message->has_flag(kMessageIsResponse)); + + bool result = false; + + Router* router = router_.value(); + if (router) + result = router->Accept(message); + + return result; + } + + virtual bool AcceptWithResponder(Message* message, + MessageReceiver* responder) MOJO_OVERRIDE { + assert(false); // not reached! + return false; + } + + private: + SharedData<Router*> router_; +}; + +// ---------------------------------------------------------------------------- + +Router::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router) + : router_(router) { +} + +Router::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() { +} + +bool Router::HandleIncomingMessageThunk::Accept(Message* message) { + return router_->HandleIncomingMessage(message); +} + +bool Router::HandleIncomingMessageThunk::AcceptWithResponder( + Message* message, + MessageReceiver* responder) { + assert(false); // not reached! + return false; +} + +// ---------------------------------------------------------------------------- + +Router::Router(ScopedMessagePipeHandle message_pipe, MojoAsyncWaiter* waiter) + : connector_(message_pipe.Pass(), waiter), + weak_self_(this), + incoming_receiver_(NULL), + thunk_(this), + next_request_id_(0) { + connector_.set_incoming_receiver(&thunk_); +} + +Router::~Router() { + weak_self_.set_value(NULL); +} + +bool Router::Accept(Message* message) { + assert(!message->has_flag(kMessageExpectsResponse)); + return connector_.Accept(message); +} + +bool Router::AcceptWithResponder(Message* message, + MessageReceiver* responder) { + assert(message->has_flag(kMessageExpectsResponse)); + + // Reserve 0 in case we want it to convey special meaning in the future. + uint64_t request_id = next_request_id_++; + if (request_id == 0) + request_id = next_request_id_++; + + message->set_request_id(request_id); + if (!connector_.Accept(message)) + return false; + + // We assume ownership of |responder|. + responders_[request_id] = responder; + return true; +} + +bool Router::HandleIncomingMessage(Message* message) { + if (message->has_flag(kMessageExpectsResponse)) { + if (incoming_receiver_) { + MessageReceiver* responder = new ResponderThunk(weak_self_); + bool ok = incoming_receiver_->AcceptWithResponder(message, responder); + if (!ok) + delete responder; + return ok; + } + + // If we receive a request expecting a response when the client is not + // listening, then we have no choice but to tear down the pipe. + connector_.CloseMessagePipe(); + } else if (message->has_flag(kMessageIsResponse)) { + uint64_t request_id = message->request_id(); + ResponderMap::iterator it = responders_.find(request_id); + if (it == responders_.end()) { + assert(false); + return false; + } + MessageReceiver* responder = it->second; + responders_.erase(it); + responder->Accept(message); + delete responder; + } else { + if (incoming_receiver_) + return incoming_receiver_->Accept(message); + // OK to drop message on the floor. + } + + return false; +} + +// ---------------------------------------------------------------------------- + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/router.h b/mojo/public/cpp/bindings/lib/router.h new file mode 100644 index 0000000..31c05f6 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/router.h @@ -0,0 +1,73 @@ +// 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_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_ + +#include <map> + +#include "mojo/public/cpp/bindings/lib/connector.h" +#include "mojo/public/cpp/bindings/lib/shared_data.h" + +namespace mojo { +namespace internal { + +class Router : public MessageReceiver { + public: + // The Router takes ownership of |message_pipe|. + explicit Router(ScopedMessagePipeHandle message_pipe, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()); + virtual ~Router(); + + // Sets the receiver to handle messages read from the message pipe that do + // not have the kMessageIsResponse flag set. + void set_incoming_receiver(MessageReceiver* receiver) { + incoming_receiver_ = receiver; + } + + // Sets the error handler to receive notifications when an error is + // encountered while reading from the pipe or waiting to read from the pipe. + void set_error_handler(ErrorHandler* error_handler) { + connector_.set_error_handler(error_handler); + } + + // Returns true if an error was encountered while reading from the pipe or + // waiting to read from the pipe. + bool encountered_error() const { return connector_.encountered_error(); } + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) + MOJO_OVERRIDE; + + private: + typedef std::map<uint64_t, MessageReceiver*> ResponderMap; + + class HandleIncomingMessageThunk : public MessageReceiver { + public: + HandleIncomingMessageThunk(Router* router); + virtual ~HandleIncomingMessageThunk(); + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(Message* message, + MessageReceiver* responder) MOJO_OVERRIDE; + private: + Router* router_; + }; + + bool HandleIncomingMessage(Message* message); + + Connector connector_; + SharedData<Router*> weak_self_; + MessageReceiver* incoming_receiver_; + HandleIncomingMessageThunk thunk_; + ResponderMap responders_; + uint64_t next_request_id_; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_ diff --git a/mojo/public/cpp/bindings/lib/scratch_buffer.cc b/mojo/public/cpp/bindings/lib/scratch_buffer.cc new file mode 100644 index 0000000..cb894e3 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/scratch_buffer.cc @@ -0,0 +1,98 @@ +// 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/public/cpp/bindings/lib/scratch_buffer.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <algorithm> + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" + +// Scrub memory in debug builds to help catch use-after-free bugs. +#ifdef NDEBUG +#define DEBUG_SCRUB(address, size) (void) (address), (void) (size) +#else +#define DEBUG_SCRUB(address, size) memset(address, 0xCD, size) +#endif + +namespace mojo { +namespace internal { + +ScratchBuffer::ScratchBuffer() + : overflow_(NULL) { + fixed_.next = NULL; + fixed_.cursor = fixed_data_; + fixed_.end = fixed_data_ + kMinSegmentSize; +} + +ScratchBuffer::~ScratchBuffer() { + // Invoke destructors in reverse order to mirror allocation order. + std::deque<PendingDestructor>::reverse_iterator it; + for (it = pending_dtors_.rbegin(); it != pending_dtors_.rend(); ++it) + it->func(it->address); + + while (overflow_) { + Segment* doomed = overflow_; + overflow_ = overflow_->next; + DEBUG_SCRUB(doomed, doomed->end - reinterpret_cast<char*>(doomed)); + free(doomed); + } + DEBUG_SCRUB(fixed_data_, sizeof(fixed_data_)); +} + +void* ScratchBuffer::Allocate(size_t delta, Destructor func) { + delta = internal::Align(delta); + + void* result = AllocateInSegment(&fixed_, delta); + if (!result) { + if (overflow_) + result = AllocateInSegment(overflow_, delta); + + if (!result) { + AddOverflowSegment(delta); + result = AllocateInSegment(overflow_, delta); + } + } + + if (func) { + PendingDestructor dtor; + dtor.func = func; + dtor.address = result; + pending_dtors_.push_back(dtor); + } + return result; +} + +void* ScratchBuffer::AllocateInSegment(Segment* segment, size_t delta) { + void* result; + if (static_cast<size_t>(segment->end - segment->cursor) >= delta) { + result = segment->cursor; + memset(result, 0, delta); + segment->cursor += delta; + } else { + result = NULL; + } + return result; +} + +void ScratchBuffer::AddOverflowSegment(size_t delta) { + if (delta < kMinSegmentSize) + delta = kMinSegmentSize; + + // Ensure segment buffer is aligned. + size_t segment_size = internal::Align(sizeof(Segment)) + delta; + + Segment* segment = static_cast<Segment*>(malloc(segment_size)); + segment->next = overflow_; + segment->cursor = reinterpret_cast<char*>(segment + 1); + segment->end = segment->cursor + delta; + + overflow_ = segment; +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/public/cpp/bindings/lib/scratch_buffer.h b/mojo/public/cpp/bindings/lib/scratch_buffer.h new file mode 100644 index 0000000..462c6fe --- /dev/null +++ b/mojo/public/cpp/bindings/lib/scratch_buffer.h @@ -0,0 +1,54 @@ +// 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_PUBLIC_CPP_BINDINGS_LIB_SCRATCH_BUFFER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SCRATCH_BUFFER_H_ + +#include <deque> + +#include "mojo/public/cpp/bindings/buffer.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +// The following class is designed to be allocated on the stack. If necessary, +// it will failover to allocating objects on the heap. +class ScratchBuffer : public Buffer { + public: + ScratchBuffer(); + virtual ~ScratchBuffer(); + + virtual void* Allocate(size_t num_bytes, Destructor func = NULL) + MOJO_OVERRIDE; + + private: + enum { kMinSegmentSize = 512 }; + + struct Segment { + Segment* next; + char* cursor; + char* end; + }; + + void* AllocateInSegment(Segment* segment, size_t num_bytes); + void AddOverflowSegment(size_t delta); + + char fixed_data_[kMinSegmentSize]; + Segment fixed_; + Segment* overflow_; + + struct PendingDestructor { + Destructor func; + void* address; + }; + std::deque<PendingDestructor> pending_dtors_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ScratchBuffer); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SCRATCH_BUFFER_H_ diff --git a/mojo/public/cpp/bindings/lib/shared_data.h b/mojo/public/cpp/bindings/lib/shared_data.h new file mode 100644 index 0000000..e396b0d --- /dev/null +++ b/mojo/public/cpp/bindings/lib/shared_data.h @@ -0,0 +1,81 @@ +// 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_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ + +namespace mojo { +namespace internal { + +// Used to allocate an instance of T that can be shared via reference counting. +template <typename T> +class SharedData { + public: + ~SharedData() { + holder_->Release(); + } + + SharedData() : holder_(new Holder()) { + } + + explicit SharedData(const T& value) : holder_(new Holder(value)) { + } + + SharedData(const SharedData<T>& other) : holder_(other.holder_) { + holder_->Retain(); + } + + SharedData<T>& operator=(const SharedData<T>& other) { + if (other.holder_ == holder_) + return *this; + holder_->Release(); + holder_ = other.holder_; + holder_->Retain(); + } + + void reset() { + holder_->Release(); + holder_ = new Holder(); + } + + void reset(const T& value) { + holder_->Release(); + holder_ = new Holder(value); + } + + void set_value(const T& value) { + holder_->value = value; + } + T* mutable_value() { + return &holder_->value; + } + const T& value() const { + return holder_->value; + } + + private: + class Holder { + public: + Holder() : value(), ref_count_(1) { + } + Holder(const T& value) : value(value), ref_count_(1) { + } + + void Retain() { ++ref_count_; } + void Release() { if (--ref_count_ == 0) delete this; } + + T value; + + private: + int ref_count_; + MOJO_DISALLOW_COPY_AND_ASSIGN(Holder); + }; + + Holder* holder_; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_DATA_H_ diff --git a/mojo/public/cpp/bindings/lib/shared_ptr.h b/mojo/public/cpp/bindings/lib/shared_ptr.h new file mode 100644 index 0000000..6ae53a5 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/shared_ptr.h @@ -0,0 +1,63 @@ +// 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_PUBLIC_CPP_BINDINGS_LIB_SHARED_PTR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_PTR_H_ + +#include "mojo/public/cpp/bindings/lib/shared_data.h" + +namespace mojo { +namespace internal { + +// Used to manage a heap-allocated instance of P that can be shared via +// reference counting. When the last reference is dropped, the instance is +// deleted. +template <typename P> +class SharedPtr { + public: + SharedPtr() {} + + explicit SharedPtr(P* ptr) { + impl_.mutable_value()->ptr = ptr; + } + + // Default copy-constructor and assignment operator are OK. + + P* get() { + return impl_.value().ptr; + } + const P* get() const { + return impl_.value().ptr; + } + + P* operator->() { return get(); } + const P* operator->() const { return get(); } + + private: + class Impl { + public: + ~Impl() { + if (ptr) + delete ptr; + } + + Impl() : ptr(NULL) { + } + + Impl(P* ptr) : ptr(ptr) { + } + + P* ptr; + + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(Impl); + }; + + SharedData<Impl> impl_; +}; + +} // namespace mojo +} // namespace internal + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SHARED_PTR_H_ diff --git a/mojo/public/cpp/bindings/lib/sync_dispatcher.cc b/mojo/public/cpp/bindings/lib/sync_dispatcher.cc new file mode 100644 index 0000000..acb537e --- /dev/null +++ b/mojo/public/cpp/bindings/lib/sync_dispatcher.cc @@ -0,0 +1,27 @@ +// 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/public/cpp/bindings/sync_dispatcher.h" + +#include <stdlib.h> + +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { + +bool WaitForMessageAndDispatch(MessagePipeHandle handle, + MessageReceiver* receiver) { + while (true) { + bool result; + MojoResult rv = ReadAndDispatchMessage(handle, receiver, &result); + if (rv == MOJO_RESULT_OK) + return result; + if (rv == MOJO_RESULT_SHOULD_WAIT) + rv = Wait(handle, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE); + if (rv != MOJO_RESULT_OK) + return false; + } +} + +} // namespace mojo diff --git a/mojo/public/cpp/bindings/message.h b/mojo/public/cpp/bindings/message.h index 8df1ce0..58001c6 100644 --- a/mojo/public/cpp/bindings/message.h +++ b/mojo/public/cpp/bindings/message.h @@ -9,7 +9,7 @@ #include <vector> -#include "mojo/public/bindings/lib/message_internal.h" +#include "mojo/public/cpp/bindings/lib/message_internal.h" namespace mojo { diff --git a/mojo/public/cpp/bindings/passable.h b/mojo/public/cpp/bindings/passable.h index 3d5c2ca..0e109d6 100644 --- a/mojo/public/cpp/bindings/passable.h +++ b/mojo/public/cpp/bindings/passable.h @@ -5,7 +5,7 @@ #ifndef MOJO_PUBLIC_CPP_BINDINGS_PASSABLE_H_ #define MOJO_PUBLIC_CPP_BINDINGS_PASSABLE_H_ -#include "mojo/public/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" #include "mojo/public/cpp/system/core.h" namespace mojo { diff --git a/mojo/public/cpp/bindings/remote_ptr.h b/mojo/public/cpp/bindings/remote_ptr.h index 9bc629f..63ee719 100644 --- a/mojo/public/cpp/bindings/remote_ptr.h +++ b/mojo/public/cpp/bindings/remote_ptr.h @@ -7,8 +7,8 @@ #include <assert.h> -#include "mojo/public/bindings/lib/router.h" #include "mojo/public/cpp/bindings/interface.h" +#include "mojo/public/cpp/bindings/lib/router.h" #include "mojo/public/cpp/system/macros.h" namespace mojo { |