diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/mojo/public/cpp | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/mojo/public/cpp')
96 files changed, 7307 insertions, 0 deletions
diff --git a/chromium/mojo/public/cpp/DEPS b/chromium/mojo/public/cpp/DEPS new file mode 100644 index 00000000000..74acd7c7ed3 --- /dev/null +++ b/chromium/mojo/public/cpp/DEPS @@ -0,0 +1,18 @@ +include_rules = [ + # Require explicit dependencies in each directory. + "-mojo/public", + # But everyone can depend on the C and C++ system headers. + "+mojo/public/c/system", + "+mojo/public/cpp/system", + # Ditto for the C environment headers (but not the C++ environment, since it + # has dependencies of its own). + "+mojo/public/c/environment", +] + +specific_include_rules = { + r".*_(unit|perf)test\.cc": [ + "+testing", + "+mojo/public/cpp/test_support", + "+mojo/public/cpp/utility", + ], +} diff --git a/chromium/mojo/public/cpp/README.md b/chromium/mojo/public/cpp/README.md new file mode 100644 index 00000000000..8f03d984b9a --- /dev/null +++ b/chromium/mojo/public/cpp/README.md @@ -0,0 +1,71 @@ +Mojo Public C++ API +=================== + +This directory contains C++ language bindings for the Mojo Public API. + +A number of subdirectories provide wrappers for the lower-level C APIs (in +subdirectories of the same name, under mojo/public/c/). Typically, these +wrappers provide increased convenience and/or type-safety. + +Other subdirectories provide support (static) libraries of various sorts. In +this case, the organization is to have the public interface for the library in +defined in header files in the subdirectory itself and the implementation of the +library at a lower level, under a lib (sub)subdirectory. A developer should be +able to substitute their own implementation of any such support library, and +expect other support libraries, which may depend on that library, to work +properly. + +Bindings +-------- + +The bindings/ subdirectory contains a support (static) library needed by the +code generated by the bindings generator tool (in mojo/public/tools/bindings/), +which translates Mojo IDL (.mojom) files into idiomatic C++ (among other +languages). + +This library depends on the Environment library. + +Environment +----------- + +The environment/ subdirectory contains a support (static) library that +represents shared state needed to support the Bindings and GLES2 libraries. + +This library depends on the Utility library. + + +GLES2 +----- + +The gles2/ subdirectory contains C++ wrappers (and some additional helpers) of +the API defined in mojo/public/c/gles2/ (which provides access to GLES2). + +These wrappers depend on the Environment library. + +Shell +----- + +The shell/ subdirectory contains a support (static) library that aids in writing +Mojo applications and interacting with the Shell service. + +System +------ + +The system/ subdirectory contains C++ wrappers (and some additional helpers) of +the API defined in mojo/public/c/system/, which defines the basic, "core" API, +especially used to communicate with Mojo services. + +Test Support +------------ + +The test_support/ subdirectory contains C++ wrappers of the test-only API +defined in mojo/public/c/test_support/. It is not meant for general use by Mojo +applications. + +Utility +------- + +The utility/ subdirectory contains a support (static) library that provides +various basic functionality. Most notably, it provides an implementation of a +RunLoop based on MojoWaitMany() that applications may use as the basis for +asynchronous message processing. diff --git a/chromium/mojo/public/cpp/application/DEPS b/chromium/mojo/public/cpp/application/DEPS new file mode 100644 index 00000000000..e808b79707e --- /dev/null +++ b/chromium/mojo/public/cpp/application/DEPS @@ -0,0 +1,14 @@ +include_rules = [ + "+mojo/public/cpp/bindings", + "+mojo/public/interfaces/service_provider", +] + +specific_include_rules = { + "mojo_main_chromium.cc": [ + "+base", + "+mojo/public/cpp" + ], + "mojo_main_standalone.cc": [ + "+mojo/public/cpp" + ], +} diff --git a/chromium/mojo/public/cpp/application/application.h b/chromium/mojo/public/cpp/application/application.h new file mode 100644 index 00000000000..da7a0ed7c61 --- /dev/null +++ b/chromium/mojo/public/cpp/application/application.h @@ -0,0 +1,121 @@ +// 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_APPLICATION_APPLICATION_H_ +#define MOJO_PUBLIC_APPLICATION_APPLICATION_H_ +#include <vector> + +#include "mojo/public/cpp/application/connect.h" +#include "mojo/public/cpp/application/lib/service_connector.h" +#include "mojo/public/cpp/system/core.h" +#include "mojo/public/interfaces/service_provider/service_provider.mojom.h" + +#if defined(WIN32) +#if !defined(CDECL) +#define CDECL __cdecl +#endif +#define APPLICATION_EXPORT __declspec(dllexport) +#else +#define CDECL +#define APPLICATION_EXPORT __attribute__((visibility("default"))) +#endif + +// DSOs can either implement MojoMain directly or include +// mojo_main_{standalone|chromium}.cc in their project and implement +// Application::Create(); +// TODO(davemoore): Establish this as part of our SDK for third party mojo +// application writers. +extern "C" APPLICATION_EXPORT MojoResult CDECL MojoMain( + MojoHandle service_provider_handle); + +namespace mojo { + +// Utility class for creating ServiceProviders that vend service instances. +// To use define a class that implements your specific server api, e.g. FooImpl +// to implement a service named Foo. +// That class must subclass an InterfaceImpl specialization. +// +// If there is context that is to be shared amongst all instances, define a +// constructor with that class as its only argument, otherwise define an empty +// constructor. +// +// class FooImpl : public InterfaceImpl<Foo> { +// public: +// FooImpl() {} +// }; +// +// or +// +// class BarImpl : public InterfaceImpl<Bar> { +// public: +// // context will remain valid for the lifetime of BarImpl. +// BarImpl(BarContext* context) : context_(context) {} +// private: +// BarContext* context; +// }; +// +// Create an Application instance that collects any service implementations. +// +// Application app(service_provider_handle); +// app.AddService<FooImpl>(); +// +// BarContext context; +// app.AddService<BarImpl>(&context); +// +// +class Application { + public: + Application(); + explicit Application(ScopedMessagePipeHandle service_provider_handle); + explicit Application(MojoHandle service_provider_handle); + virtual ~Application(); + + // Override this method to control what urls are allowed to connect to a + // service. + virtual bool AllowIncomingConnection(const mojo::String& service_name, + const mojo::String& requestor_url); + + template <typename Impl, typename Context> + void AddService(Context* context) { + service_registry_.AddServiceConnector( + new internal::ServiceConnector<Impl, Context>(Impl::Name_, context)); + } + + template <typename Impl> + void AddService() { + service_registry_.AddServiceConnector( + new internal::ServiceConnector<Impl, void>(Impl::Name_, NULL)); + } + + template <typename Interface> + void ConnectTo(const std::string& url, InterfacePtr<Interface>* ptr) { + mojo::ConnectToService(service_provider(), url, ptr); + } + + ServiceProvider* service_provider() { + return service_registry_.remote_service_provider(); + } + + void BindServiceProvider(ScopedMessagePipeHandle service_provider_handle); + + protected: + // Override this to do any necessary initialization. There's no need to call + // Application's implementation. + // The service_provider will be bound to its pipe before this is called. + virtual void Initialize(); + + private: + friend MojoResult (::MojoMain)(MojoHandle); + + // Implement this method to create the specific subclass of Application. + static Application* Create(); + + internal::ServiceRegistry service_registry_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Application); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_APPLICATION_APPLICATION_H_ diff --git a/chromium/mojo/public/cpp/application/connect.h b/chromium/mojo/public/cpp/application/connect.h new file mode 100644 index 00000000000..e4ba641e2ed --- /dev/null +++ b/chromium/mojo/public/cpp/application/connect.h @@ -0,0 +1,24 @@ +// 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_APPLICATION_CONNECT_H_ +#define MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_ + +#include "mojo/public/interfaces/service_provider/service_provider.mojom.h" + +namespace mojo { + +template <typename Interface> +inline void ConnectToService(ServiceProvider* service_provider, + const std::string& url, + InterfacePtr<Interface>* ptr) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass()); + service_provider->ConnectToService( + url, Interface::Name_, pipe.handle1.Pass(), std::string()); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_APPLICATION_CONNECT_H_ diff --git a/chromium/mojo/public/cpp/application/lib/application.cc b/chromium/mojo/public/cpp/application/lib/application.cc new file mode 100644 index 00000000000..78f5a8bbd0e --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/application.cc @@ -0,0 +1,34 @@ +// 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/application/application.h" + +namespace mojo { + +Application::Application() : service_registry_(this) {} + +Application::Application(ScopedMessagePipeHandle service_provider_handle) + : service_registry_(this, service_provider_handle.Pass()) {} + +Application::Application(MojoHandle service_provider_handle) + : service_registry_( + this, + mojo::MakeScopedHandle( + MessagePipeHandle(service_provider_handle)).Pass()) {} + +Application::~Application() {} + +bool Application::AllowIncomingConnection(const mojo::String& service_name, + const mojo::String& requestor_url) { + return true; +} + +void Application::BindServiceProvider( + ScopedMessagePipeHandle service_provider_handle) { + service_registry_.BindRemoteServiceProvider(service_provider_handle.Pass()); +} + +void Application::Initialize() {} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/application/lib/mojo_main_chromium.cc b/chromium/mojo/public/cpp/application/lib/mojo_main_chromium.cc new file mode 100644 index 00000000000..cda7cd02d18 --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/mojo_main_chromium.cc @@ -0,0 +1,23 @@ +// 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 "base/at_exit.h" +#include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "mojo/public/cpp/application/application.h" + +extern "C" APPLICATION_EXPORT MojoResult CDECL MojoMain( + MojoHandle service_provider_handle) { + base::CommandLine::Init(0, NULL); + base::AtExitManager at_exit; + base::MessageLoop loop; + + scoped_ptr<mojo::Application> app(mojo::Application::Create()); + app->BindServiceProvider( + mojo::MakeScopedHandle(mojo::MessagePipeHandle(service_provider_handle))); + app->Initialize(); + loop.Run(); + + return MOJO_RESULT_OK; +} diff --git a/chromium/mojo/public/cpp/application/lib/mojo_main_standalone.cc b/chromium/mojo/public/cpp/application/lib/mojo_main_standalone.cc new file mode 100644 index 00000000000..05825aa3319 --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/mojo_main_standalone.cc @@ -0,0 +1,22 @@ +// 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/application/application.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/utility/run_loop.h" + +extern "C" APPLICATION_EXPORT MojoResult CDECL MojoMain( + MojoHandle service_provider_handle) { + mojo::Environment env; + mojo::RunLoop loop; + + mojo::Application* app = mojo::Application::Create(); + app->BindServiceProvider( + mojo::MakeScopedHandle(mojo::MessagePipeHandle(service_provider_handle))); + app->Initialize(); + loop.Run(); + delete app; + + return MOJO_RESULT_OK; +} diff --git a/chromium/mojo/public/cpp/application/lib/service_connector.cc b/chromium/mojo/public/cpp/application/lib/service_connector.cc new file mode 100644 index 00000000000..5cc4421b7aa --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/service_connector.cc @@ -0,0 +1,18 @@ +// 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/application/lib/service_connector.h" + +namespace mojo { +namespace internal { + +ServiceConnectorBase::ServiceConnectorBase(const std::string& name) + : name_(name), + registry_(NULL) { +} + +ServiceConnectorBase::~ServiceConnectorBase() {} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/application/lib/service_connector.h b/chromium/mojo/public/cpp/application/lib/service_connector.h new file mode 100644 index 00000000000..30786adb55d --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/service_connector.h @@ -0,0 +1,133 @@ +// 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_APPLICATION_LIB_SERVICE_CONNECTOR_H_ +#define MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_CONNECTOR_H_ + +#include <assert.h> + +#include <vector> + +#include "mojo/public/cpp/application/lib/service_registry.h" +#include "mojo/public/interfaces/service_provider/service_provider.mojom.h" + +namespace mojo { +namespace internal { + +template <class ServiceImpl, typename Context> +class ServiceConnector; + +// Specialization of ServiceConnection. +// ServiceImpl: Subclass of InterfaceImpl<...>. +// Context: Type of shared context. +template <class ServiceImpl, typename Context> +class ServiceConnection : public ServiceImpl { + public: + ServiceConnection() : ServiceImpl() {} + ServiceConnection(Context* context) : ServiceImpl(context) {} + + virtual void OnConnectionError() MOJO_OVERRIDE { + service_connector_->RemoveConnection(static_cast<ServiceImpl*>(this)); + ServiceImpl::OnConnectionError(); + } + +private: + friend class ServiceConnector<ServiceImpl, Context>; + + // Called shortly after this class is instantiated. + void set_service_connector( + ServiceConnector<ServiceImpl, Context>* connector) { + service_connector_ = connector; + } + + ServiceConnector<ServiceImpl, Context>* service_connector_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnection); +}; + +template <typename ServiceImpl, typename Context> +struct ServiceConstructor { + static ServiceConnection<ServiceImpl, Context>* New(Context* context) { + return new ServiceConnection<ServiceImpl, Context>(context); + } +}; + +template <typename ServiceImpl> +struct ServiceConstructor<ServiceImpl, void> { + public: + static ServiceConnection<ServiceImpl, void>* New(void* context) { + return new ServiceConnection<ServiceImpl, void>(); + } +}; + +class ServiceConnectorBase { + public: + ServiceConnectorBase(const std::string& name); + virtual ~ServiceConnectorBase(); + virtual void ConnectToService(const std::string& url, + const std::string& name, + ScopedMessagePipeHandle client_handle) = 0; + std::string name() const { return name_; } + void set_registry(ServiceRegistry* registry) { registry_ = registry; } + + protected: + std::string name_; + ServiceRegistry* registry_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnectorBase); +}; + +template <class ServiceImpl, typename Context=void> +class ServiceConnector : public internal::ServiceConnectorBase { + public: + ServiceConnector(const std::string& name, Context* context = NULL) + : ServiceConnectorBase(name), context_(context) {} + + virtual ~ServiceConnector() { + ConnectionList doomed; + doomed.swap(connections_); + for (typename ConnectionList::iterator it = doomed.begin(); + it != doomed.end(); ++it) { + delete *it; + } + assert(connections_.empty()); // No one should have added more! + } + + virtual void ConnectToService(const std::string& url, + const std::string& name, + ScopedMessagePipeHandle handle) MOJO_OVERRIDE { + ServiceConnection<ServiceImpl, Context>* impl = + ServiceConstructor<ServiceImpl, Context>::New(context_); + impl->set_service_connector(this); + BindToPipe(impl, handle.Pass()); + + connections_.push_back(impl); + } + + void RemoveConnection(ServiceImpl* impl) { + // Called from ~ServiceImpl, in response to a connection error. + for (typename ConnectionList::iterator it = connections_.begin(); + it != connections_.end(); ++it) { + if (*it == impl) { + delete impl; + connections_.erase(it); + return; + } + } + } + + Context* context() const { return context_; } + + private: + typedef std::vector<ServiceImpl*> ConnectionList; + ConnectionList connections_; + Context* context_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnector); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_CONNECTOR_H_ diff --git a/chromium/mojo/public/cpp/application/lib/service_registry.cc b/chromium/mojo/public/cpp/application/lib/service_registry.cc new file mode 100644 index 00000000000..bc901dfb924 --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/service_registry.cc @@ -0,0 +1,78 @@ +// 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/application/lib/service_registry.h" + +#include "mojo/public/cpp/application/application.h" +#include "mojo/public/cpp/application/lib/service_connector.h" + +namespace mojo { +namespace internal { + +ServiceRegistry::ServiceRegistry(Application* application) + : application_(application) { +} + +ServiceRegistry::ServiceRegistry( + Application* application, + ScopedMessagePipeHandle service_provider_handle) + : application_(application) { + remote_service_provider_.Bind(service_provider_handle.Pass()); + remote_service_provider_.set_client(this); +} + +ServiceRegistry::~ServiceRegistry() { + for (NameToServiceConnectorMap::iterator i = + name_to_service_connector_.begin(); + i != name_to_service_connector_.end(); ++i) { + delete i->second; + } + name_to_service_connector_.clear(); +} + +void ServiceRegistry::AddServiceConnector( + ServiceConnectorBase* service_connector) { + name_to_service_connector_[service_connector->name()] = service_connector; + service_connector->set_registry(this); +} + +void ServiceRegistry::RemoveServiceConnector( + ServiceConnectorBase* service_connector) { + NameToServiceConnectorMap::iterator it = + name_to_service_connector_.find(service_connector->name()); + assert(it != name_to_service_connector_.end()); + delete it->second; + name_to_service_connector_.erase(it); + if (name_to_service_connector_.empty()) + remote_service_provider_.reset(); +} + +void ServiceRegistry::BindRemoteServiceProvider( + ScopedMessagePipeHandle service_provider_handle) { + remote_service_provider_.Bind(service_provider_handle.Pass()); + remote_service_provider_.set_client(this); +} + +void ServiceRegistry::ConnectToService(const mojo::String& service_url, + const mojo::String& service_name, + ScopedMessagePipeHandle client_handle, + const mojo::String& requestor_url) { + if (name_to_service_connector_.find(service_name) == + name_to_service_connector_.end() || + !application_->AllowIncomingConnection(service_name, requestor_url)) { + client_handle.reset(); + return; + } + + internal::ServiceConnectorBase* service_connector = + name_to_service_connector_[service_name]; + assert(service_connector); + // requestor_url is ignored because the service_connector stores the url + // of the requestor safely. + return service_connector->ConnectToService( + service_url, service_name, client_handle.Pass()); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/application/lib/service_registry.h b/chromium/mojo/public/cpp/application/lib/service_registry.h new file mode 100644 index 00000000000..478cd055ef2 --- /dev/null +++ b/chromium/mojo/public/cpp/application/lib/service_registry.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_APPLICATION_LIB_SERVICE_REGISTRY_H_ +#define MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_REGISTRY_H_ + +#include "mojo/public/interfaces/service_provider/service_provider.mojom.h" + +namespace mojo { + +class Application; + +namespace internal { + +class ServiceConnectorBase; + +class ServiceRegistry : public ServiceProvider { + public: + ServiceRegistry(Application* application); + ServiceRegistry(Application* application, + ScopedMessagePipeHandle service_provider_handle); + virtual ~ServiceRegistry(); + + void AddServiceConnector(ServiceConnectorBase* service_connector); + void RemoveServiceConnector(ServiceConnectorBase* service_connector); + + ServiceProvider* remote_service_provider() { + return remote_service_provider_.get(); + } + + void BindRemoteServiceProvider( + ScopedMessagePipeHandle service_provider_handle); + + // ServiceProvider method. + virtual void ConnectToService(const mojo::String& service_url, + const mojo::String& service_name, + ScopedMessagePipeHandle client_handle, + const mojo::String& requestor_url) + MOJO_OVERRIDE; + + private: + Application* application_; + typedef std::map<std::string, ServiceConnectorBase*> + NameToServiceConnectorMap; + NameToServiceConnectorMap name_to_service_connector_; + ServiceProviderPtr remote_service_provider_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceRegistry); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_APPLICATION_LIB_SERVICE_REGISTRY_H_ diff --git a/chromium/mojo/public/cpp/bindings/BUILD.gn b/chromium/mojo/public/cpp/bindings/BUILD.gn new file mode 100644 index 00000000000..2cc35aa52ff --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/BUILD.gn @@ -0,0 +1,53 @@ +# 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. + +source_set("bindings") { + sources = [ + "array.h", + "callback.h", + "error_handler.h", + "interface_ptr.h", + "message.h", + "message_filter.h", + "no_interface.h", + "string.h", + "struct_ptr.h", + "sync_dispatcher.h", + "type_converter.h", + "lib/array_internal.cc", + "lib/array_internal.h", + "lib/array_serialization.h", + "lib/bindings_internal.h", + "lib/bindings_serialization.cc", + "lib/bindings_serialization.h", + "lib/bounds_checker.cc", + "lib/bounds_checker.h", + "lib/buffer.h", + "lib/callback_internal.h", + "lib/connector.cc", + "lib/connector.h", + "lib/filter_chain.cc", + "lib/filter_chain.h", + "lib/fixed_buffer.cc", + "lib/fixed_buffer.h", + "lib/message.cc", + "lib/message_builder.cc", + "lib/message_builder.h", + "lib/message_filter.cc", + "lib/message_internal.h", + "lib/message_queue.cc", + "lib/message_queue.h", + "lib/no_interface.cc", + "lib/router.cc", + "lib/router.h", + "lib/shared_data.h", + "lib/shared_ptr.h", + "lib/string_serialization.cc", + "lib/string_serialization.h", + "lib/sync_dispatcher.cc", + "lib/template_util.h", + "lib/validation_errors.cc", + "lib/validation_errors.h", + ] +} diff --git a/chromium/mojo/public/cpp/bindings/DEPS b/chromium/mojo/public/cpp/bindings/DEPS new file mode 100644 index 00000000000..2a0496e9d9c --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/public/cpp/environment", +] diff --git a/chromium/mojo/public/cpp/bindings/array.h b/chromium/mojo/public/cpp/bindings/array.h new file mode 100644 index 00000000000..daf7125bb3c --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/array.h @@ -0,0 +1,143 @@ +// 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_ARRAY_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ + +#include <string.h> + +#include <algorithm> +#include <string> +#include <vector> + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/lib/template_util.h" +#include "mojo/public/cpp/bindings/type_converter.h" + +namespace mojo { + +// Provides read-only access to array data. +template <typename T> +class Array { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(Array, RValue) + public: + typedef internal::ArrayTraits<T, internal::IsMoveOnlyType<T>::value> + Traits; + typedef typename Traits::ConstRefType ConstRefType; + typedef typename Traits::RefType RefType; + typedef typename Traits::StorageType StorageType; + typedef typename Traits::ForwardType ForwardType; + + typedef internal::Array_Data<typename internal::WrapperTraits<T>::DataType> + Data_; + + Array() : is_null_(true) {} + explicit Array(size_t size) : vec_(size), is_null_(false) { + Traits::Initialize(&vec_); + } + ~Array() { Traits::Finalize(&vec_); } + + Array(RValue other) : is_null_(true) { Take(other.object); } + Array& operator=(RValue other) { + Take(other.object); + return *this; + } + + static Array New(size_t size) { + return Array(size).Pass(); + } + + template <typename U> + static Array From(const U& other) { + return TypeConverter<Array, U>::ConvertFrom(other); + } + + template <typename U> + U To() const { + return TypeConverter<Array, U>::ConvertTo(*this); + } + + void reset() { + if (!vec_.empty()) { + Traits::Finalize(&vec_); + vec_.clear(); + } + is_null_ = true; + } + + bool is_null() const { return is_null_; } + + size_t size() const { return vec_.size(); } + + ConstRefType at(size_t offset) const { return Traits::at(&vec_, offset); } + ConstRefType operator[](size_t offset) const { return at(offset); } + + RefType at(size_t offset) { return Traits::at(&vec_, offset); } + RefType operator[](size_t offset) { return at(offset); } + + void push_back(ForwardType value) { + is_null_ = false; + Traits::PushBack(&vec_, value); + } + + void resize(size_t size) { + is_null_ = false; + Traits::Resize(&vec_, size); + } + + const std::vector<StorageType>& storage() const { + return vec_; + } + operator const std::vector<StorageType>&() const { + return vec_; + } + + void Swap(Array* other) { + std::swap(is_null_, other->is_null_); + vec_.swap(other->vec_); + } + void Swap(std::vector<StorageType>* other) { + is_null_ = false; + vec_.swap(*other); + } + + private: + typedef std::vector<StorageType> Array::*Testable; + + public: + operator Testable() const { return is_null_ ? 0 : &Array::vec_; } + + private: + void Take(Array* other) { + reset(); + Swap(other); + } + + std::vector<StorageType> vec_; + bool is_null_; +}; + +template <typename T, typename E> +class TypeConverter<Array<T>, std::vector<E> > { + public: + static Array<T> ConvertFrom(const std::vector<E>& input) { + Array<T> result(input.size()); + for (size_t i = 0; i < input.size(); ++i) + result[i] = TypeConverter<T, E>::ConvertFrom(input[i]); + return result.Pass(); + } + static std::vector<E> ConvertTo(const Array<T>& input) { + std::vector<E> result; + if (!input.is_null()) { + result.resize(input.size()); + for (size_t i = 0; i < input.size(); ++i) + result[i] = TypeConverter<T, E>::ConvertTo(input[i]); + } + return result; + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ diff --git a/chromium/mojo/public/cpp/bindings/callback.h b/chromium/mojo/public/cpp/bindings/callback.h new file mode 100644 index 00000000000..d8ff4718232 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/callback.h @@ -0,0 +1,462 @@ +// This file was GENERATED by command: +// pump.py callback.h.pump +// DO NOT EDIT BY HAND!!! + + + +// 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_CALLBACK_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ + +#include "mojo/public/cpp/bindings/lib/callback_internal.h" +#include "mojo/public/cpp/bindings/lib/shared_ptr.h" +#include "mojo/public/cpp/bindings/lib/template_util.h" + +namespace mojo { + +template <typename Sig> +class Callback; + +template <> +class Callback<void()> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run() const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run() const { + if (sink_.get()) + sink_->Run(); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run() const MOJO_OVERRIDE { + sink.Run(); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1> +class Callback<void(A1)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2> +class Callback<void(A1, A2)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3> +class Callback<void(A1, A2, A3)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3, typename A4> +class Callback<void(A1, A2, A3, A4)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3, typename A4, typename A5> +class Callback<void(A1, A2, A3, A4, A5)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3, typename A4, typename A5, + typename A6> +class Callback<void(A1, A2, A3, A4, A5, A6)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5), + internal::Forward(a6)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5), + internal::Forward(a6)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +template <typename A1, typename A2, typename A3, typename A4, typename A5, + typename A6, typename A7> +class Callback<void(A1, A2, A3, A4, A5, A6, A7)> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6, + typename internal::Callback_ParamTraits<A7>::ForwardType a7) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6, + typename internal::Callback_ParamTraits<A7>::ForwardType a7) const { + if (sink_.get()) + sink_->Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5), + internal::Forward(a6), + internal::Forward(a7)); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + typename internal::Callback_ParamTraits<A1>::ForwardType a1, + typename internal::Callback_ParamTraits<A2>::ForwardType a2, + typename internal::Callback_ParamTraits<A3>::ForwardType a3, + typename internal::Callback_ParamTraits<A4>::ForwardType a4, + typename internal::Callback_ParamTraits<A5>::ForwardType a5, + typename internal::Callback_ParamTraits<A6>::ForwardType a6, + typename internal::Callback_ParamTraits<A7>::ForwardType a7) const + MOJO_OVERRIDE { + sink.Run( + internal::Forward(a1), + internal::Forward(a2), + internal::Forward(a3), + internal::Forward(a4), + internal::Forward(a5), + internal::Forward(a6), + internal::Forward(a7)); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ diff --git a/chromium/mojo/public/cpp/bindings/callback.h.pump b/chromium/mojo/public/cpp/bindings/callback.h.pump new file mode 100644 index 00000000000..a0f23d5f77e --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/callback.h.pump @@ -0,0 +1,80 @@ +$$ This is a pump file for generating file templates. Pump is a python +$$ script that is part of the Google Test suite of utilities. Description +$$ can be found here: +$$ +$$ http://code.google.com/p/googletest/wiki/PumpManual +$$ + +$var MAX_ARITY = 7 + +// 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_CALLBACK_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ + +#include "mojo/public/cpp/bindings/lib/callback_internal.h" +#include "mojo/public/cpp/bindings/lib/shared_ptr.h" +#include "mojo/public/cpp/bindings/lib/template_util.h" + +namespace mojo { + +template <typename Sig> +class Callback; + +$range ARITY 0..MAX_ARITY +$for ARITY [[ +$range ARG 1..ARITY + +template <$for ARG , [[typename A$(ARG)]]> +class Callback<void($for ARG , [[A$(ARG)]])> { + public: + struct Runnable { + virtual ~Runnable() {} + virtual void Run( + $for ARG , + [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const = 0; + }; + + Callback() {} + + // The Callback assumes ownership of |runnable|. + explicit Callback(Runnable* runnable) : sink_(runnable) {} + + // Any class that is copy-constructable and has a compatible Run method may + // be adapted to a Callback using this constructor. + template <typename Sink> + Callback(const Sink& sink) : sink_(new Adapter<Sink>(sink)) {} + + void Run( + $for ARG , + [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const { + if (sink_.get()) + sink_->Run( + $for ARG , + [[internal::Forward(a$(ARG))]]); + } + + private: + template <typename Sink> + struct Adapter : public Runnable { + explicit Adapter(const Sink& sink) : sink(sink) {} + virtual void Run( + $for ARG , + [[typename internal::Callback_ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const MOJO_OVERRIDE { + sink.Run( + $for ARG , + [[internal::Forward(a$(ARG))]]); + } + Sink sink; + }; + + internal::SharedPtr<Runnable> sink_; +}; + +]] $$ for ARITY + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_H_ diff --git a/chromium/mojo/public/cpp/bindings/error_handler.h b/chromium/mojo/public/cpp/bindings/error_handler.h new file mode 100644 index 00000000000..8ce1af27264 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/error_handler.h @@ -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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_ERROR_HANDLER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_ERROR_HANDLER_H_ + +namespace mojo { + +// This interface is used to report connection errors. +class ErrorHandler { + public: + virtual ~ErrorHandler() {} + virtual void OnConnectionError() = 0; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_ERROR_HANDLER_H_ diff --git a/chromium/mojo/public/cpp/bindings/interface_impl.h b/chromium/mojo/public/cpp/bindings/interface_impl.h new file mode 100644 index 00000000000..8ba5e7ffa4a --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/interface_impl.h @@ -0,0 +1,109 @@ +// 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_INTERFACE_IMPL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ + +#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/bindings/lib/interface_impl_internal.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// InterfaceImpl<..> is designed to be the base class of an interface +// implementation. It may be bound to a pipe or a proxy, see BindToPipe and +// BindToProxy. +template <typename Interface> +class InterfaceImpl : public internal::InterfaceImplBase<Interface> { + public: + typedef typename Interface::Client Client; + + InterfaceImpl() : internal_state_(this) {} + virtual ~InterfaceImpl() {} + + // Returns a proxy to the client interface. This is null upon construction, + // and becomes non-null after OnClientConnected. NOTE: It remains non-null + // until this instance is deleted. + Client* client() { return internal_state_.client(); } + + // Called when the client has connected to this instance. + virtual void OnConnectionEstablished() {} + + // Called when the client is no longer connected to this instance. NOTE: The + // client() method continues to return a non-null pointer after this method + // is called. After this method is called, any method calls made on client() + // will be silently ignored. + virtual void OnConnectionError() {} + + // DO NOT USE. Exposed only for internal use and for testing. + internal::InterfaceImplState<Interface>* internal_state() { + return &internal_state_; + } + + private: + internal::InterfaceImplState<Interface> internal_state_; + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImpl); +}; + +// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given +// MessagePipe. The instance is returned for convenience in member initializer +// lists, etc. If the pipe is closed, the instance's OnConnectionError method +// will be called. +// +// The instance is also bound to the current thread. Its methods will only be +// called on the current thread, and if the current thread exits, then it will +// also be deleted, and along with it, its end point of the pipe will be closed. +// +// Before returning, the instance's OnConnectionEstablished method is called. +template <typename Impl> +Impl* BindToPipe( + Impl* instance, + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + instance->internal_state()->Bind(handle.Pass(), waiter); + return instance; +} + +// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given +// InterfacePtr<..>. The instance is returned for convenience in member +// initializer lists, etc. If the pipe is closed, the instance's +// OnConnectionError method will be called. +// +// The instance is also bound to the current thread. Its methods will only be +// called on the current thread, and if the current thread exits, then it will +// also be deleted, and along with it, its end point of the pipe will be closed. +// +// Before returning, the instance's OnConnectionEstablished method is called. +template <typename Impl, typename Interface> +Impl* BindToProxy( + Impl* instance, + InterfacePtr<Interface>* ptr, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + instance->internal_state()->BindProxy(ptr, waiter); + return instance; +} + +// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given +// InterfaceRequest<..>. The instance is returned for convenience in member +// initializer lists, etc. If the pipe is closed, the instance's +// OnConnectionError method will be called. +// +// The instance is also bound to the current thread. Its methods will only be +// called on the current thread, and if the current thread exits, then it will +// also be deleted, and along with it, its end point of the pipe will be closed. +// +// Before returning, the instance will receive a SetClient call, providing it +// with a proxy to the client on the other end of the pipe. +template <typename Impl, typename Interface> +Impl* BindToRequest( + Impl* instance, + InterfaceRequest<Interface>* request, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + return BindToPipe(instance, request->PassMessagePipe(), waiter); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ diff --git a/chromium/mojo/public/cpp/bindings/interface_ptr.h b/chromium/mojo/public/cpp/bindings/interface_ptr.h new file mode 100644 index 00000000000..726896d9cce --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/interface_ptr.h @@ -0,0 +1,124 @@ +// 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_INTERFACE_PTR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ + +#include <assert.h> + +#include <algorithm> + +#include "mojo/public/cpp/bindings/error_handler.h" +#include "mojo/public/cpp/bindings/lib/interface_ptr_internal.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +class ErrorHandler; + +// InterfacePtr represents a proxy to a remote instance of an interface. +template <typename Interface> +class InterfacePtr { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfacePtr, RValue) + public: + InterfacePtr() {} + + InterfacePtr(RValue other) { + internal_state_.Swap(&other.object->internal_state_); + } + InterfacePtr& operator=(RValue other) { + reset(); + internal_state_.Swap(&other.object->internal_state_); + return *this; + } + + ~InterfacePtr() {} + + Interface* get() const { + return internal_state_.instance(); + } + Interface* operator->() const { return get(); } + Interface& operator*() const { return *get(); } + + void reset() { + State doomed; + internal_state_.Swap(&doomed); + } + + // This method configures the InterfacePtr<..> to be a proxy to a remote + // object on the other end of the given pipe. + // + // The proxy is bound to the current thread, which means its methods may + // only be called on the current thread. + // + // To move a bound InterfacePtr<..> to another thread, call + // ResetAndReturnMessagePipe. Then create a new InterfacePtr<..> on another + // thread, and bind the new InterfacePtr<..> to the message pipe on that + // thread. + void Bind( + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + reset(); + internal_state_.ConfigureProxy(handle.Pass(), waiter); + } + + // The client interface may only be set after this InterfacePtr<..> is bound. + void set_client(typename Interface::Client* client) { + internal_state_.set_client(client); + } + + // This method may be called to query if the underlying pipe has encountered + // an error. If true, this means method calls made on this interface will be + // dropped (and may have already been dropped) on the floor. + bool encountered_error() const { + assert(internal_state_.router()); + return internal_state_.router()->encountered_error(); + } + + // This method may be called to register an ErrorHandler to observe a + // connection error on the underlying pipe. The callback runs asynchronously + // from the current message loop. + void set_error_handler(ErrorHandler* error_handler) { + assert(internal_state_.router()); + internal_state_.router()->set_error_handler(error_handler); + } + + // Returns the underlying message pipe handle (if any) and resets the + // InterfacePtr<..> to its uninitialized state. This method is helpful if you + // need to move a proxy to another thread. See related notes for Bind. + ScopedMessagePipeHandle PassMessagePipe() { + State state; + internal_state_.Swap(&state); + return state.router() ? + state.router()->PassMessagePipe() : ScopedMessagePipeHandle(); + } + + // DO NOT USE. Exposed only for internal use and for testing. + internal::InterfacePtrState<Interface>* internal_state() { + return &internal_state_; + } + + private: + typedef internal::InterfacePtrState<Interface> State; + State internal_state_; +}; + +// Takes a handle to the proxy end-point of a pipe. On the other end is +// presumed to be an interface implementation of type |Interface|. Returns a +// generated proxy to that interface, which may be used on the current thread. +// It is valid to call set_client on the returned InterfacePtr<..> to set an +// instance of Interface::Client. +template <typename Interface> +InterfacePtr<Interface> MakeProxy( + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + InterfacePtr<Interface> ptr; + if (handle.is_valid()) + ptr.Bind(handle.Pass(), waiter); + return ptr.Pass(); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ diff --git a/chromium/mojo/public/cpp/bindings/interface_request.h b/chromium/mojo/public/cpp/bindings/interface_request.h new file mode 100644 index 00000000000..6b7d3033c9d --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/interface_request.h @@ -0,0 +1,76 @@ +// 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_INTERFACE_REQUEST_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ + +#include "mojo/public/cpp/bindings/interface_ptr.h" + +namespace mojo { + +// Used in methods that return instances of remote objects. +template <typename Interface> +class InterfaceRequest { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfaceRequest, RValue) + public: + InterfaceRequest() {} + + InterfaceRequest(RValue other) { + handle_ = other.object->handle_.Pass(); + } + InterfaceRequest& operator=(RValue other) { + handle_ = other.object->handle_.Pass(); + return *this; + } + + // Returns true if the request has yet to be completed. + bool is_pending() const { return handle_.is_valid(); } + + void Bind(ScopedMessagePipeHandle handle) { + handle_ = handle.Pass(); + } + + ScopedMessagePipeHandle PassMessagePipe() { + return handle_.Pass(); + } + + private: + ScopedMessagePipeHandle handle_; +}; + +template <typename Interface> +InterfaceRequest<Interface> MakeRequest(ScopedMessagePipeHandle handle) { + InterfaceRequest<Interface> request; + request.Bind(handle.Pass()); + return request.Pass(); +} + +// Used to construct a request that synchronously binds an InterfacePtr<..>, +// making it immediately usable upon return. The resulting request object may +// then be later bound to an InterfaceImpl<..> via BindToRequest. +// +// Given the following interface: +// +// interface Foo { +// CreateBar(Bar& bar); +// } +// +// The caller of CreateBar would have code similar to the following: +// +// InterfacePtr<Foo> foo = ...; +// InterfacePtr<Bar> bar; +// foo->CreateBar(Get(&bar)); +// +// Upon return from CreateBar, |bar| is ready to have methods called on it. +// +template <typename Interface> +InterfaceRequest<Interface> Get(InterfacePtr<Interface>* ptr) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass()); + return MakeRequest<Interface>(pipe.handle1.Pass()); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_REQUEST_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/DEPS b/chromium/mojo/public/cpp/bindings/lib/DEPS new file mode 100644 index 00000000000..b809b58d337 --- /dev/null +++ b/chromium/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/chromium/mojo/public/cpp/bindings/lib/TODO b/chromium/mojo/public/cpp/bindings/lib/TODO new file mode 100644 index 00000000000..21bcb6fe7a2 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/TODO @@ -0,0 +1,6 @@ +TODOs: + - Ensure validation checks are solid + - Add tests of validation logic + - Optimize Buffer classes? + - Add compile-time asserts to verify object packing and padding. + - Investigate making arrays of objects not be arrays of pointers. diff --git a/chromium/mojo/public/cpp/bindings/lib/array_internal.cc b/chromium/mojo/public/cpp/bindings/lib/array_internal.cc new file mode 100644 index 00000000000..3f7f1ce0b16 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/array_internal.cc @@ -0,0 +1,70 @@ +// 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, true>::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 +void ArraySerializationHelper<Handle, true>::DecodePointersAndHandles( + const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + DecodeHandle(&elements[i], handles); +} + +// static +bool ArraySerializationHelper<Handle, true>::ValidateElements( + const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!bounds_checker->ClaimHandle(elements[i])) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE); + return false; + } + } + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/array_internal.h b/chromium/mojo/public/cpp/bindings/lib/array_internal.h new file mode 100644 index 00000000000..8ea00991251 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/array_internal.h @@ -0,0 +1,384 @@ +// 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 <vector> + +#include "mojo/public/cpp/bindings/lib/bindings_internal.h" +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/buffer.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +namespace mojo { +template <typename T> class Array; +class String; + +namespace internal { + +template <typename T> +struct ArrayDataTraits { + typedef T StorageType; + 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 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; + } +}; + +template <typename T> +struct ArrayDataTraits<Array_Data<T>*> { + typedef ArrayPointer<T> StorageType; + typedef Array_Data<T>*& Ref; + typedef Array_Data<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].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 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, bool kIsHandle> struct ArraySerializationHelper; + +template <typename T> +struct ArraySerializationHelper<T, false> { + typedef typename ArrayDataTraits<T>::StorageType ElementType; + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + } + + static void DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + } + + static bool ValidateElements(const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker) { + return true; + } +}; + +template <> +struct ArraySerializationHelper<Handle, true> { + typedef ArrayDataTraits<Handle>::StorageType ElementType; + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles); + + static void DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles); + + static bool ValidateElements(const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker); +}; + +template <typename H> +struct ArraySerializationHelper<H, true> { + typedef typename ArrayDataTraits<H>::StorageType ElementType; + + static void EncodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + ArraySerializationHelper<Handle, true>::EncodePointersAndHandles( + header, elements, handles); + } + + static void DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + ArraySerializationHelper<Handle, true>::DecodePointersAndHandles( + header, elements, handles); + } + + static bool ValidateElements(const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker) { + return ArraySerializationHelper<Handle, true>::ValidateElements( + header, elements, bounds_checker); + } +}; + +template <typename P> +struct ArraySerializationHelper<P*, false> { + typedef typename ArrayDataTraits<P*>::StorageType ElementType; + + 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 void DecodePointersAndHandles(const ArrayHeader* header, + ElementType* elements, + std::vector<Handle>* handles) { + for (uint32_t i = 0; i < header->num_elements; ++i) + Decode(&elements[i], handles); + } + + static bool ValidateElements(const ArrayHeader* header, + const ElementType* elements, + BoundsChecker* bounds_checker) { + for (uint32_t i = 0; i < header->num_elements; ++i) { + if (!ValidateEncodedPointer(&elements[i].offset)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER); + return false; + } + if (!P::Validate(DecodePointerRaw(&elements[i].offset), bounds_checker)) + return false; + } + return true; + } +}; + +template <typename T> +class Array_Data { + public: + typedef ArrayDataTraits<T> Traits; + typedef typename Traits::StorageType StorageType; + typedef typename Traits::Ref Ref; + typedef typename Traits::ConstRef ConstRef; + typedef ArraySerializationHelper<T, IsHandle<T>::value> Helper; + + 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); + } + + static bool Validate(const void* data, BoundsChecker* bounds_checker) { + if (!data) + return true; + if (!IsAligned(data)) { + ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); + return false; + } + if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + const ArrayHeader* header = static_cast<const ArrayHeader*>(data); + if (header->num_bytes < (sizeof(Array_Data<T>) + + Traits::GetStorageSize(header->num_elements))) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER); + return false; + } + if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data); + return Helper::ValidateElements(&object->header_, object->storage(), + bounds_checker); + } + + 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)); + } + + void EncodePointersAndHandles(std::vector<Handle>* handles) { + Helper::EncodePointersAndHandles(&header_, storage(), handles); + } + + void DecodePointersAndHandles(std::vector<Handle>* handles) { + Helper::DecodePointersAndHandles(&header_, storage(), handles); + } + + 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 kIsMoveOnlyType> struct ArrayTraits {}; + +template <typename T> struct ArrayTraits<T, false> { + typedef T StorageType; + typedef typename std::vector<T>::reference RefType; + typedef typename std::vector<T>::const_reference ConstRefType; + typedef ConstRefType ForwardType; + static inline void Initialize(std::vector<T>* vec) { + } + static inline void Finalize(std::vector<T>* vec) { + } + static inline ConstRefType at(const std::vector<T>* vec, size_t offset) { + return vec->at(offset); + } + static inline RefType at(std::vector<T>* vec, size_t offset) { + return vec->at(offset); + } + static inline void Resize(std::vector<T>* vec, size_t size) { + vec->resize(size); + } + static inline void PushBack(std::vector<T>* vec, ForwardType value) { + vec->push_back(value); + } +}; + +template <typename T> struct ArrayTraits<T, true> { + struct StorageType { + char buf[sizeof(T) + (8 - (sizeof(T) % 8)) % 8]; // Make 8-byte aligned. + }; + typedef T& RefType; + typedef const T& ConstRefType; + typedef T ForwardType; + static inline void Initialize(std::vector<StorageType>* vec) { + for (size_t i = 0; i < vec->size(); ++i) + new (vec->at(i).buf) T(); + } + static inline void Finalize(std::vector<StorageType>* vec) { + for (size_t i = 0; i < vec->size(); ++i) + reinterpret_cast<T*>(vec->at(i).buf)->~T(); + } + static inline ConstRefType at(const std::vector<StorageType>* vec, + size_t offset) { + return *reinterpret_cast<const T*>(vec->at(offset).buf); + } + static inline RefType at(std::vector<StorageType>* vec, size_t offset) { + return *reinterpret_cast<T*>(vec->at(offset).buf); + } + static inline void Resize(std::vector<StorageType>* vec, size_t size) { + size_t old_size = vec->size(); + for (size_t i = size; i < old_size; i++) + reinterpret_cast<T*>(vec->at(i).buf)->~T(); + ResizeStorage(vec, size); + for (size_t i = old_size; i < vec->size(); i++) + new (vec->at(i).buf) T(); + } + static inline void PushBack(std::vector<StorageType>* vec, RefType value) { + size_t old_size = vec->size(); + ResizeStorage(vec, old_size + 1); + new (vec->at(old_size).buf) T(value.Pass()); + } + static inline void ResizeStorage(std::vector<StorageType>* vec, size_t size) { + if (size <= vec->capacity()) { + vec->resize(size); + return; + } + std::vector<StorageType> new_storage(size); + for (size_t i = 0; i < vec->size(); i++) + new (new_storage.at(i).buf) T(at(vec, i).Pass()); + vec->swap(new_storage); + Finalize(&new_storage); + } +}; + +template <> struct WrapperTraits<String, false> { + typedef String_Data* DataType; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/array_serialization.h b/chromium/mojo/public/cpp/bindings/lib/array_serialization.h new file mode 100644 index 00000000000..83403d52502 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/array_serialization.h @@ -0,0 +1,179 @@ +// 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_ARRAY_SERIALIZATION_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ + +#include <string> + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/lib/string_serialization.h" + +namespace mojo { + +template <typename E> +inline size_t GetSerializedSize_(const Array<E>& input); + +template <typename E, typename F> +inline void Serialize_(Array<E> input, internal::Buffer* buf, + internal::Array_Data<F>** output); +template <typename E, typename F> +inline void Deserialize_(internal::Array_Data<F>* data, Array<E>* output); + +namespace internal { + +template <typename E, typename F, bool move_only = IsMoveOnlyType<E>::value> +struct ArraySerializer; + +template <typename E, typename F> struct ArraySerializer<E, F, false> { + MOJO_COMPILE_ASSERT(sizeof(E) == sizeof(F), wrong_array_serializer); + static size_t GetSerializedSize(const Array<E>& input) { + return sizeof(Array_Data<F>) + Align(input.size() * sizeof(E)); + } + static void SerializeElements( + Array<E> input, Buffer* buf, Array_Data<F>* output) { + memcpy(output->storage(), &input.storage()[0], input.size() * sizeof(E)); + } + static void DeserializeElements( + Array_Data<F>* input, Array<E>* output) { + std::vector<E> result(input->size()); + memcpy(&result[0], input->storage(), input->size() * sizeof(E)); + output->Swap(&result); + } +}; + +template <> struct ArraySerializer<bool, bool, false> { + static size_t GetSerializedSize(const Array<bool>& input) { + return sizeof(Array_Data<bool>) + Align((input.size() + 7) / 8); + } + static void SerializeElements( + Array<bool> input, Buffer* buf, Array_Data<bool>* output) { + // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? + for (size_t i = 0; i < input.size(); ++i) + output->at(i) = input[i]; + } + static void DeserializeElements( + Array_Data<bool>* input, Array<bool>* output) { + Array<bool> result(input->size()); + // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? + for (size_t i = 0; i < input->size(); ++i) + result.at(i) = input->at(i); + output->Swap(&result); + } +}; + +template <typename H> struct ArraySerializer<ScopedHandleBase<H>, H, true> { + static size_t GetSerializedSize(const Array<ScopedHandleBase<H> >& input) { + return sizeof(Array_Data<H>) + Align(input.size() * sizeof(H)); + } + static void SerializeElements( + Array<ScopedHandleBase<H> > input, + Buffer* buf, + Array_Data<H>* output) { + for (size_t i = 0; i < input.size(); ++i) + output->at(i) = input[i].release(); // Transfer ownership of the handle. + } + static void DeserializeElements( + Array_Data<H>* input, Array<ScopedHandleBase<H> >* output) { + Array<ScopedHandleBase<H> > result(input->size()); + for (size_t i = 0; i < input->size(); ++i) + result.at(i) = MakeScopedHandle(FetchAndReset(&input->at(i))); + output->Swap(&result); + } +}; + +template <typename S> struct ArraySerializer<S, typename S::Data_*, true> { + static size_t GetSerializedSize(const Array<S>& input) { + size_t size = sizeof(Array_Data<typename S::Data_*>) + + input.size() * sizeof(internal::StructPointer<typename S::Data_>); + for (size_t i = 0; i < input.size(); ++i) + size += GetSerializedSize_(input[i]); + return size; + } + static void SerializeElements( + Array<S> input, + Buffer* buf, + Array_Data<typename S::Data_*>* output) { + for (size_t i = 0; i < input.size(); ++i) { + typename S::Data_* element; + Serialize_(input[i].Pass(), buf, &element); + output->at(i) = element; + } + } + static void DeserializeElements( + Array_Data<typename S::Data_*>* input, Array<S>* output) { + Array<S> result(input->size()); + for (size_t i = 0; i < input->size(); ++i) { + S element; + Deserialize_(input->at(i), &element); + result[i] = element.Pass(); + } + output->Swap(&result); + } +}; + +template <> struct ArraySerializer<String, String_Data*, false> { + static size_t GetSerializedSize(const Array<String>& input) { + size_t size = sizeof(Array_Data<String_Data*>) + + input.size() * sizeof(internal::StringPointer); + for (size_t i = 0; i < input.size(); ++i) + size += GetSerializedSize_(input[i]); + return size; + } + static void SerializeElements( + Array<String> input, + Buffer* buf, + Array_Data<String_Data*>* output) { + for (size_t i = 0; i < input.size(); ++i) { + String_Data* element; + Serialize_(input[i], buf, &element); + output->at(i) = element; + } + } + static void DeserializeElements( + Array_Data<String_Data*>* input, Array<String>* output) { + Array<String> result(input->size()); + for (size_t i = 0; i < input->size(); ++i) + Deserialize_(input->at(i), &result[i]); + output->Swap(&result); + } +}; + +} // namespace internal + +template <typename E> +inline size_t GetSerializedSize_(const Array<E>& input) { + if (!input) + return 0; + typedef typename internal::WrapperTraits<E>::DataType F; + return internal::ArraySerializer<E, F>::GetSerializedSize(input); +} + +template <typename E, typename F> +inline void Serialize_(Array<E> input, internal::Buffer* buf, + internal::Array_Data<F>** output) { + if (input) { + internal::Array_Data<F>* result = + internal::Array_Data<F>::New(input.size(), buf); + internal::ArraySerializer<E, F>::SerializeElements( + internal::Forward(input), buf, result); + *output = result; + } else { + *output = NULL; + } +} + +template <typename E, typename F> +inline void Deserialize_(internal::Array_Data<F>* input, + Array<E>* output) { + if (input) { + internal::ArraySerializer<E, F>::DeserializeElements(input, output); + } else { + output->reset(); + } +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h b/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h new file mode 100644 index 00000000000..6e87cbd1fb5 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h @@ -0,0 +1,86 @@ +// 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/bindings/lib/template_util.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +class String; + +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 H> struct IsHandle { + static const bool value = IsBaseOf<Handle, H>::value; +}; + +template <typename T, bool move_only = IsMoveOnlyType<T>::value> +struct WrapperTraits; + +template <typename T> struct WrapperTraits<T, false> { + typedef T DataType; +}; +template <typename H> struct WrapperTraits<ScopedHandleBase<H>, true> { + typedef H DataType; +}; +template <typename S> struct WrapperTraits<S, true> { + typedef typename S::Data_* DataType; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc new file mode 100644 index 00000000000..d5f77853684 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.cc @@ -0,0 +1,118 @@ +// 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" +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +namespace mojo { +namespace internal { + +namespace { + +const size_t kAlignment = 8; + +template<typename T> +T AlignImpl(T t) { + return t + (kAlignment - (t % kAlignment)) % kAlignment; +} + +} // namespace + +size_t Align(size_t size) { + return AlignImpl(size); +} + +char* AlignPointer(char* ptr) { + return reinterpret_cast<char*>(AlignImpl(reinterpret_cast<uintptr_t>(ptr))); +} + +bool IsAligned(const void* ptr) { + return !(reinterpret_cast<uintptr_t>(ptr) % 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 ValidateEncodedPointer(const uint64_t* offset) { + // Cast to uintptr_t so overflow behavior is well defined. + return reinterpret_cast<uintptr_t>(offset) + *offset >= + reinterpret_cast<uintptr_t>(offset); +} + +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 { + handle->set_value(kEncodedInvalidHandleValue); + } +} + +void DecodeHandle(Handle* handle, std::vector<Handle>* handles) { + if (handle->value() == kEncodedInvalidHandleValue) { + *handle = Handle(); + return; + } + assert(handle->value() < handles->size()); + // Just leave holes in the vector so we don't screw up other indices. + *handle = FetchAndReset(&handles->at(handle->value())); +} + +bool ValidateStructHeader(const void* data, + uint32_t min_num_bytes, + uint32_t min_num_fields, + BoundsChecker* bounds_checker) { + assert(min_num_bytes >= sizeof(StructHeader)); + + if (!IsAligned(data)) { + ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT); + return false; + } + if (!bounds_checker->IsValidRange(data, sizeof(StructHeader))) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + const StructHeader* header = static_cast<const StructHeader*>(data); + + // TODO(yzshen): Currently our binding code cannot handle structs of smaller + // size or with fewer fields than the version that it sees. That needs to be + // changed in order to provide backward compatibility. + if (header->num_bytes < min_num_bytes || + header->num_fields < min_num_fields) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + + if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { + ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE); + return false; + } + + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h new file mode 100644 index 00000000000..6bebf90bf95 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bindings_serialization.h @@ -0,0 +1,83 @@ +// 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/system/core.h" + +namespace mojo { +namespace internal { + +class BoundsChecker; + +// Please note that this is a different value than |mojo::kInvalidHandleValue|, +// which is the "decoded" invalid handle. +const MojoHandle kEncodedInvalidHandleValue = static_cast<MojoHandle>(-1); + +size_t Align(size_t size); +char* AlignPointer(char* ptr); + +bool IsAligned(const void* ptr); + +// 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); +// Note: This function doesn't validate the encoded pointer value. +const void* DecodePointerRaw(const uint64_t* offset); + +// Note: This function doesn't validate the encoded pointer value. +template <typename T> +inline void DecodePointer(const uint64_t* offset, T** ptr) { + *ptr = reinterpret_cast<T*>(const_cast<void*>(DecodePointerRaw(offset))); +} + +// Checks whether decoding the pointer will overflow and produce a pointer +// smaller than |offset|. +bool ValidateEncodedPointer(const uint64_t* offset); + +// 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); +// Note: This function doesn't validate the encoded handle value. +void 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); +} + +// Note: This function doesn't validate the encoded pointer and handle values. +template <typename T> +inline void Decode(T* obj, std::vector<Handle>* handles) { + DecodePointer(&obj->offset, &obj->ptr); + if (obj->ptr) + obj->ptr->DecodePointersAndHandles(handles); +} + +// If returns true, this function also claims the memory range of the size +// specified in the struct header, starting from |data|. +// Note: |min_num_bytes| must be no less than sizeof(StructHeader). +bool ValidateStructHeader(const void* data, + uint32_t min_num_bytes, + uint32_t min_num_fields, + BoundsChecker* bounds_checker); + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc new file mode 100644 index 00000000000..cf1f3238e03 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.cc @@ -0,0 +1,77 @@ +// 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/bounds_checker.h" + +#include <assert.h> + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +namespace internal { + +BoundsChecker::BoundsChecker(const void* data, uint32_t data_num_bytes, + size_t num_handles) + : data_begin_(reinterpret_cast<uintptr_t>(data)), + data_end_(data_begin_ + data_num_bytes), + handle_begin_(0), + handle_end_(static_cast<uint32_t>(num_handles)) { + if (data_end_ < data_begin_) { + // The calculation of |data_end_| overflowed. + // It shouldn't happen but if it does, set the range to empty so + // IsValidRange() and ClaimMemory() always fail. + assert(false); // Not reached. + data_end_ = data_begin_; + } + if (handle_end_ < num_handles) { + // Assigning |num_handles| to |handle_end_| overflowed. + // It shouldn't happen but if it does, set the handle index range to empty. + assert(false); // Not reached. + handle_end_ = 0; + } +} + +BoundsChecker::~BoundsChecker() { +} + +bool BoundsChecker::ClaimMemory(const void* position, uint32_t num_bytes) { + uintptr_t begin = reinterpret_cast<uintptr_t>(position); + uintptr_t end = begin + num_bytes; + + if (!InternalIsValidRange(begin, end)) + return false; + + data_begin_ = end; + return true; +} + +bool BoundsChecker::ClaimHandle(const Handle& encoded_handle) { + uint32_t index = encoded_handle.value(); + if (index == kEncodedInvalidHandleValue) + return true; + + if (index < handle_begin_ || index >= handle_end_) + return false; + + // |index| + 1 shouldn't overflow, because |index| is not the max value of + // uint32_t (it is less than |handle_end_|). + handle_begin_ = index + 1; + return true; +} + +bool BoundsChecker::IsValidRange(const void* position, + uint32_t num_bytes) const { + uintptr_t begin = reinterpret_cast<uintptr_t>(position); + uintptr_t end = begin + num_bytes; + + return InternalIsValidRange(begin, end); +} + +bool BoundsChecker::InternalIsValidRange(uintptr_t begin, uintptr_t end) const { + return end > begin && begin >= data_begin_ && end <= data_end_; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h new file mode 100644 index 00000000000..6c472309dde --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/bounds_checker.h @@ -0,0 +1,64 @@ +// 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_BOUNDS_CHECKER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BOUNDS_CHECKER_H_ + +#include <stdint.h> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +class Handle; + +namespace internal { + +// BoundsChecker is used to validate object sizes, pointers and handle indices +// for payload of incoming messages. +class BoundsChecker { + public: + // [data, data + data_num_bytes) specifies the initial valid memory range. + // [0, num_handles) specifies the initial valid range of handle indices. + BoundsChecker(const void* data, uint32_t data_num_bytes, + size_t num_handles); + + ~BoundsChecker(); + + // Claims the specified memory range. + // The method succeeds if the range is valid to claim. (Please see + // the comments for IsValidRange().) + // On success, the valid memory range is shrinked to begin right after the end + // of the claimed range. + bool ClaimMemory(const void* position, uint32_t num_bytes); + + // Claims the specified encoded handle (which is basically a handle index). + // The method succeeds if: + // - |encoded_handle|'s value is |kEncodedInvalidHandleValue|. + // - the handle is contained inside the valid range of handle indices. In this + // case, the valid range is shinked to begin right after the claimed handle. + bool ClaimHandle(const Handle& encoded_handle); + + // Returns true if the specified range is not empty, and the range is + // contained inside the valid memory range. + bool IsValidRange(const void* position, uint32_t num_bytes) const; + + private: + bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const; + + // [data_begin_, data_end_) is the valid memory range. + uintptr_t data_begin_; + uintptr_t data_end_; + + // [handle_begin_, handle_end_) is the valid handle index range. + uint32_t handle_begin_; + uint32_t handle_end_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(BoundsChecker); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BOUNDS_CHECKER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/buffer.h b/chromium/mojo/public/cpp/bindings/lib/buffer.h new file mode 100644 index 00000000000..c3b570e7767 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/buffer.h @@ -0,0 +1,24 @@ +// 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_BUFFER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BUFFER_H_ + +#include <stddef.h> + +namespace mojo { +namespace internal { + +// Buffer provides a way to allocate memory. Allocations are 8-byte aligned and +// zero-initialized. Allocations remain valid for the lifetime of the Buffer. +class Buffer { + public: + virtual ~Buffer() {} + virtual void* Allocate(size_t num_bytes) = 0; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BUFFER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/callback_internal.h b/chromium/mojo/public/cpp/bindings/lib/callback_internal.h new file mode 100644 index 00000000000..f76ebef59e6 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/callback_internal.h @@ -0,0 +1,26 @@ +// 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_ + +namespace mojo { +class String; + +namespace internal { + +template <typename T> +struct Callback_ParamTraits { + typedef T ForwardType; +}; + +template <> +struct Callback_ParamTraits<String> { + typedef const String& ForwardType; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_CALLBACK_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.cc b/chromium/mojo/public/cpp/bindings/lib/connector.cc new file mode 100644 index 00000000000..aa2c4d12334 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/connector.cc @@ -0,0 +1,157 @@ +// 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, + const MojoAsyncWaiter* waiter) + : error_handler_(NULL), + waiter_(waiter), + message_pipe_(message_pipe.Pass()), + incoming_receiver_(NULL), + async_wait_id_(0), + error_(false), + drop_writes_(false), + enforce_errors_from_incoming_receiver_(true), + destroyed_flag_(NULL) { + // 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 (destroyed_flag_) + *destroyed_flag_ = true; + + if (async_wait_id_) + waiter_->CancelWait(async_wait_id_); +} + +void Connector::CloseMessagePipe() { + Close(message_pipe_.Pass()); +} + +ScopedMessagePipeHandle Connector::PassMessagePipe() { + if (async_wait_id_) { + waiter_->CancelWait(async_wait_id_); + async_wait_id_ = 0; + } + return message_pipe_.Pass(); +} + +bool Connector::Accept(Message* message) { + assert(message_pipe_.is_valid()); + + 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; +} + +// static +void Connector::CallOnHandleReady(void* closure, MojoResult result) { + Connector* self = static_cast<Connector*>(closure); + self->OnHandleReady(result); +} + +void Connector::OnHandleReady(MojoResult result) { + assert(async_wait_id_ != 0); + async_wait_id_ = 0; + + if (result == MOJO_RESULT_OK) { + // Return immediately if |this| was destroyed. Do not touch any members! + if (!ReadMore()) + return; + } else { + error_ = true; + } + + if (error_ && error_handler_) + error_handler_->OnConnectionError(); +} + +void Connector::WaitToReadMore() { + async_wait_id_ = waiter_->AsyncWait(message_pipe_.get().value(), + MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, + &Connector::CallOnHandleReady, + this); +} + +bool Connector::ReadMore() { + while (true) { + bool receiver_result = false; + + // Detect if |this| was destroyed during message dispatch. Allow for the + // possibility of re-entering ReadMore() through message dispatch. + bool was_destroyed_during_dispatch = false; + bool* previous_destroyed_flag = destroyed_flag_; + destroyed_flag_ = &was_destroyed_during_dispatch; + + MojoResult rv = ReadAndDispatchMessage( + message_pipe_.get(), incoming_receiver_, &receiver_result); + + if (was_destroyed_during_dispatch) { + if (previous_destroyed_flag) + *previous_destroyed_flag = true; // Propagate flag. + return false; + } + destroyed_flag_ = previous_destroyed_flag; + + if (rv == MOJO_RESULT_SHOULD_WAIT) { + WaitToReadMore(); + break; + } + if (rv != MOJO_RESULT_OK || + (enforce_errors_from_incoming_receiver_ && !receiver_result)) { + error_ = true; + break; + } + } + return true; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.h b/chromium/mojo/public/cpp/bindings/lib/connector.h new file mode 100644 index 00000000000..30cd65f4c42 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/connector.h @@ -0,0 +1,100 @@ +// 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/c/environment/async_waiter.h" +#include "mojo/public/cpp/bindings/lib/message_queue.h" +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/environment/environment.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, + const MojoAsyncWaiter* waiter = Environment::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; + } + + // Errors from incoming receivers will force the connector into an error + // state, where no more messages will be processed. This method is used + // during testing to prevent that from happening. + void set_enforce_errors_from_incoming_receiver(bool enforce) { + enforce_errors_from_incoming_receiver_ = enforce; + } + + // 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. Connector is put into a + // quiescent state. + void CloseMessagePipe(); + + // Releases the pipe, not triggering the error state. Connector is put into + // a quiescent state. + ScopedMessagePipeHandle PassMessagePipe(); + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE; + + private: + static void CallOnHandleReady(void* closure, MojoResult result); + void OnHandleReady(MojoResult result); + + void WaitToReadMore(); + + // Returns false if |this| was destroyed during message dispatch. + MOJO_WARN_UNUSED_RESULT bool ReadMore(); + + ErrorHandler* error_handler_; + const MojoAsyncWaiter* waiter_; + + ScopedMessagePipeHandle message_pipe_; + MessageReceiver* incoming_receiver_; + + MojoAsyncWaitID async_wait_id_; + bool error_; + bool drop_writes_; + bool enforce_errors_from_incoming_receiver_; + + // If non-null, this will be set to true when the Connector is destroyed. We + // use this flag to allow for the Connector to be destroyed as a side-effect + // of dispatching an incoming message. + bool* destroyed_flag_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Connector); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_CONNECTOR_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/filter_chain.cc b/chromium/mojo/public/cpp/bindings/lib/filter_chain.cc new file mode 100644 index 00000000000..efd4ba19875 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/filter_chain.cc @@ -0,0 +1,49 @@ +// 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/filter_chain.h" + +#include <assert.h> + +#include <algorithm> + +namespace mojo { +namespace internal { + +FilterChain::FilterChain(MessageReceiver* sink) : sink_(sink) { +} + +FilterChain::FilterChain(RValue other) : sink_(other.object->sink_) { + other.object->sink_ = NULL; + filters_.swap(other.object->filters_); +} + +FilterChain& FilterChain::operator=(RValue other) { + std::swap(sink_, other.object->sink_); + filters_.swap(other.object->filters_); + return *this; +} + +FilterChain::~FilterChain() { + for (std::vector<MessageFilter*>::iterator iter = filters_.begin(); + iter != filters_.end(); + ++iter) { + delete *iter; + } +} + +void FilterChain::SetSink(MessageReceiver* sink) { + assert(!sink_); + sink_ = sink; + if (!filters_.empty()) + filters_.back()->set_sink(sink); +} + +MessageReceiver* FilterChain::GetHead() { + assert(sink_); + return filters_.empty() ? sink_ : filters_.front(); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/filter_chain.h b/chromium/mojo/public/cpp/bindings/lib/filter_chain.h new file mode 100644 index 00000000000..8680f41aaee --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/filter_chain.h @@ -0,0 +1,66 @@ +// 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_FILTER_CHAIN_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_ + +#include <vector> + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/bindings/message_filter.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +class FilterChain { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(FilterChain, RValue) + + public: + // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while + // this object is alive. + explicit FilterChain(MessageReceiver* sink = NULL); + + // Move-only constructor and operator=. + FilterChain(RValue other); + FilterChain& operator=(RValue other); + + ~FilterChain(); + + template <typename FilterType> + inline void Append(); + + // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while + // this object is alive. + void SetSink(MessageReceiver* sink); + + // Returns a receiver to accept messages. Messages flow through all filters in + // the same order as they were appended to the chain. If all filters allow a + // message to pass, it will be forwarded to |sink_|. + // The returned value is invalidated when this object goes away. + MessageReceiver* GetHead(); + + private: + // Owned by this object. + std::vector<MessageFilter*> filters_; + + MessageReceiver* sink_; +}; + +template <typename FilterType> +inline void FilterChain::Append() { + FilterType* filter = new FilterType(sink_); + if (!filters_.empty()) + filters_.back()->set_sink(filter); + filters_.push_back(filter); +} + +template <> +inline void FilterChain::Append<PassThroughFilter>() { +} + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_FILTER_CHAIN_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc new file mode 100644 index 00000000000..5226231725c --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.cc @@ -0,0 +1,53 @@ +// 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)) { + // calloc() required to zero memory and thus avoid info leaks. + ptr_ = static_cast<char*>(calloc(size_, 1)); +} + +FixedBuffer::~FixedBuffer() { + free(ptr_); +} + +void* FixedBuffer::Allocate(size_t delta) { + 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/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h new file mode 100644 index 00000000000..a3515a2ae86 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/fixed_buffer.h @@ -0,0 +1,67 @@ +// 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/lib/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) 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/chromium/mojo/public/cpp/bindings/lib/interface_impl_internal.h b/chromium/mojo/public/cpp/bindings/lib/interface_impl_internal.h new file mode 100644 index 00000000000..f2cc4f0c5b6 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/interface_impl_internal.h @@ -0,0 +1,94 @@ +// 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_INTERFACE_IMPL_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ + +#include "mojo/public/cpp/bindings/error_handler.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/bindings/lib/filter_chain.h" +#include "mojo/public/cpp/bindings/lib/message_header_validator.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfaceImplBase : public Interface { + public: + virtual ~InterfaceImplBase() {} + virtual void OnConnectionEstablished() = 0; + virtual void OnConnectionError() = 0; +}; + +template <typename Interface> +class InterfaceImplState : public ErrorHandler { + public: + typedef typename Interface::Client Client; + + explicit InterfaceImplState(InterfaceImplBase<Interface>* instance) + : router_(NULL), + proxy_(NULL) { + assert(instance); + stub_.set_sink(instance); + } + + virtual ~InterfaceImplState() { + delete proxy_; + if (router_) { + router_->set_error_handler(NULL); + delete router_; + } + } + + void BindProxy( + InterfacePtr<Interface>* ptr, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass(), waiter); + Bind(pipe.handle1.Pass(), waiter); + } + + void Bind(ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter) { + assert(!router_); + + FilterChain filters; + filters.Append<MessageHeaderValidator>(); + filters.Append<typename Interface::RequestValidator_>(); + filters.Append<typename Interface::Client::ResponseValidator_>(); + + router_ = new Router(handle.Pass(), filters.Pass(), waiter); + router_->set_incoming_receiver(&stub_); + router_->set_error_handler(this); + + proxy_ = new typename Client::Proxy_(router_); + + instance()->OnConnectionEstablished(); + } + + Router* router() { return router_; } + Client* client() { return proxy_; } + + private: + InterfaceImplBase<Interface>* instance() { + return static_cast<InterfaceImplBase<Interface>*>(stub_.sink()); + } + + virtual void OnConnectionError() MOJO_OVERRIDE { + instance()->OnConnectionError(); + } + + Router* router_; + typename Client::Proxy_* proxy_; + typename Interface::Stub_ stub_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImplState); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_internal.h b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_internal.h new file mode 100644 index 00000000000..a318d6185c5 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_internal.h @@ -0,0 +1,84 @@ +// 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_INTERFACE_PTR_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ + +#include <assert.h> +#include <stdio.h> + +#include "mojo/public/cpp/bindings/lib/filter_chain.h" +#include "mojo/public/cpp/bindings/lib/message_header_validator.h" +#include "mojo/public/cpp/bindings/lib/router.h" +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfacePtrState { + public: + InterfacePtrState() : proxy_(NULL), router_(NULL) {} + + ~InterfacePtrState() { + // Destruction order matters here. We delete |proxy_| first, even though + // |router_| may have a reference to it, so that |~Interface| may have a + // shot at generating new outbound messages (ie, invoking client methods). + delete proxy_; + delete router_; + } + + Interface* instance() const { return proxy_; } + + Router* router() const { return router_; } + + void Swap(InterfacePtrState* other) { + std::swap(other->proxy_, proxy_); + std::swap(other->router_, router_); + } + + void ConfigureProxy( + ScopedMessagePipeHandle handle, + const MojoAsyncWaiter* waiter = Environment::GetDefaultAsyncWaiter()) { + assert(!proxy_); + assert(!router_); + + FilterChain filters; + filters.Append<MessageHeaderValidator>(); + filters.Append<typename Interface::Client::RequestValidator_>(); + filters.Append<typename Interface::ResponseValidator_>(); + + router_ = new Router(handle.Pass(), filters.Pass(), waiter); + ProxyWithStub* proxy = new ProxyWithStub(router_); + router_->set_incoming_receiver(&proxy->stub); + + proxy_ = proxy; + } + + void set_client(typename Interface::Client* client) { + assert(proxy_); + proxy_->stub.set_sink(client); + } + + private: + class ProxyWithStub : public Interface::Proxy_ { + public: + explicit ProxyWithStub(MessageReceiverWithResponder* receiver) + : Interface::Proxy_(receiver) { + } + typename Interface::Client::Stub_ stub; + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyWithStub); + }; + + ProxyWithStub* proxy_; + Router* router_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/message.cc b/chromium/mojo/public/cpp/bindings/lib/message.cc new file mode 100644 index 00000000000..78017c00793 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message.cc @@ -0,0 +1,81 @@ +// 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) + *receiver_result = receiver->Accept(&message); + + return rv; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_builder.cc b/chromium/mojo/public/cpp/bindings/lib/message_builder.cc new file mode 100644 index 00000000000..c7466444d04 --- /dev/null +++ b/chromium/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/chromium/mojo/public/cpp/bindings/lib/message_builder.h b/chromium/mojo/public/cpp/bindings/lib/message_builder.h new file mode 100644 index 00000000000..b4988ff9cb9 --- /dev/null +++ b/chromium/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/chromium/mojo/public/cpp/bindings/lib/message_filter.cc b/chromium/mojo/public/cpp/bindings/lib/message_filter.cc new file mode 100644 index 00000000000..b09f40d8c5e --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_filter.cc @@ -0,0 +1,23 @@ +// 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/message_filter.h" + +namespace mojo { + +MessageFilter::MessageFilter(MessageReceiver* sink) : sink_(sink) { +} + +MessageFilter::~MessageFilter() { +} + +PassThroughFilter::PassThroughFilter(MessageReceiver* sink) + : MessageFilter(sink) { +} + +bool PassThroughFilter::Accept(Message* message) { + return sink_->Accept(message); +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc new file mode 100644 index 00000000000..a55917afde5 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.cc @@ -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. + +#include "mojo/public/cpp/bindings/lib/message_header_validator.h" + +#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" +#include "mojo/public/cpp/bindings/lib/bounds_checker.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" + +namespace mojo { +namespace internal { +namespace { + +bool IsValidMessageHeader(const MessageHeader* header) { + // NOTE: Our goal is to preserve support for future extension of the message + // header. If we encounter fields we do not understand, we must ignore them. + + // Extra validation of the struct header: + if (header->num_fields == 2) { + if (header->num_bytes != sizeof(MessageHeader)) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + } else if (header->num_fields == 3) { + if (header->num_bytes != sizeof(MessageHeaderWithRequestID)) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + } else if (header->num_fields > 3) { + if (header->num_bytes < sizeof(MessageHeaderWithRequestID)) { + ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER); + return false; + } + } + + // Validate flags (allow unknown bits): + + // These flags require a RequestID. + if (header->num_fields < 3 && + ((header->flags & kMessageExpectsResponse) || + (header->flags & kMessageIsResponse))) { + ReportValidationError(VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID); + return false; + } + + // These flags are mutually exclusive. + if ((header->flags & kMessageExpectsResponse) && + (header->flags & kMessageIsResponse)) { + ReportValidationError( + VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION); + return false; + } + + return true; +} + +} // namespace + +MessageHeaderValidator::MessageHeaderValidator(MessageReceiver* sink) + : MessageFilter(sink) { +} + +bool MessageHeaderValidator::Accept(Message* message) { + // Pass 0 as number of handles because we don't expect any in the header, even + // if |message| contains handles. + BoundsChecker bounds_checker(message->data(), message->data_num_bytes(), 0); + + if (!ValidateStructHeader(message->data(), sizeof(MessageHeader), 2, + &bounds_checker)) { + return false; + } + + if (!IsValidMessageHeader(message->header())) + return false; + + return sink_->Accept(message); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/message_header_validator.h b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.h new file mode 100644 index 00000000000..c3f43a07fbc --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/message_header_validator.h @@ -0,0 +1,24 @@ +// 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_HEADER_VALIDATOR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_HEADER_VALIDATOR_H_ + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/bindings/message_filter.h" + +namespace mojo { +namespace internal { + +class MessageHeaderValidator : public MessageFilter { + public: + explicit MessageHeaderValidator(MessageReceiver* sink = NULL); + + virtual bool Accept(Message* message) MOJO_OVERRIDE; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_HEADER_VALIDATOR_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/message_internal.h b/chromium/mojo/public/cpp/bindings/lib/message_internal.h new file mode 100644 index 00000000000..3c67902b7a8 --- /dev/null +++ b/chromium/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/chromium/mojo/public/cpp/bindings/lib/message_queue.cc b/chromium/mojo/public/cpp/bindings/lib/message_queue.cc new file mode 100644 index 00000000000..1982ccb14c2 --- /dev/null +++ b/chromium/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/chromium/mojo/public/cpp/bindings/lib/message_queue.h b/chromium/mojo/public/cpp/bindings/lib/message_queue.h new file mode 100644 index 00000000000..4e46b54a250 --- /dev/null +++ b/chromium/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/chromium/mojo/public/cpp/bindings/lib/no_interface.cc b/chromium/mojo/public/cpp/bindings/lib/no_interface.cc new file mode 100644 index 00000000000..9e0945c83b3 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/no_interface.cc @@ -0,0 +1,20 @@ +// 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/no_interface.h" + +namespace mojo { + +const char* NoInterface::Name_ = "mojo::NoInterface"; + +bool NoInterfaceStub::Accept(Message* message) { + return false; +} + +bool NoInterfaceStub::AcceptWithResponder(Message* message, + MessageReceiver* responder) { + return false; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/router.cc b/chromium/mojo/public/cpp/bindings/lib/router.cc new file mode 100644 index 00000000000..a8222203c47 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/router.cc @@ -0,0 +1,140 @@ +// 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; + } + + private: + SharedData<Router*> router_; +}; + +// ---------------------------------------------------------------------------- + +Router::HandleIncomingMessageThunk::HandleIncomingMessageThunk(Router* router) + : router_(router) { +} + +Router::HandleIncomingMessageThunk::~HandleIncomingMessageThunk() { +} + +bool Router::HandleIncomingMessageThunk::Accept(Message* message) { + return router_->HandleIncomingMessage(message); +} + +// ---------------------------------------------------------------------------- + +Router::Router(ScopedMessagePipeHandle message_pipe, + FilterChain filters, + const MojoAsyncWaiter* waiter) + : thunk_(this), + filters_(filters.Pass()), + connector_(message_pipe.Pass(), waiter), + weak_self_(this), + incoming_receiver_(NULL), + next_request_id_(0), + testing_mode_(false) { + filters_.SetSink(&thunk_); + connector_.set_incoming_receiver(filters_.GetHead()); +} + +Router::~Router() { + weak_self_.set_value(NULL); + + for (ResponderMap::const_iterator i = responders_.begin(); + i != responders_.end(); ++i) { + delete i->second; + } +} + +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; +} + +void Router::EnableTestingMode() { + testing_mode_ = true; + connector_.set_enforce_errors_from_incoming_receiver(false); +} + +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(testing_mode_); + return false; + } + MessageReceiver* responder = it->second; + responders_.erase(it); + bool ok = responder->Accept(message); + delete responder; + return ok; + } 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/chromium/mojo/public/cpp/bindings/lib/router.h b/chromium/mojo/public/cpp/bindings/lib/router.h new file mode 100644 index 00000000000..76bf1471e2e --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/router.h @@ -0,0 +1,91 @@ +// 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/filter_chain.h" +#include "mojo/public/cpp/bindings/lib/shared_data.h" +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { +namespace internal { + +class Router : public MessageReceiverWithResponder { + public: + Router(ScopedMessagePipeHandle message_pipe, + FilterChain filters, + const MojoAsyncWaiter* waiter = Environment::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(MessageReceiverWithResponder* 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(); } + + void CloseMessagePipe() { + connector_.CloseMessagePipe(); + } + + ScopedMessagePipeHandle PassMessagePipe() { + return connector_.PassMessagePipe(); + } + + // MessageReceiver implementation: + virtual bool Accept(Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) + MOJO_OVERRIDE; + + // Sets this object to testing mode. + // In testing mode: + // - the object is more tolerant of unrecognized response messages; + // - the connector continues working after seeing errors from its incoming + // receiver. + void EnableTestingMode(); + + 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; + + private: + Router* router_; + }; + + bool HandleIncomingMessage(Message* message); + + HandleIncomingMessageThunk thunk_; + FilterChain filters_; + Connector connector_; + SharedData<Router*> weak_self_; + MessageReceiverWithResponder* incoming_receiver_; + ResponderMap responders_; + uint64_t next_request_id_; + bool testing_mode_; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ROUTER_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/shared_data.h b/chromium/mojo/public/cpp/bindings/lib/shared_data.h new file mode 100644 index 00000000000..c7bd54f8d7c --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/shared_data.h @@ -0,0 +1,84 @@ +// 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_ + +#include "mojo/public/cpp/system/macros.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(); + return *this; + } + + 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/chromium/mojo/public/cpp/bindings/lib/shared_ptr.h b/chromium/mojo/public/cpp/bindings/lib/shared_ptr.h new file mode 100644 index 00000000000..6ae53a5681a --- /dev/null +++ b/chromium/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/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc new file mode 100644 index 00000000000..0044b1b9cff --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/string_serialization.cc @@ -0,0 +1,38 @@ +// 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/string_serialization.h" + +#include <string.h> + +namespace mojo { + +size_t GetSerializedSize_(const String& input) { + if (!input) + return 0; + return internal::Align(sizeof(internal::String_Data) + input.size()); +} + +void Serialize_(const String& input, internal::Buffer* buf, + internal::String_Data** output) { + if (input) { + internal::String_Data* result = + internal::String_Data::New(input.size(), buf); + memcpy(result->storage(), input.data(), input.size()); + *output = result; + } else { + *output = NULL; + } +} + +void Deserialize_(internal::String_Data* input, String* output) { + if (input) { + String result(input->storage(), input->size()); + result.Swap(output); + } else { + output->reset(); + } +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/string_serialization.h b/chromium/mojo/public/cpp/bindings/lib/string_serialization.h new file mode 100644 index 00000000000..bad2a0c2766 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/string_serialization.h @@ -0,0 +1,20 @@ +// 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_STRING_SERIALIZATION_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_ + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/string.h" + +namespace mojo { + +size_t GetSerializedSize_(const String& input); +void Serialize_(const String& input, internal::Buffer* buffer, + internal::String_Data** output); +void Deserialize_(internal::String_Data* input, String* output); + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_STRING_SERIALIZATION_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/sync_dispatcher.cc b/chromium/mojo/public/cpp/bindings/lib/sync_dispatcher.cc new file mode 100644 index 00000000000..2cde97f6ee4 --- /dev/null +++ b/chromium/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_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE); + if (rv != MOJO_RESULT_OK) + return false; + } +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/template_util.h b/chromium/mojo/public/cpp/bindings/lib/template_util.h new file mode 100644 index 00000000000..599126691ed --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/template_util.h @@ -0,0 +1,89 @@ +// 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_TEMPLATE_UTIL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_TEMPLATE_UTIL_H_ + +namespace mojo { +namespace internal { + +template<class T, T v> +struct IntegralConstant { + static const T value = v; +}; + +template <class T, T v> const T IntegralConstant<T, v>::value; + +typedef IntegralConstant<bool, true> TrueType; +typedef IntegralConstant<bool, false> FalseType; + +template <class T> struct IsConst : FalseType {}; +template <class T> struct IsConst<const T> : TrueType {}; + +template<bool B, typename T = void> +struct EnableIf {}; + +template<typename T> +struct EnableIf<true, T> { typedef T type; }; + +// Types YesType and NoType are guaranteed such that sizeof(YesType) < +// sizeof(NoType). +typedef char YesType; + +struct NoType { + YesType dummy[2]; +}; + +// A helper template to determine if given type is non-const move-only-type, +// i.e. if a value of the given type should be passed via .Pass() in a +// destructive way. +template <typename T> struct IsMoveOnlyType { + template <typename U> + static YesType Test(const typename U::MoveOnlyTypeForCPP03*); + + template <typename U> + static NoType Test(...); + + static const bool value = sizeof(Test<T>(0)) == sizeof(YesType) && + !IsConst<T>::value; +}; + +template <typename T> +typename EnableIf<!IsMoveOnlyType<T>::value, T>::type& Forward(T& t) { + return t; +} + +template <typename T> +typename EnableIf<IsMoveOnlyType<T>::value, T>::type Forward(T& t) { + return t.Pass(); +} + +// This goop is a trick used to implement a template that can be used to +// determine if a given class is the base class of another given class. +template<typename, typename> struct IsSame { + static bool const value = false; +}; +template<typename A> struct IsSame<A, A> { + static bool const value = true; +}; +template<typename Base, typename Derived> struct IsBaseOf { + private: + // This class doesn't work correctly with forward declarations. + // Because sizeof cannot be applied to incomplete types, this line prevents us + // from passing in forward declarations. + typedef char (*EnsureTypesAreComplete)[sizeof(Base) + sizeof(Derived)]; + + static Derived* CreateDerived(); + static char (&Check(Base*))[1]; + static char (&Check(...))[2]; + + public: + static bool const value = sizeof Check(CreateDerived()) == 1 && + !IsSame<Base const, void const>::value; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_TEMPLATE_UTIL_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/validation_errors.cc b/chromium/mojo/public/cpp/bindings/lib/validation_errors.cc new file mode 100644 index 00000000000..ed5904d3963 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/validation_errors.cc @@ -0,0 +1,64 @@ +// 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/validation_errors.h" + +#include <assert.h> +#include <stdio.h> + +namespace mojo { +namespace internal { +namespace { + +ValidationErrorObserverForTesting* g_validation_error_observer = NULL; + +} // namespace + +const char* ValidationErrorToString(ValidationError error) { + switch (error) { + case VALIDATION_ERROR_NONE: + return "VALIDATION_ERROR_NONE"; + case VALIDATION_ERROR_MISALIGNED_OBJECT: + return "VALIDATION_ERROR_MISALIGNED_OBJECT"; + case VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE: + return "VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE"; + case VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER: + return "VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER"; + case VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER: + return "VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER"; + case VALIDATION_ERROR_ILLEGAL_HANDLE: + return "VALIDATION_ERROR_ILLEGAL_HANDLE"; + case VALIDATION_ERROR_ILLEGAL_POINTER: + return "VALIDATION_ERROR_ILLEGAL_POINTER"; + case VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION: + return "VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION"; + case VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID: + return "VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID"; + } + + return "Unknown error"; +} + +void ReportValidationError(ValidationError error) { + if (g_validation_error_observer) { + g_validation_error_observer->set_last_error(error); + } else { + // TODO(yzshen): Consider adding better logging support. + fprintf(stderr, "Invalid message: %s\n", ValidationErrorToString(error)); + } +} + +ValidationErrorObserverForTesting::ValidationErrorObserverForTesting() + : last_error_(VALIDATION_ERROR_NONE) { + assert(!g_validation_error_observer); + g_validation_error_observer = this; +} + +ValidationErrorObserverForTesting::~ValidationErrorObserverForTesting() { + assert(g_validation_error_observer == this); + g_validation_error_observer = NULL; +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/validation_errors.h b/chromium/mojo/public/cpp/bindings/lib/validation_errors.h new file mode 100644 index 00000000000..9b443c371e5 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/lib/validation_errors.h @@ -0,0 +1,66 @@ +// 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_VALIDATION_ERRORS_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_ + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +enum ValidationError { + // There is no validation error. + VALIDATION_ERROR_NONE, + // An object (struct or array) is not 8-byte aligned. + VALIDATION_ERROR_MISALIGNED_OBJECT, + // An object is not contained inside the message data, or it overlaps other + // objects. + VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE, + // A struct header doesn't make sense, for example: + // - |num_bytes| is smaller than the size of the oldest version that we + // support. + // - |num_fields| is smaller than the field number of the oldest version that + // we support. + // - |num_bytes| and |num_fields| don't match. + VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER, + // An array header doesn't make sense, for example: + // - |num_bytes| is smaller than the size of the header plus the size required + // to store |num_elements| elements. + VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, + // An encoded handle is illegal. + VALIDATION_ERROR_ILLEGAL_HANDLE, + // An encoded pointer is illegal. + VALIDATION_ERROR_ILLEGAL_POINTER, + // |flags| in the message header is an invalid flag combination. + VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION, + // |flags| in the message header indicates that a request ID is required but + // there isn't one. + VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID, +}; + +const char* ValidationErrorToString(ValidationError error); + +void ReportValidationError(ValidationError error); + +// Only used by validation tests and when there is only one thread doing message +// validation. +class ValidationErrorObserverForTesting { + public: + ValidationErrorObserverForTesting(); + ~ValidationErrorObserverForTesting(); + + ValidationError last_error() const { return last_error_; } + void set_last_error(ValidationError error) { last_error_ = error; } + + private: + ValidationError last_error_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_ diff --git a/chromium/mojo/public/cpp/bindings/message.h b/chromium/mojo/public/cpp/bindings/message.h new file mode 100644 index 00000000000..beb1cd9036f --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/message.h @@ -0,0 +1,123 @@ +// 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_MESSAGE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_ + +#include <assert.h> + +#include <vector> + +#include "mojo/public/cpp/bindings/lib/message_internal.h" + +namespace mojo { + +// Message is a holder for the data and handles to be sent over a MessagePipe. +// Message owns its data and handles, but a consumer of Message is free to +// mutate the data and handles. The message's data is comprised of a header +// followed by payload. +class Message { + public: + Message(); + ~Message(); + + // These may only be called on a newly created Message object. + void AllocUninitializedData(uint32_t num_bytes); + void AdoptData(uint32_t num_bytes, internal::MessageData* data); + + // Swaps data and handles between this Message and another. + void Swap(Message* other); + + uint32_t data_num_bytes() const { return data_num_bytes_; } + + // Access the raw bytes of the message. + const uint8_t* data() const { return + reinterpret_cast<const uint8_t*>(data_); + } + uint8_t* mutable_data() { return reinterpret_cast<uint8_t*>(data_); } + + // Access the header. + const internal::MessageHeader* header() const { return &data_->header; } + + uint32_t name() const { return data_->header.name; } + bool has_flag(uint32_t flag) const { return !!(data_->header.flags & flag); } + + // Access the request_id field (if present). + bool has_request_id() const { return data_->header.num_fields >= 3; } + uint64_t request_id() const { + assert(has_request_id()); + return static_cast<const internal::MessageHeaderWithRequestID*>( + &data_->header)->request_id; + } + void set_request_id(uint64_t request_id) { + assert(has_request_id()); + static_cast<internal::MessageHeaderWithRequestID*>(&data_->header)-> + request_id = request_id; + } + + // Access the payload. + const uint8_t* payload() const { + return reinterpret_cast<const uint8_t*>(data_) + data_->header.num_bytes; + } + uint8_t* mutable_payload() { + return reinterpret_cast<uint8_t*>(data_) + data_->header.num_bytes; + } + uint32_t payload_num_bytes() const { + assert(data_num_bytes_ >= data_->header.num_bytes); + return data_num_bytes_ - data_->header.num_bytes; + } + + // Access the handles. + const std::vector<Handle>* handles() const { return &handles_; } + std::vector<Handle>* mutable_handles() { return &handles_; } + + private: + uint32_t data_num_bytes_; + internal::MessageData* data_; // Heap-allocated using malloc. + std::vector<Handle> handles_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Message); +}; + +class MessageReceiver { + public: + virtual ~MessageReceiver() {} + + // The receiver may mutate the given message. Returns true if the message + // was accepted and false otherwise, indicating that the message was invalid + // or malformed. + virtual bool Accept(Message* message) MOJO_WARN_UNUSED_RESULT = 0; +}; + +class MessageReceiverWithResponder : public MessageReceiver { + public: + virtual ~MessageReceiverWithResponder() {} + + // A variant on Accept that registers a MessageReceiver (known as the + // responder) to handle the response message generated from the given + // message. The responder's Accept method may be called during + // AcceptWithResponder or some time after its return. + // + // NOTE: Upon returning true, AcceptWithResponder assumes ownership of + // |responder| and will delete it after calling |responder->Accept| or upon + // its own destruction. + // + virtual bool AcceptWithResponder( + Message* message, MessageReceiver* responder) MOJO_WARN_UNUSED_RESULT = 0; +}; + +// Read a single message from the pipe and dispatch to the given receiver. The +// receiver may be null, in which case the message is simply discarded. +// Returns MOJO_RESULT_SHOULD_WAIT if the caller should wait on the handle to +// become readable. Returns MOJO_RESULT_OK if a message was dispatched and +// otherwise returns an error code if something went wrong. +// +// NOTE: The message hasn't been validated and may be malformed! +MojoResult ReadAndDispatchMessage(MessagePipeHandle handle, + MessageReceiver* receiver, + bool* receiver_result); + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_ diff --git a/chromium/mojo/public/cpp/bindings/message_filter.h b/chromium/mojo/public/cpp/bindings/message_filter.h new file mode 100644 index 00000000000..6d716733ecc --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/message_filter.h @@ -0,0 +1,39 @@ +// 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_MESSAGE_FILTER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_FILTER_H_ + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// This class is the base class for message filters. Subclasses should +// implement the pure virtual method Accept() inherited from MessageReceiver to +// process messages and/or forward them to |sink_|. +class MessageFilter : public MessageReceiver { + public: + // Doesn't take ownership of |sink|. Therefore |sink| has to stay alive while + // this object is alive. + explicit MessageFilter(MessageReceiver* sink = NULL); + virtual ~MessageFilter(); + + void set_sink(MessageReceiver* sink) { sink_ = sink; } + + protected: + MessageReceiver* sink_; +}; + +// A trivial filter that simply forwards every message it receives to |sink_|. +class PassThroughFilter : public MessageFilter { + public: + explicit PassThroughFilter(MessageReceiver* sink = NULL); + + virtual bool Accept(Message* message) MOJO_OVERRIDE; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_MESSAGE_FILTER_H_ diff --git a/chromium/mojo/public/cpp/bindings/no_interface.h b/chromium/mojo/public/cpp/bindings/no_interface.h new file mode 100644 index 00000000000..83b0eff5000 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/no_interface.h @@ -0,0 +1,56 @@ +// 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_NO_INTERFACE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_ + +#include <assert.h> + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/bindings/message_filter.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +// NoInterface is for use in cases when a non-existent or empty interface is +// needed (e.g., when the Mojom "Peer" attribute is not present). + +class NoInterfaceProxy; +class NoInterfaceStub; + +class NoInterface { + public: + static const char* Name_; + typedef NoInterfaceProxy Proxy_; + typedef NoInterfaceStub Stub_; + typedef PassThroughFilter RequestValidator_; + typedef PassThroughFilter ResponseValidator_; + typedef NoInterface Client; + virtual ~NoInterface() {} +}; + +class NoInterfaceProxy : public NoInterface { + public: + explicit NoInterfaceProxy(MessageReceiver* receiver) {} +}; + +class NoInterfaceStub : public MessageReceiverWithResponder { + public: + NoInterfaceStub() {} + void set_sink(NoInterface* sink) {} + NoInterface* sink() { return NULL; } + virtual bool Accept(Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) + MOJO_OVERRIDE; +}; + + +// AnyInterface is for use in cases where any interface would do (e.g., see the +// Shell::Connect method). + +typedef NoInterface AnyInterface; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_ diff --git a/chromium/mojo/public/cpp/bindings/string.h b/chromium/mojo/public/cpp/bindings/string.h new file mode 100644 index 00000000000..a2427844975 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/string.h @@ -0,0 +1,154 @@ +// 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_STRING_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRING_H_ + +#include <assert.h> + +#include <string> + +#include "mojo/public/cpp/bindings/lib/array_internal.h" +#include "mojo/public/cpp/bindings/type_converter.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +class String { + public: + typedef internal::String_Data Data_; + + String() : is_null_(true) {} + String(const std::string& str) : value_(str), is_null_(false) {} + String(const char* chars) : is_null_(!chars) { + if (chars) + value_ = chars; + } + String(const char* chars, size_t num_chars) + : value_(chars, num_chars), + is_null_(false) { + } + template <size_t N> + String(const char chars[N]) : value_(chars, N-1), is_null_(false) {} + + template <typename U> + static String From(const U& other) { + return TypeConverter<String, U>::ConvertFrom(other); + } + + template <typename U> + U To() const { + return TypeConverter<String, U>::ConvertTo(*this); + } + + String& operator=(const std::string& str) { + value_ = str; + is_null_ = false; + return *this; + } + String& operator=(const char* chars) { + is_null_ = !chars; + if (chars) { + value_ = chars; + } else { + value_.clear(); + } + return *this; + } + + void reset() { + value_.clear(); + is_null_ = true; + } + + bool is_null() const { return is_null_; } + + size_t size() const { return value_.size(); } + + const char* data() const { return value_.data(); } + + const char& at(size_t offset) const { return value_.at(offset); } + const char& operator[](size_t offset) const { return value_[offset]; } + + const std::string& get() const { return value_; } + operator const std::string&() const { return value_; } + + void Swap(String* other) { + std::swap(is_null_, other->is_null_); + value_.swap(other->value_); + } + + void Swap(std::string* other) { + is_null_ = false; + value_.swap(*other); + } + + private: + typedef std::string String::*Testable; + + public: + operator Testable() const { return is_null_ ? 0 : &String::value_; } + + private: + std::string value_; + bool is_null_; +}; + +inline bool operator==(const String& a, const String& b) { + return a.is_null() == b.is_null() && a.get() == b.get(); +} +inline bool operator==(const char* a, const String& b) { + return !b.is_null() && a == b.get(); +} +inline bool operator==(const String& a, const char* b) { + return !a.is_null() && a.get() == b; +} +inline bool operator!=(const String& a, const String& b) { return !(a == b); } +inline bool operator!=(const char* a, const String& b) { return !(a == b); } +inline bool operator!=(const String& a, const char* b) { return !(a == b); } + +// TODO(darin): Add similar variants of operator<,<=,>,>= + +template <> +class TypeConverter<String, std::string> { + public: + static String ConvertFrom(const std::string& input) { + return String(input); + } + static std::string ConvertTo(const String& input) { + return input; + } +}; + +template <size_t N> +class TypeConverter<String, char[N]> { + public: + static String ConvertFrom(const char input[N]) { + assert(input); + return String(input, N-1); + } +}; + +// Appease MSVC. +template <size_t N> +class TypeConverter<String, const char[N]> { + public: + static String ConvertFrom(const char input[N]) { + assert(input); + return String(input, N-1); + } +}; + +template <> +class TypeConverter<String, const char*> { + public: + // |input| may be null, in which case a null String will be returned. + static String ConvertFrom(const char* input) { + return String(input); + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRING_H_ diff --git a/chromium/mojo/public/cpp/bindings/struct_ptr.h b/chromium/mojo/public/cpp/bindings/struct_ptr.h new file mode 100644 index 00000000000..a4e55e758f4 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/struct_ptr.h @@ -0,0 +1,154 @@ +// 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_STRUCT_PTR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ + +#include <assert.h> + +#include <new> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +template <typename Struct> +class StructHelper { + public: + template <typename Ptr> + static void Initialize(Ptr* ptr) { ptr->Initialize(); } +}; + +} // namespace internal + +template <typename Struct> +class StructPtr { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(StructPtr, RValue); + public: + typedef typename Struct::Data_ Data_; + + StructPtr() : ptr_(NULL) {} + ~StructPtr() { + delete ptr_; + } + + StructPtr(RValue other) : ptr_(NULL) { Take(other.object); } + StructPtr& operator=(RValue other) { + Take(other.object); + return *this; + } + + template <typename U> + U To() const { + return TypeConverter<StructPtr, U>::ConvertTo(*this); + } + + void reset() { + if (ptr_) { + delete ptr_; + ptr_ = NULL; + } + } + + bool is_null() const { return ptr_ == NULL; } + + Struct& operator*() const { + assert(ptr_); + return *ptr_; + } + Struct* operator->() const { + assert(ptr_); + return ptr_; + } + Struct* get() const { return ptr_; } + + void Swap(StructPtr* other) { + std::swap(ptr_, other->ptr_); + } + + private: + typedef Struct* StructPtr::*Testable; + + public: + operator Testable() const { return ptr_ ? &StructPtr::ptr_ : 0; } + + private: + friend class internal::StructHelper<Struct>; + void Initialize() { assert(!ptr_); ptr_ = new Struct(); } + + void Take(StructPtr* other) { + reset(); + Swap(other); + } + + Struct* ptr_; +}; + +// Designed to be used when Struct is small and copyable. +template <typename Struct> +class InlinedStructPtr { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InlinedStructPtr, RValue); + public: + typedef typename Struct::Data_ Data_; + + InlinedStructPtr() : is_null_(true) {} + ~InlinedStructPtr() {} + + InlinedStructPtr(RValue other) : is_null_(true) { Take(other.object); } + InlinedStructPtr& operator=(RValue other) { + Take(other.object); + return *this; + } + + template <typename U> + U To() const { + return TypeConverter<InlinedStructPtr, U>::ConvertTo(*this); + } + + void reset() { + is_null_ = true; + value_.~Struct(); + new (&value_) Struct(); + } + + bool is_null() const { return is_null_; } + + Struct& operator*() const { + assert(!is_null_); + return value_; + } + Struct* operator->() const { + assert(!is_null_); + return &value_; + } + Struct* get() const { return &value_; } + + void Swap(InlinedStructPtr* other) { + std::swap(value_, other->value_); + std::swap(is_null_, other->is_null_); + } + + private: + typedef Struct InlinedStructPtr::*Testable; + + public: + operator Testable() const { return is_null_ ? 0 : &InlinedStructPtr::value_; } + + private: + friend class internal::StructHelper<Struct>; + void Initialize() { is_null_ = false; } + + void Take(InlinedStructPtr* other) { + reset(); + Swap(other); + } + + mutable Struct value_; + bool is_null_; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_STRUCT_PTR_H_ diff --git a/chromium/mojo/public/cpp/bindings/sync_dispatcher.h b/chromium/mojo/public/cpp/bindings/sync_dispatcher.h new file mode 100644 index 00000000000..9f825bf8a6a --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/sync_dispatcher.h @@ -0,0 +1,47 @@ +// 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_SYNC_DISPATCHER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_SYNC_DISPATCHER_H_ + +#include "mojo/public/cpp/bindings/lib/filter_chain.h" +#include "mojo/public/cpp/bindings/lib/message_header_validator.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +class MessageReceiver; + +// Waits for one message to arrive on the message pipe, and dispatch it to the +// receiver. Returns true on success, false on failure. +// +// NOTE: The message hasn't been validated and may be malformed! +bool WaitForMessageAndDispatch(MessagePipeHandle handle, + mojo::MessageReceiver* receiver); + +template<typename Interface> class SyncDispatcher { + public: + SyncDispatcher(ScopedMessagePipeHandle message_pipe, Interface* sink) + : message_pipe_(message_pipe.Pass()) { + stub_.set_sink(sink); + + filters_.Append<internal::MessageHeaderValidator>(); + filters_.Append<typename Interface::RequestValidator_>(); + filters_.SetSink(&stub_); + } + + bool WaitAndDispatchOneMessage() { + return WaitForMessageAndDispatch(message_pipe_.get(), + filters_.GetHead()); + } + + private: + ScopedMessagePipeHandle message_pipe_; + typename Interface::Stub_ stub_; + internal::FilterChain filters_; +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_SYNC_DISPATCHER_H_ diff --git a/chromium/mojo/public/cpp/bindings/type_converter.h b/chromium/mojo/public/cpp/bindings/type_converter.h new file mode 100644 index 00000000000..0ac5f6d4760 --- /dev/null +++ b/chromium/mojo/public/cpp/bindings/type_converter.h @@ -0,0 +1,82 @@ +// 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_TYPE_CONVERTER_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_ + +namespace mojo { + +// Specialize the following class: +// template <typename T, typename U> class TypeConverter; +// to perform type conversion for Mojom-defined structs and arrays. Here, T is +// the Mojom-defined struct or array, and U is some other non-Mojom +// struct or array type. +// +// Specializations should implement the following interface: +// namespace mojo { +// template <> +// class TypeConverter<T, U> { +// public: +// static T ConvertFrom(const U& input); +// static U ConvertTo(const T& input); +// }; +// } +// +// EXAMPLE: +// +// Suppose you have the following Mojom-defined struct: +// +// module geometry { +// struct Point { +// int32 x; +// int32 y; +// }; +// } +// +// Now, imagine you wanted to write a TypeConverter specialization for +// gfx::Point. It might look like this: +// +// namespace mojo { +// template <> +// class TypeConverter<geometry::PointPtr, gfx::Point> { +// public: +// static geometry::PointPtr ConvertFrom(const gfx::Point& input) { +// geometry::PointPtr result; +// result->x = input.x(); +// result->y = input.y(); +// return result.Pass(); +// } +// static gfx::Point ConvertTo(const geometry::PointPtr& input) { +// return input ? gfx::Point(input->x, input->y) : gfx::Point(); +// } +// }; +// } +// +// With the above TypeConverter defined, it is possible to write code like this: +// +// void AcceptPoint(const geometry::PointPtr& input) { +// // With an explicit cast using the .To<> method. +// gfx::Point pt = input.To<gfx::Point>(); +// +// // With an explicit cast using the static From() method. +// geometry::PointPtr output = geometry::Point::From(pt); +// } +// +template <typename T, typename U> class TypeConverter; + +// The following specialization is useful when you are converting between +// Array<POD> and std::vector<POD>. +template <typename T> class TypeConverter<T, T> { + public: + static T ConvertFrom(const T& obj) { + return obj; + } + static T ConvertTo(const T& obj) { + return obj; + } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_TYPE_CONVERTER_H_ diff --git a/chromium/mojo/public/cpp/environment/environment.h b/chromium/mojo/public/cpp/environment/environment.h new file mode 100644 index 00000000000..48f4c26eb72 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/environment.h @@ -0,0 +1,41 @@ +// 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_ENVIRONMENT_ENVIRONMENT_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_ENVIRONMENT_H_ + +#include "mojo/public/cpp/system/macros.h" + +struct MojoAsyncWaiter; +struct MojoLogger; + +namespace mojo { + +// Other parts of the Mojo C++ APIs use the *static* methods of this class. +// +// The "standalone" implementation of this class requires that this class (in +// the lib/ subdirectory) be instantiated (and remain so) while using the Mojo +// C++ APIs. I.e., the static methods depend on things set up by the constructor +// and torn down by the destructor. +// +// Other implementations may not have this requirement. +class Environment { + public: + Environment(); + // This constructor allows the standard implementations to be overridden (set + // a parameter to null to get the standard implementation). + Environment(const MojoAsyncWaiter* default_async_waiter, + const MojoLogger* default_logger); + ~Environment(); + + static const MojoAsyncWaiter* GetDefaultAsyncWaiter(); + static const MojoLogger* GetDefaultLogger(); + + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(Environment); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_ENVIRONMENT_H_ diff --git a/chromium/mojo/public/cpp/environment/lib/DEPS b/chromium/mojo/public/cpp/environment/lib/DEPS new file mode 100644 index 00000000000..1889e1fb75f --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+mojo/public/cpp/environment", + "+mojo/public/cpp/utility", +] diff --git a/chromium/mojo/public/cpp/environment/lib/default_async_waiter.cc b/chromium/mojo/public/cpp/environment/lib/default_async_waiter.cc new file mode 100644 index 00000000000..257f1c8d797 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/default_async_waiter.cc @@ -0,0 +1,94 @@ +// 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/environment/lib/default_async_waiter.h" + +#include <assert.h> + +#include "mojo/public/c/environment/async_waiter.h" +#include "mojo/public/cpp/utility/run_loop.h" +#include "mojo/public/cpp/utility/run_loop_handler.h" + +namespace mojo { + +namespace { + +// RunLoopHandler implementation used for a request to AsyncWait(). There are +// two ways RunLoopHandlerImpl is deleted: +// . when the handle is ready (or errored). +// . when CancelWait() is invoked. +class RunLoopHandlerImpl : public RunLoopHandler { + public: + RunLoopHandlerImpl(const Handle& handle, + MojoAsyncWaitCallback callback, + void* closure) + : handle_(handle), + callback_(callback), + closure_(closure) { + } + + virtual ~RunLoopHandlerImpl() { + RunLoop::current()->RemoveHandler(handle_); + } + + // RunLoopHandler: + virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE { + NotifyCallback(MOJO_RESULT_OK); + } + + virtual void OnHandleError(const Handle& handle, + MojoResult result) MOJO_OVERRIDE { + NotifyCallback(result); + } + + private: + void NotifyCallback(MojoResult result) { + // Delete this to unregister the handle. That way if the callback + // reregisters everything is ok. + MojoAsyncWaitCallback callback = callback_; + void* closure = closure_; + delete this; + + callback(closure, result); + } + + const Handle handle_; + MojoAsyncWaitCallback callback_; + void* closure_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopHandlerImpl); +}; + +MojoAsyncWaitID AsyncWait(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline, + MojoAsyncWaitCallback callback, + void* closure) { + RunLoop* run_loop = RunLoop::current(); + assert(run_loop); + + // |run_loop_handler| is destroyed either when the handle is ready or if + // CancelWait is invoked. + RunLoopHandlerImpl* run_loop_handler = + new RunLoopHandlerImpl(Handle(handle), callback, closure); + run_loop->AddHandler(run_loop_handler, Handle(handle), signals, deadline); + return reinterpret_cast<MojoAsyncWaitID>(run_loop_handler); +} + +void CancelWait(MojoAsyncWaitID wait_id) { + delete reinterpret_cast<RunLoopHandlerImpl*>(wait_id); +} + +} // namespace + +namespace internal { + +const MojoAsyncWaiter kDefaultAsyncWaiter = { + AsyncWait, + CancelWait +}; + +} // namespace internal + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/environment/lib/default_async_waiter.h b/chromium/mojo/public/cpp/environment/lib/default_async_waiter.h new file mode 100644 index 00000000000..49ce233490c --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/default_async_waiter.h @@ -0,0 +1,18 @@ +// 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_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_ + +struct MojoAsyncWaiter; + +namespace mojo { +namespace internal { + +extern const MojoAsyncWaiter kDefaultAsyncWaiter; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_ASYNC_WAITER_H_ diff --git a/chromium/mojo/public/cpp/environment/lib/default_logger.cc b/chromium/mojo/public/cpp/environment/lib/default_logger.cc new file mode 100644 index 00000000000..af4a62866b0 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/default_logger.cc @@ -0,0 +1,71 @@ +// 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/environment/lib/default_logger.h" + +#include <stdio.h> +#include <stdlib.h> // For |abort()|. + +#include <algorithm> + +#include "mojo/public/c/environment/logger.h" + +namespace mojo { + +namespace { + +MojoLogLevel g_minimum_log_level = MOJO_LOG_LEVEL_INFO; + +const char* GetLogLevelString(MojoLogLevel log_level) { + if (log_level <= MOJO_LOG_LEVEL_VERBOSE-3) + return "VERBOSE4+"; + switch (log_level) { + case MOJO_LOG_LEVEL_VERBOSE-2: + return "VERBOSE3"; + case MOJO_LOG_LEVEL_VERBOSE-1: + return "VERBOSE2"; + case MOJO_LOG_LEVEL_VERBOSE: + return "VERBOSE1"; + case MOJO_LOG_LEVEL_INFO: + return "INFO"; + case MOJO_LOG_LEVEL_WARNING: + return "WARNING"; + case MOJO_LOG_LEVEL_ERROR: + return "ERROR"; + } + // Consider everything higher to be fatal. + return "FATAL"; +} + +void LogMessage(MojoLogLevel log_level, const char* message) { + if (log_level < g_minimum_log_level) + return; + + // TODO(vtl): Add timestamp also? + fprintf(stderr, "%s: %s\n", GetLogLevelString(log_level), message); + if (log_level >= MOJO_LOG_LEVEL_FATAL) + abort(); +} + +MojoLogLevel GetMinimumLogLevel() { + return g_minimum_log_level; +} + +void SetMinimumLogLevel(MojoLogLevel minimum_log_level) { + g_minimum_log_level = std::min(minimum_log_level, MOJO_LOG_LEVEL_FATAL); +} + +} // namespace + +namespace internal { + +const MojoLogger kDefaultLogger = { + LogMessage, + GetMinimumLogLevel, + SetMinimumLogLevel +}; + +} // namespace internal + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/environment/lib/default_logger.h b/chromium/mojo/public/cpp/environment/lib/default_logger.h new file mode 100644 index 00000000000..4db32336811 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/default_logger.h @@ -0,0 +1,18 @@ +// 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_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_ + +struct MojoLogger; + +namespace mojo { +namespace internal { + +extern const MojoLogger kDefaultLogger; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_LIB_DEFAULT_LOGGER_H_ diff --git a/chromium/mojo/public/cpp/environment/lib/environment.cc b/chromium/mojo/public/cpp/environment/lib/environment.cc new file mode 100644 index 00000000000..58e270e9ae4 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/environment.cc @@ -0,0 +1,60 @@ +// 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/environment/environment.h" + +#include <stddef.h> + +#include "mojo/public/c/environment/logger.h" +#include "mojo/public/cpp/environment/lib/default_async_waiter.h" +#include "mojo/public/cpp/environment/lib/default_logger.h" +#include "mojo/public/cpp/utility/run_loop.h" + +namespace mojo { + +namespace { + +const MojoAsyncWaiter* g_default_async_waiter = NULL; +const MojoLogger* g_default_logger = NULL; + +void Init(const MojoAsyncWaiter* default_async_waiter, + const MojoLogger* default_logger) { + g_default_async_waiter = + default_async_waiter ? default_async_waiter : + &internal::kDefaultAsyncWaiter; + g_default_logger = default_logger ? default_logger : + &internal::kDefaultLogger; + + RunLoop::SetUp(); +} + +} // namespace + +Environment::Environment() { + Init(NULL, NULL); +} + +Environment::Environment(const MojoAsyncWaiter* default_async_waiter, + const MojoLogger* default_logger) { + Init(default_async_waiter, default_logger); +} + +Environment::~Environment() { + RunLoop::TearDown(); + + // TODO(vtl): Maybe we should allow nesting, and restore previous default + // async waiters and loggers? +} + +// static +const MojoAsyncWaiter* Environment::GetDefaultAsyncWaiter() { + return g_default_async_waiter; +} + +// static +const MojoLogger* Environment::GetDefaultLogger() { + return g_default_logger; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/environment/lib/logging.cc b/chromium/mojo/public/cpp/environment/lib/logging.cc new file mode 100644 index 00000000000..990626df736 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/lib/logging.cc @@ -0,0 +1,45 @@ +// 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/environment/logging.h" + +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { +namespace internal { + +namespace { + +// Gets a pointer to the filename portion of |s|. Assumes that the filename +// follows the last slash or backslash in |s|, or is |s| if no slash or +// backslash is present. +// +// E.g., a pointer to "foo.cc" is returned for the following inputs: "foo.cc", +// "./foo.cc", ".\foo.cc", "/absolute/path/to/foo.cc", +// "relative/path/to/foo.cc", "C:\absolute\path\to\foo.cc", etc. +const char* GetFilename(const char* s) { + const char* rv = s; + while (*s) { + if (*s == '/' || *s == '\\') + rv = s + 1; + s++; + } + return rv; +} + +} // namespace + +LogMessage::LogMessage(const char* file, int line, MojoLogLevel log_level) + : log_level_(log_level) { + // Note: Don't include the log level in the message, since that's passed on. + stream_ << GetFilename(file) << '(' << line << "): "; +} + +LogMessage::~LogMessage() { + Environment::GetDefaultLogger()->LogMessage(log_level_, + stream_.str().c_str()); +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/environment/logging.h b/chromium/mojo/public/cpp/environment/logging.h new file mode 100644 index 00000000000..a3e2cef4293 --- /dev/null +++ b/chromium/mojo/public/cpp/environment/logging.h @@ -0,0 +1,87 @@ +// 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. + +// Logging macros, similar to Chromium's base/logging.h, except with |MOJO_| +// prefixes and missing some features (notably |CHECK_EQ()|, etc.). + +// TODO(vtl): It's weird that this is in the environment directory, since its +// implementation (in environment/lib) is meant to be used by any implementation +// of the environment. + +#ifndef MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_ +#define MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_ + +#include <sstream> + +#include "mojo/public/c/environment/logger.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/macros.h" + +#define MOJO_LOG_STREAM(level) \ + ::mojo::internal::LogMessage(__FILE__, __LINE__, \ + MOJO_LOG_LEVEL_ ## level).stream() + +#define MOJO_LAZY_LOG_STREAM(level, condition) \ + !(condition) ? \ + (void) 0 : \ + ::mojo::internal::VoidifyOstream() & MOJO_LOG_STREAM(level) + +#define MOJO_SHOULD_LOG(level) \ + (MOJO_LOG_LEVEL_ ## level >= \ + ::mojo::Environment::GetDefaultLogger()->GetMinimumLogLevel()) + +#define MOJO_LOG(level) \ + MOJO_LAZY_LOG_STREAM(level, MOJO_SHOULD_LOG(level)) + +#define MOJO_LOG_IF(level, condition) \ + MOJO_LAZY_LOG_STREAM(level, MOJO_SHOULD_LOG(level) && (condition)) + +#define MOJO_CHECK(condition) \ + MOJO_LAZY_LOG_STREAM(FATAL, !(condition)) \ + << "Check failed: " #condition ". " + +// Note: For non-debug builds, |MOJO_DLOG_IF()| *eliminates* (i.e., doesn't +// compile) the condition, whereas |MOJO_DCHECK()| "neuters" the condition +// (i.e., compiles, but doesn't evaluate). +#ifdef NDEBUG + +#define MOJO_DLOG(level) MOJO_LAZY_LOG_STREAM(level, false) +#define MOJO_DLOG_IF(level, condition) MOJO_LAZY_LOG_STREAM(level, false) +#define MOJO_DCHECK(condition) MOJO_LAZY_LOG_STREAM(FATAL, false && (condition)) + +#else + +#define MOJO_DLOG(level) MOJO_LOG(level) +#define MOJO_DLOG_IF(level, condition) MOJO_LOG_IF(level, condition) +#define MOJO_DCHECK(condition) MOJO_CHECK(condition) + +#endif // NDEBUG + +namespace mojo { +namespace internal { + +class LogMessage { + public: + LogMessage(const char* file, int line, MojoLogLevel log_level); + ~LogMessage(); + + std::ostream& stream() { return stream_; } + + private: + const MojoLogLevel log_level_; + std::ostringstream stream_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(LogMessage); +}; + +// Used to ignore a stream. +struct VoidifyOstream { + // Use & since it has precedence lower than << but higher than ?:. + void operator&(std::ostream&) {} +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_ENVIRONMENT_LOGGING_H_ diff --git a/chromium/mojo/public/cpp/gles2/DEPS b/chromium/mojo/public/cpp/gles2/DEPS new file mode 100644 index 00000000000..3c48be99eb8 --- /dev/null +++ b/chromium/mojo/public/cpp/gles2/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+mojo/public/c/gles2", + "+mojo/public/cpp/environment", +] diff --git a/chromium/mojo/public/cpp/gles2/gles2.h b/chromium/mojo/public/cpp/gles2/gles2.h new file mode 100644 index 00000000000..a408fc701eb --- /dev/null +++ b/chromium/mojo/public/cpp/gles2/gles2.h @@ -0,0 +1,24 @@ +// 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_GLES2_GLES2_H_ +#define MOJO_PUBLIC_CPP_GLES2_GLES2_H_ + +#include "mojo/public/c/gles2/gles2.h" +#include "mojo/public/cpp/environment/environment.h" + +namespace mojo { + +class GLES2Initializer { + public: + explicit GLES2Initializer(const MojoAsyncWaiter* async_waiter = + Environment::GetDefaultAsyncWaiter()) { + MojoGLES2Initialize(async_waiter); + } + ~GLES2Initializer() { MojoGLES2Terminate(); } +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_GLES2_GLES2_H_ diff --git a/chromium/mojo/public/cpp/system/core.h b/chromium/mojo/public/cpp/system/core.h new file mode 100644 index 00000000000..d73bb296514 --- /dev/null +++ b/chromium/mojo/public/cpp/system/core.h @@ -0,0 +1,555 @@ +// 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_SYSTEM_CORE_H_ +#define MOJO_PUBLIC_CPP_SYSTEM_CORE_H_ + +#include <assert.h> +#include <stddef.h> + +#include <limits> + +#include "mojo/public/c/system/core.h" +#include "mojo/public/c/system/system_export.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// OVERVIEW +// +// |Handle| and |...Handle|: +// +// |Handle| is a simple, copyable wrapper for the C type |MojoHandle| (which is +// just an integer). Its purpose is to increase type-safety, not provide +// lifetime management. For the same purpose, we have trivial *subclasses* of +// |Handle|, e.g., |MessagePipeHandle| and |DataPipeProducerHandle|. |Handle| +// and its subclasses impose *no* extra overhead over using |MojoHandle|s +// directly. +// +// Note that though we provide constructors for |Handle|/|...Handle| from a +// |MojoHandle|, we do not provide, e.g., a constructor for |MessagePipeHandle| +// from a |Handle|. This is for type safety: If we did, you'd then be able to +// construct a |MessagePipeHandle| from, e.g., a |DataPipeProducerHandle| (since +// it's a |Handle|). +// +// |ScopedHandleBase| and |Scoped...Handle|: +// +// |ScopedHandleBase<HandleType>| is a templated scoped wrapper, for the handle +// types above (in the same sense that a C++11 |unique_ptr<T>| is a scoped +// wrapper for a |T*|). It provides lifetime management, closing its owned +// handle on destruction. It also provides (emulated) move semantics, again +// along the lines of C++11's |unique_ptr| (and exactly like Chromium's +// |scoped_ptr|). +// +// |ScopedHandle| is just (a typedef of) a |ScopedHandleBase<Handle>|. +// Similarly, |ScopedMessagePipeHandle| is just a +// |ScopedHandleBase<MessagePipeHandle>|. Etc. Note that a +// |ScopedMessagePipeHandle| is *not* a (subclass of) |ScopedHandle|. +// +// Wrapper functions: +// +// We provide simple wrappers for the |Mojo...()| functions (in +// mojo/public/c/system/core.h -- see that file for details on individual +// functions). +// +// The general guideline is functions that imply ownership transfer of a handle +// should take (or produce) an appropriate |Scoped...Handle|, while those that +// don't take a |...Handle|. For example, |CreateMessagePipe()| has two +// |ScopedMessagePipe| "out" parameters, whereas |Wait()| and |WaitMany()| take +// |Handle| parameters. Some, have both: e.g., |DuplicatedBuffer()| takes a +// suitable (unscoped) handle (e.g., |SharedBufferHandle|) "in" parameter and +// produces a suitable scoped handle (e.g., |ScopedSharedBufferHandle| a.k.a. +// |ScopedHandleBase<SharedBufferHandle>|) as an "out" parameter. +// +// An exception are some of the |...Raw()| functions. E.g., |CloseRaw()| takes a +// |Handle|, leaving the user to discard the handle. +// +// More significantly, |WriteMessageRaw()| exposes the full API complexity of +// |MojoWriteMessage()| (but doesn't require any extra overhead). It takes a raw +// array of |Handle|s as input, and takes ownership of them (i.e., invalidates +// them) on *success* (but not on failure). There are a number of reasons for +// this. First, C++03 |std::vector|s cannot contain the move-only +// |Scoped...Handle|s. Second, |std::vector|s impose extra overhead +// (necessitating heap-allocation of the buffer). Third, |std::vector|s wouldn't +// provide the desired level of flexibility/safety: a vector of handles would +// have to be all of the same type (probably |Handle|/|ScopedHandle|). Fourth, +// it's expected to not be used directly, but instead be used by generated +// bindings. +// +// Other |...Raw()| functions expose similar rough edges, e.g., dealing with raw +// pointers (and lengths) instead of taking |std::vector|s or similar. + +// Standalone functions -------------------------------------------------------- + +inline MojoTimeTicks GetTimeTicksNow() { + return MojoGetTimeTicksNow(); +} + +// ScopedHandleBase ------------------------------------------------------------ + +// Scoper for the actual handle types defined further below. It's move-only, +// like the C++11 |unique_ptr|. +template <class HandleType> +class ScopedHandleBase { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(ScopedHandleBase, RValue) + + public: + ScopedHandleBase() {} + explicit ScopedHandleBase(HandleType handle) : handle_(handle) {} + ~ScopedHandleBase() { CloseIfNecessary(); } + + template <class CompatibleHandleType> + explicit ScopedHandleBase(ScopedHandleBase<CompatibleHandleType> other) + : handle_(other.release()) { + } + + // Move-only constructor and operator=. + ScopedHandleBase(RValue other) : handle_(other.object->release()) {} + ScopedHandleBase& operator=(RValue other) { + if (other.object != this) { + CloseIfNecessary(); + handle_ = other.object->release(); + } + return *this; + } + + const HandleType& get() const { return handle_; } + + template <typename PassedHandleType> + static ScopedHandleBase<HandleType> From( + ScopedHandleBase<PassedHandleType> other) { + MOJO_COMPILE_ASSERT( + sizeof(static_cast<PassedHandleType*>(static_cast<HandleType*>(0))), + HandleType_is_not_a_subtype_of_PassedHandleType); + return ScopedHandleBase<HandleType>( + static_cast<HandleType>(other.release().value())); + } + + void swap(ScopedHandleBase& other) { + handle_.swap(other.handle_); + } + + HandleType release() MOJO_WARN_UNUSED_RESULT { + HandleType rv; + rv.swap(handle_); + return rv; + } + + void reset(HandleType handle = HandleType()) { + CloseIfNecessary(); + handle_ = handle; + } + + bool is_valid() const { + return handle_.is_valid(); + } + + private: + void CloseIfNecessary() { + if (!handle_.is_valid()) + return; + MojoResult result MOJO_ALLOW_UNUSED = MojoClose(handle_.value()); + assert(result == MOJO_RESULT_OK); + } + + HandleType handle_; +}; + +template <typename HandleType> +inline ScopedHandleBase<HandleType> MakeScopedHandle(HandleType handle) { + return ScopedHandleBase<HandleType>(handle); +} + +// Handle ---------------------------------------------------------------------- + +const MojoHandle kInvalidHandleValue = MOJO_HANDLE_INVALID; + +// Wrapper base class for |MojoHandle|. +class Handle { + public: + Handle() : value_(kInvalidHandleValue) {} + explicit Handle(MojoHandle value) : value_(value) {} + ~Handle() {} + + void swap(Handle& other) { + MojoHandle temp = value_; + value_ = other.value_; + other.value_ = temp; + } + + bool is_valid() const { + return value_ != kInvalidHandleValue; + } + + MojoHandle value() const { return value_; } + MojoHandle* mutable_value() { return &value_; } + void set_value(MojoHandle value) { value_ = value; } + + private: + MojoHandle value_; + + // Copying and assignment allowed. +}; + +// Should have zero overhead. +MOJO_COMPILE_ASSERT(sizeof(Handle) == sizeof(MojoHandle), + bad_size_for_cpp_Handle); + +// The scoper should also impose no more overhead. +typedef ScopedHandleBase<Handle> ScopedHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedHandle) == sizeof(Handle), + bad_size_for_cpp_ScopedHandle); + +inline MojoResult Wait(const Handle& handle, + MojoHandleSignals signals, + MojoDeadline deadline) { + return MojoWait(handle.value(), signals, deadline); +} + +// |HandleVectorType| and |FlagsVectorType| should be similar enough to +// |std::vector<Handle>| and |std::vector<MojoHandleSignals>|, respectively: +// - They should have a (const) |size()| method that returns an unsigned type. +// - They must provide contiguous storage, with access via (const) reference to +// that storage provided by a (const) |operator[]()| (by reference). +template <class HandleVectorType, class FlagsVectorType> +inline MojoResult WaitMany(const HandleVectorType& handles, + const FlagsVectorType& signals, + MojoDeadline deadline) { + if (signals.size() != handles.size()) + return MOJO_RESULT_INVALID_ARGUMENT; + if (handles.size() > std::numeric_limits<uint32_t>::max()) + return MOJO_RESULT_OUT_OF_RANGE; + + if (handles.size() == 0) + return MojoWaitMany(NULL, NULL, 0, deadline); + + const Handle& first_handle = handles[0]; + const MojoHandleSignals& first_signals = signals[0]; + return MojoWaitMany( + reinterpret_cast<const MojoHandle*>(&first_handle), + reinterpret_cast<const MojoHandleSignals*>(&first_signals), + static_cast<uint32_t>(handles.size()), + deadline); +} + +// |Close()| takes ownership of the handle, since it'll invalidate it. +// Note: There's nothing to do, since the argument will be destroyed when it +// goes out of scope. +template <class HandleType> +inline void Close(ScopedHandleBase<HandleType> /*handle*/) {} + +// Most users should typically use |Close()| (above) instead. +inline MojoResult CloseRaw(Handle handle) { + return MojoClose(handle.value()); +} + +// Strict weak ordering, so that |Handle|s can be used as keys in |std::map|s, +// etc. +inline bool operator<(const Handle& a, const Handle& b) { + return a.value() < b.value(); +} + +// MessagePipeHandle ----------------------------------------------------------- + +class MessagePipeHandle : public Handle { + public: + MessagePipeHandle() {} + explicit MessagePipeHandle(MojoHandle value) : Handle(value) {} + + // Copying and assignment allowed. +}; + +MOJO_COMPILE_ASSERT(sizeof(MessagePipeHandle) == sizeof(Handle), + bad_size_for_cpp_MessagePipeHandle); + +typedef ScopedHandleBase<MessagePipeHandle> ScopedMessagePipeHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedMessagePipeHandle) == + sizeof(MessagePipeHandle), + bad_size_for_cpp_ScopedMessagePipeHandle); + +inline MojoResult CreateMessagePipe(const MojoCreateMessagePipeOptions* options, + ScopedMessagePipeHandle* message_pipe0, + ScopedMessagePipeHandle* message_pipe1) { + assert(message_pipe0); + assert(message_pipe1); + MessagePipeHandle handle0; + MessagePipeHandle handle1; + MojoResult rv = MojoCreateMessagePipe(options, + handle0.mutable_value(), + handle1.mutable_value()); + // Reset even on failure (reduces the chances that a "stale"/incorrect handle + // will be used). + message_pipe0->reset(handle0); + message_pipe1->reset(handle1); + return rv; +} + +// These "raw" versions fully expose the underlying API, but don't help with +// ownership of handles (especially when writing messages). +// TODO(vtl): Write "baked" versions. +inline MojoResult WriteMessageRaw(MessagePipeHandle message_pipe, + const void* bytes, + uint32_t num_bytes, + const MojoHandle* handles, + uint32_t num_handles, + MojoWriteMessageFlags flags) { + return MojoWriteMessage(message_pipe.value(), bytes, num_bytes, handles, + num_handles, flags); +} + +inline MojoResult ReadMessageRaw(MessagePipeHandle message_pipe, + void* bytes, + uint32_t* num_bytes, + MojoHandle* handles, + uint32_t* num_handles, + MojoReadMessageFlags flags) { + return MojoReadMessage(message_pipe.value(), bytes, num_bytes, handles, + num_handles, flags); +} + +// A wrapper class that automatically creates a message pipe and owns both +// handles. +class MessagePipe { + public: + MessagePipe(); + explicit MessagePipe(const MojoCreateMessagePipeOptions& options); + ~MessagePipe(); + + ScopedMessagePipeHandle handle0; + ScopedMessagePipeHandle handle1; +}; + +inline MessagePipe::MessagePipe() { + MojoResult result MOJO_ALLOW_UNUSED = + CreateMessagePipe(NULL, &handle0, &handle1); + assert(result == MOJO_RESULT_OK); +} + +inline MessagePipe::MessagePipe(const MojoCreateMessagePipeOptions& options) { + MojoResult result MOJO_ALLOW_UNUSED = + CreateMessagePipe(&options, &handle0, &handle1); + assert(result == MOJO_RESULT_OK); +} + +inline MessagePipe::~MessagePipe() { +} + +// DataPipeProducerHandle and DataPipeConsumerHandle --------------------------- + +class DataPipeProducerHandle : public Handle { + public: + DataPipeProducerHandle() {} + explicit DataPipeProducerHandle(MojoHandle value) : Handle(value) {} + + // Copying and assignment allowed. +}; + +MOJO_COMPILE_ASSERT(sizeof(DataPipeProducerHandle) == sizeof(Handle), + bad_size_for_cpp_DataPipeProducerHandle); + +typedef ScopedHandleBase<DataPipeProducerHandle> ScopedDataPipeProducerHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedDataPipeProducerHandle) == + sizeof(DataPipeProducerHandle), + bad_size_for_cpp_ScopedDataPipeProducerHandle); + +class DataPipeConsumerHandle : public Handle { + public: + DataPipeConsumerHandle() {} + explicit DataPipeConsumerHandle(MojoHandle value) : Handle(value) {} + + // Copying and assignment allowed. +}; + +MOJO_COMPILE_ASSERT(sizeof(DataPipeConsumerHandle) == sizeof(Handle), + bad_size_for_cpp_DataPipeConsumerHandle); + +typedef ScopedHandleBase<DataPipeConsumerHandle> ScopedDataPipeConsumerHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedDataPipeConsumerHandle) == + sizeof(DataPipeConsumerHandle), + bad_size_for_cpp_ScopedDataPipeConsumerHandle); + +inline MojoResult CreateDataPipe( + const MojoCreateDataPipeOptions* options, + ScopedDataPipeProducerHandle* data_pipe_producer, + ScopedDataPipeConsumerHandle* data_pipe_consumer) { + assert(data_pipe_producer); + assert(data_pipe_consumer); + DataPipeProducerHandle producer_handle; + DataPipeConsumerHandle consumer_handle; + MojoResult rv = MojoCreateDataPipe(options, producer_handle.mutable_value(), + consumer_handle.mutable_value()); + // Reset even on failure (reduces the chances that a "stale"/incorrect handle + // will be used). + data_pipe_producer->reset(producer_handle); + data_pipe_consumer->reset(consumer_handle); + return rv; +} + +inline MojoResult WriteDataRaw(DataPipeProducerHandle data_pipe_producer, + const void* elements, + uint32_t* num_bytes, + MojoWriteDataFlags flags) { + return MojoWriteData(data_pipe_producer.value(), elements, num_bytes, flags); +} + +inline MojoResult BeginWriteDataRaw(DataPipeProducerHandle data_pipe_producer, + void** buffer, + uint32_t* buffer_num_bytes, + MojoWriteDataFlags flags) { + return MojoBeginWriteData(data_pipe_producer.value(), buffer, + buffer_num_bytes, flags); +} + +inline MojoResult EndWriteDataRaw(DataPipeProducerHandle data_pipe_producer, + uint32_t num_bytes_written) { + return MojoEndWriteData(data_pipe_producer.value(), num_bytes_written); +} + +inline MojoResult ReadDataRaw(DataPipeConsumerHandle data_pipe_consumer, + void* elements, + uint32_t* num_bytes, + MojoReadDataFlags flags) { + return MojoReadData(data_pipe_consumer.value(), elements, num_bytes, flags); +} + +inline MojoResult BeginReadDataRaw(DataPipeConsumerHandle data_pipe_consumer, + const void** buffer, + uint32_t* buffer_num_bytes, + MojoReadDataFlags flags) { + return MojoBeginReadData(data_pipe_consumer.value(), buffer, buffer_num_bytes, + flags); +} + +inline MojoResult EndReadDataRaw(DataPipeConsumerHandle data_pipe_consumer, + uint32_t num_bytes_read) { + return MojoEndReadData(data_pipe_consumer.value(), num_bytes_read); +} + +// A wrapper class that automatically creates a data pipe and owns both handles. +// TODO(vtl): Make an even more friendly version? (Maybe templatized for a +// particular type instead of some "element"? Maybe functions that take +// vectors?) +class DataPipe { + public: + DataPipe(); + explicit DataPipe(const MojoCreateDataPipeOptions& options); + ~DataPipe(); + + ScopedDataPipeProducerHandle producer_handle; + ScopedDataPipeConsumerHandle consumer_handle; +}; + +inline DataPipe::DataPipe() { + MojoResult result MOJO_ALLOW_UNUSED = + CreateDataPipe(NULL, &producer_handle, &consumer_handle); + assert(result == MOJO_RESULT_OK); +} + +inline DataPipe::DataPipe(const MojoCreateDataPipeOptions& options) { + MojoResult result MOJO_ALLOW_UNUSED = + CreateDataPipe(&options, &producer_handle, &consumer_handle); + assert(result == MOJO_RESULT_OK); +} + +inline DataPipe::~DataPipe() { +} + +// SharedBufferHandle ---------------------------------------------------------- + +class SharedBufferHandle : public Handle { + public: + SharedBufferHandle() {} + explicit SharedBufferHandle(MojoHandle value) : Handle(value) {} + + // Copying and assignment allowed. +}; + +MOJO_COMPILE_ASSERT(sizeof(SharedBufferHandle) == sizeof(Handle), + bad_size_for_cpp_SharedBufferHandle); + +typedef ScopedHandleBase<SharedBufferHandle> ScopedSharedBufferHandle; +MOJO_COMPILE_ASSERT(sizeof(ScopedSharedBufferHandle) == + sizeof(SharedBufferHandle), + bad_size_for_cpp_ScopedSharedBufferHandle); + +inline MojoResult CreateSharedBuffer( + const MojoCreateSharedBufferOptions* options, + uint64_t num_bytes, + ScopedSharedBufferHandle* shared_buffer) { + assert(shared_buffer); + SharedBufferHandle handle; + MojoResult rv = MojoCreateSharedBuffer(options, num_bytes, + handle.mutable_value()); + // Reset even on failure (reduces the chances that a "stale"/incorrect handle + // will be used). + shared_buffer->reset(handle); + return rv; +} + +// TODO(vtl): This (and also the functions below) are templatized to allow for +// future/other buffer types. A bit "safer" would be to overload this function +// manually. (The template enforces that the in and out handles to be of the +// same type.) +template <class BufferHandleType> +inline MojoResult DuplicateBuffer( + BufferHandleType buffer, + const MojoDuplicateBufferHandleOptions* options, + ScopedHandleBase<BufferHandleType>* new_buffer) { + assert(new_buffer); + BufferHandleType handle; + MojoResult rv = MojoDuplicateBufferHandle( + buffer.value(), options, handle.mutable_value()); + // Reset even on failure (reduces the chances that a "stale"/incorrect handle + // will be used). + new_buffer->reset(handle); + return rv; +} + +template <class BufferHandleType> +inline MojoResult MapBuffer(BufferHandleType buffer, + uint64_t offset, + uint64_t num_bytes, + void** pointer, + MojoMapBufferFlags flags) { + assert(buffer.is_valid()); + return MojoMapBuffer(buffer.value(), offset, num_bytes, pointer, flags); +} + +inline MojoResult UnmapBuffer(void* pointer) { + assert(pointer); + return MojoUnmapBuffer(pointer); +} + +// A wrapper class that automatically creates a shared buffer and owns the +// handle. +class SharedBuffer { + public: + explicit SharedBuffer(uint64_t num_bytes); + SharedBuffer(uint64_t num_bytes, + const MojoCreateSharedBufferOptions& options); + ~SharedBuffer(); + + ScopedSharedBufferHandle handle; +}; + +inline SharedBuffer::SharedBuffer(uint64_t num_bytes) { + MojoResult result MOJO_ALLOW_UNUSED = + CreateSharedBuffer(NULL, num_bytes, &handle); + assert(result == MOJO_RESULT_OK); +} + +inline SharedBuffer::SharedBuffer( + uint64_t num_bytes, + const MojoCreateSharedBufferOptions& options) { + MojoResult result MOJO_ALLOW_UNUSED = + CreateSharedBuffer(&options, num_bytes, &handle); + assert(result == MOJO_RESULT_OK); +} + +inline SharedBuffer::~SharedBuffer() { +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_SYSTEM_CORE_H_ diff --git a/chromium/mojo/public/cpp/system/macros.h b/chromium/mojo/public/cpp/system/macros.h new file mode 100644 index 00000000000..ac4f3dbc84c --- /dev/null +++ b/chromium/mojo/public/cpp/system/macros.h @@ -0,0 +1,53 @@ +// 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_SYSTEM_MACROS_H_ +#define MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_ + +#include "mojo/public/c/system/macros.h" + +// Annotate a virtual method indicating it must be overriding a virtual method +// in the parent class. Use like: +// virtual void foo() OVERRIDE; +#if defined(_MSC_VER) || defined(__clang__) +#define MOJO_OVERRIDE override +#else +#define MOJO_OVERRIDE +#endif + +// A macro to disallow the copy constructor and operator= functions. +// This should be used in the private: declarations for a class. +#define MOJO_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +// Used to calculate the number of elements in an array. +// (See |arraysize()| in Chromium's base/basictypes.h for more details.) +namespace mojo { +template <typename T, size_t N> +char (&ArraySizeHelper(T (&array)[N]))[N]; +#if !defined(_MSC_VER) +template <typename T, size_t N> +char (&ArraySizeHelper(const T (&array)[N]))[N]; +#endif +} // namespace mojo +#define MOJO_ARRAYSIZE(array) (sizeof(::mojo::ArraySizeHelper(array))) + +// Used to make a type move-only in C++03. See Chromium's base/move.h for more +// details. +#define MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \ + private: \ + struct rvalue_type { \ + explicit rvalue_type(type* object) : object(object) {} \ + type* object; \ + }; \ + type(type&); \ + void operator=(type&); \ + public: \ + operator rvalue_type() { return rvalue_type(this); } \ + type Pass() { return type(rvalue_type(this)); } \ + typedef void MoveOnlyTypeForCPP03; \ + private: + +#endif // MOJO_PUBLIC_CPP_SYSTEM_MACROS_H_ diff --git a/chromium/mojo/public/cpp/test_support/DEPS b/chromium/mojo/public/cpp/test_support/DEPS new file mode 100644 index 00000000000..6dc53942e16 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/public/c/test_support", +] diff --git a/chromium/mojo/public/cpp/test_support/lib/test_support.cc b/chromium/mojo/public/cpp/test_support/lib/test_support.cc new file mode 100644 index 00000000000..55a3dcc7024 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/lib/test_support.cc @@ -0,0 +1,26 @@ +// 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/test_support/test_support.h" + +#include <stdlib.h> + +namespace mojo { +namespace test { + +std::vector<std::string> EnumerateSourceRootRelativeDirectory( + const std::string& relative_path) { + char** names = MojoTestSupportEnumerateSourceRootRelativeDirectory( + relative_path.c_str()); + std::vector<std::string> results; + for (char** ptr = names; *ptr != NULL; ++ptr) { + results.push_back(*ptr); + free(*ptr); + } + free(names); + return results; +} + +} // namespace test +} // namespace mojo diff --git a/chromium/mojo/public/cpp/test_support/lib/test_utils.cc b/chromium/mojo/public/cpp/test_support/lib/test_utils.cc new file mode 100644 index 00000000000..b47ea209020 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/lib/test_utils.cc @@ -0,0 +1,91 @@ +// 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/test_support/test_utils.h" + +#include "mojo/public/cpp/system/core.h" +#include "mojo/public/cpp/test_support/test_support.h" + +namespace mojo { +namespace test { + +bool WriteTextMessage(const MessagePipeHandle& handle, + const std::string& text) { + MojoResult rv = WriteMessageRaw(handle, + text.data(), + static_cast<uint32_t>(text.size()), + NULL, + 0, + MOJO_WRITE_MESSAGE_FLAG_NONE); + return rv == MOJO_RESULT_OK; +} + +bool ReadTextMessage(const MessagePipeHandle& handle, std::string* text) { + MojoResult rv; + bool did_wait = false; + + uint32_t num_bytes = 0, num_handles = 0; + for (;;) { + rv = ReadMessageRaw(handle, + NULL, + &num_bytes, + NULL, + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + if (rv == MOJO_RESULT_SHOULD_WAIT) { + if (did_wait) { + assert(false); // Looping endlessly!? + return false; + } + rv = Wait(handle, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE); + if (rv != MOJO_RESULT_OK) + return false; + did_wait = true; + } else { + assert(!num_handles); + break; + } + } + + text->resize(num_bytes); + rv = ReadMessageRaw(handle, + &text->at(0), + &num_bytes, + NULL, + &num_handles, + MOJO_READ_MESSAGE_FLAG_NONE); + return rv == MOJO_RESULT_OK; +} + +bool DiscardMessage(const MessagePipeHandle& handle) { + MojoResult rv = ReadMessageRaw(handle, NULL, NULL, NULL, NULL, + MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); + return rv == MOJO_RESULT_OK; +} + +void IterateAndReportPerf(const char* test_name, + PerfTestSingleIteration single_iteration, + void* closure) { + // TODO(vtl): These should be specifiable using command-line flags. + static const size_t kGranularity = 100; + static const MojoTimeTicks kPerftestTimeMicroseconds = 3 * 1000000; + + const MojoTimeTicks start_time = GetTimeTicksNow(); + MojoTimeTicks end_time; + size_t iterations = 0; + do { + for (size_t i = 0; i < kGranularity; i++) + (*single_iteration)(closure); + iterations += kGranularity; + + end_time = GetTimeTicksNow(); + } while (end_time - start_time < kPerftestTimeMicroseconds); + + MojoTestSupportLogPerfResult(test_name, + 1000000.0 * iterations / (end_time - start_time), + "iterations/second"); +} + +} // namespace test +} // namespace mojo diff --git a/chromium/mojo/public/cpp/test_support/test_support.h b/chromium/mojo/public/cpp/test_support/test_support.h new file mode 100644 index 00000000000..eb4d4be7116 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/test_support.h @@ -0,0 +1,34 @@ +// 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_TEST_SUPPORT_TEST_SUPPORT_H_ +#define MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_SUPPORT_H_ + +#include <string> +#include <vector> + +#include "mojo/public/c/test_support/test_support.h" + +namespace mojo { +namespace test { + +inline void LogPerfResult(const char* test_name, + double value, + const char* units) { + MojoTestSupportLogPerfResult(test_name, value, units); +} + +// Opens text file relative to the source root for reading. +inline FILE* OpenSourceRootRelativeFile(const std::string& relative_path) { + return MojoTestSupportOpenSourceRootRelativeFile(relative_path.c_str()); +} + +// Returns the list of regular files in a directory relative to the source root. +std::vector<std::string> EnumerateSourceRootRelativeDirectory( + const std::string& relative_path); + +} // namespace test +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_SUPPORT_H_ diff --git a/chromium/mojo/public/cpp/test_support/test_utils.h b/chromium/mojo/public/cpp/test_support/test_utils.h new file mode 100644 index 00000000000..43a3ea99821 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/test_utils.h @@ -0,0 +1,39 @@ +// 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_TEST_SUPPORT_TEST_UTILS_H_ +#define MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_UTILS_H_ + +#include <string> + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { +namespace test { + +// Writes a message to |handle| with message data |text|. Returns true on +// success. +bool WriteTextMessage(const MessagePipeHandle& handle, const std::string& text); + +// Reads a message from |handle|, putting its contents into |*text|. Returns +// true on success. (This blocks if necessary and will call |MojoReadMessage()| +// multiple times, e.g., to query the size of the message.) +bool ReadTextMessage(const MessagePipeHandle& handle, std::string* text); + +// Discards a message from |handle|. Returns true on success. (This does not +// block. It will fail if no message is available to discard.) +bool DiscardMessage(const MessagePipeHandle& handle); + +// Run |single_iteration| an appropriate number of times and report its +// performance appropriately. (This actually runs |single_iteration| for a fixed +// amount of time and reports the number of iterations per unit time.) +typedef void (*PerfTestSingleIteration)(void* closure); +void IterateAndReportPerf(const char* test_name, + PerfTestSingleIteration single_iteration, + void* closure); + +} // namespace test +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_TEST_SUPPORT_TEST_UTILS_H_ diff --git a/chromium/mojo/public/cpp/utility/lib/mutex.cc b/chromium/mojo/public/cpp/utility/lib/mutex.cc new file mode 100644 index 00000000000..23370e1c023 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/mutex.cc @@ -0,0 +1,52 @@ +// 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/utility/mutex.h" + +#include <assert.h> +#include <errno.h> + +namespace mojo { + +// Release builds have inlined (non-error-checking) definitions in the header. +#if !defined(NDEBUG) +Mutex::Mutex() { + pthread_mutexattr_t mutexattr; + int rv = pthread_mutexattr_init(&mutexattr); + assert(rv == 0); + rv = pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK); + assert(rv == 0); + rv = pthread_mutex_init(&mutex_, &mutexattr); + assert(rv == 0); + rv = pthread_mutexattr_destroy(&mutexattr); + assert(rv == 0); +} + +Mutex::~Mutex() { + int rv = pthread_mutex_destroy(&mutex_); + assert(rv == 0); +} + +void Mutex::Lock() { + int rv = pthread_mutex_lock(&mutex_); + assert(rv == 0); +} + +void Mutex::Unlock() { + int rv = pthread_mutex_unlock(&mutex_); + assert(rv == 0); +} + +bool Mutex::TryLock() { + int rv = pthread_mutex_trylock(&mutex_); + assert(rv == 0 || rv == EBUSY); + return rv == 0; +} + +void Mutex::AssertHeld() { + assert(pthread_mutex_lock(&mutex_) == EDEADLK); +} +#endif // !defined(NDEBUG) + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/lib/run_loop.cc b/chromium/mojo/public/cpp/utility/lib/run_loop.cc new file mode 100644 index 00000000000..f523eaeaead --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/run_loop.cc @@ -0,0 +1,221 @@ +// 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/utility/run_loop.h" + +#include <assert.h> + +#include <algorithm> +#include <vector> + +#include "mojo/public/cpp/utility/lib/thread_local.h" +#include "mojo/public/cpp/utility/run_loop_handler.h" + +namespace mojo { +namespace { + +internal::ThreadLocalPointer<RunLoop> current_run_loop; + +const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0); + +} // namespace + +// State needed for one iteration of WaitMany(). +struct RunLoop::WaitState { + WaitState() : deadline(MOJO_DEADLINE_INDEFINITE) {} + + std::vector<Handle> handles; + std::vector<MojoHandleSignals> handle_signals; + MojoDeadline deadline; +}; + +struct RunLoop::RunState { + RunState() : should_quit(false) {} + + bool should_quit; +}; + +RunLoop::RunLoop() : run_state_(NULL), next_handler_id_(0) { + assert(!current()); + current_run_loop.Set(this); +} + +RunLoop::~RunLoop() { + assert(current() == this); + current_run_loop.Set(NULL); +} + +// static +void RunLoop::SetUp() { + current_run_loop.Allocate(); +} + +// static +void RunLoop::TearDown() { + assert(!current()); + current_run_loop.Free(); +} + +// static +RunLoop* RunLoop::current() { + return current_run_loop.Get(); +} + +void RunLoop::AddHandler(RunLoopHandler* handler, + const Handle& handle, + MojoHandleSignals handle_signals, + MojoDeadline deadline) { + assert(current() == this); + assert(handler); + assert(handle.is_valid()); + // Assume it's an error if someone tries to reregister an existing handle. + assert(0u == handler_data_.count(handle)); + HandlerData handler_data; + handler_data.handler = handler; + handler_data.handle_signals = handle_signals; + handler_data.deadline = (deadline == MOJO_DEADLINE_INDEFINITE) ? + kInvalidTimeTicks : + GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline); + handler_data.id = next_handler_id_++; + handler_data_[handle] = handler_data; +} + +void RunLoop::RemoveHandler(const Handle& handle) { + assert(current() == this); + handler_data_.erase(handle); +} + +bool RunLoop::HasHandler(const Handle& handle) const { + return handler_data_.find(handle) != handler_data_.end(); +} + +void RunLoop::Run() { + assert(current() == this); + RunState* old_state = run_state_; + RunState run_state; + run_state_ = &run_state; + while (!run_state.should_quit) + Wait(false); + run_state_ = old_state; +} + +void RunLoop::RunUntilIdle() { + assert(current() == this); + RunState* old_state = run_state_; + RunState run_state; + run_state_ = &run_state; + while (!run_state.should_quit) { + if (!Wait(true)) + break; + } + run_state_ = old_state; +} + +void RunLoop::Quit() { + assert(current() == this); + if (run_state_) + run_state_->should_quit = true; +} + +bool RunLoop::Wait(bool non_blocking) { + const WaitState wait_state = GetWaitState(non_blocking); + if (wait_state.handles.empty()) { + Quit(); + return false; + } + + const MojoResult result = WaitMany(wait_state.handles, + wait_state.handle_signals, + wait_state.deadline); + if (result >= 0) { + const size_t index = static_cast<size_t>(result); + assert(handler_data_.find(wait_state.handles[index]) != + handler_data_.end()); + handler_data_[wait_state.handles[index]].handler->OnHandleReady( + wait_state.handles[index]); + return true; + } + + switch (result) { + case MOJO_RESULT_INVALID_ARGUMENT: + case MOJO_RESULT_FAILED_PRECONDITION: + return RemoveFirstInvalidHandle(wait_state); + case MOJO_RESULT_DEADLINE_EXCEEDED: + return NotifyDeadlineExceeded(); + } + + assert(false); + return false; +} + +bool RunLoop::NotifyDeadlineExceeded() { + bool notified = false; + + // Make a copy in case someone tries to add/remove new handlers as part of + // notifying. + const HandleToHandlerData cloned_handlers(handler_data_); + const MojoTimeTicks now(GetTimeTicksNow()); + for (HandleToHandlerData::const_iterator i = cloned_handlers.begin(); + i != cloned_handlers.end(); ++i) { + // Since we're iterating over a clone of the handlers, verify the handler is + // still valid before notifying. + if (i->second.deadline != kInvalidTimeTicks && + i->second.deadline < now && + handler_data_.find(i->first) != handler_data_.end() && + handler_data_[i->first].id == i->second.id) { + handler_data_.erase(i->first); + i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED); + notified = true; + } + } + + return notified; +} + +bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) { + for (size_t i = 0; i < wait_state.handles.size(); ++i) { + const MojoResult result = + mojo::Wait(wait_state.handles[i], wait_state.handle_signals[i], + static_cast<MojoDeadline>(0)); + if (result == MOJO_RESULT_INVALID_ARGUMENT || + result == MOJO_RESULT_FAILED_PRECONDITION) { + // Remove the handle first, this way if OnHandleError() tries to remove + // the handle our iterator isn't invalidated. + assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end()); + RunLoopHandler* handler = + handler_data_[wait_state.handles[i]].handler; + handler_data_.erase(wait_state.handles[i]); + handler->OnHandleError(wait_state.handles[i], result); + return true; + } + assert(MOJO_RESULT_DEADLINE_EXCEEDED == result); + } + return false; +} + +RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const { + WaitState wait_state; + MojoTimeTicks min_time = kInvalidTimeTicks; + for (HandleToHandlerData::const_iterator i = handler_data_.begin(); + i != handler_data_.end(); ++i) { + wait_state.handles.push_back(i->first); + wait_state.handle_signals.push_back(i->second.handle_signals); + if (!non_blocking && i->second.deadline != kInvalidTimeTicks && + (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) { + min_time = i->second.deadline; + } + } + if (non_blocking) { + wait_state.deadline = static_cast<MojoDeadline>(0); + } else if (min_time != kInvalidTimeTicks) { + const MojoTimeTicks now = GetTimeTicksNow(); + if (min_time < now) + wait_state.deadline = static_cast<MojoDeadline>(0); + else + wait_state.deadline = static_cast<MojoDeadline>(min_time - now); + } + return wait_state; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/lib/thread.cc b/chromium/mojo/public/cpp/utility/lib/thread.cc new file mode 100644 index 00000000000..da33497df42 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/thread.cc @@ -0,0 +1,69 @@ +// 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/utility/thread.h" + +#include <assert.h> + +namespace mojo { + +Thread::Thread() + : options_(), + thread_(), + started_(false), + joined_(false) { +} + +Thread::Thread(const Options& options) + : options_(options), + thread_(), + started_(false), + joined_(false) { +} + +Thread::~Thread() { + // If it was started, it must have been joined. + assert(!started_ || joined_); +} + +void Thread::Start() { + assert(!started_); + assert(!joined_); + + pthread_attr_t attr; + int rv MOJO_ALLOW_UNUSED = pthread_attr_init(&attr); + assert(rv == 0); + + // Non-default stack size? + if (options_.stack_size() != 0) { + rv = pthread_attr_setstacksize(&attr, options_.stack_size()); + assert(rv == 0); + } + + started_ = true; + rv = pthread_create(&thread_, &attr, &ThreadRunTrampoline, this); + assert(rv == 0); + + rv = pthread_attr_destroy(&attr); + assert(rv == 0); +} + +void Thread::Join() { + // Must have been started but not yet joined. + assert(started_); + assert(!joined_); + + joined_ = true; + int rv MOJO_ALLOW_UNUSED = pthread_join(thread_, NULL); + assert(rv == 0); +} + +// static +void* Thread::ThreadRunTrampoline(void* arg) { + Thread* self = static_cast<Thread*>(arg); + self->Run(); + return NULL; +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/lib/thread_local.h b/chromium/mojo/public/cpp/utility/lib/thread_local.h new file mode 100644 index 00000000000..4c3625d00d8 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/thread_local.h @@ -0,0 +1,61 @@ +// 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_UTILITY_LIB_THREAD_LOCAL_H_ +#define MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_ + +#ifndef _WIN32 +#include <pthread.h> +#endif + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +// Helper functions that abstract the cross-platform APIs. +struct ThreadLocalPlatform { +#ifdef _WIN32 + typedef unsigned long SlotType; +#else + typedef pthread_key_t SlotType; +#endif + + static void AllocateSlot(SlotType* slot); + static void FreeSlot(SlotType slot); + static void* GetValueFromSlot(SlotType slot); + static void SetValueInSlot(SlotType slot, void* value); +}; + +// This class is intended to be statically allocated. +template <typename P> +class ThreadLocalPointer { + public: + ThreadLocalPointer() : slot_() { + } + + void Allocate() { + ThreadLocalPlatform::AllocateSlot(&slot_); + } + + void Free() { + ThreadLocalPlatform::FreeSlot(slot_); + } + + P* Get() { + return static_cast<P*>(ThreadLocalPlatform::GetValueFromSlot(slot_)); + } + + void Set(P* value) { + ThreadLocalPlatform::SetValueInSlot(slot_, value); + } + + private: + ThreadLocalPlatform::SlotType slot_; +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_ diff --git a/chromium/mojo/public/cpp/utility/lib/thread_local_posix.cc b/chromium/mojo/public/cpp/utility/lib/thread_local_posix.cc new file mode 100644 index 00000000000..b33dfc61297 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/thread_local_posix.cc @@ -0,0 +1,39 @@ +// 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/utility/lib/thread_local.h" + +#include <assert.h> + +namespace mojo { +namespace internal { + +// static +void ThreadLocalPlatform::AllocateSlot(SlotType* slot) { + if (pthread_key_create(slot, NULL) != 0) { + assert(false); + } +} + +// static +void ThreadLocalPlatform::FreeSlot(SlotType slot) { + if (pthread_key_delete(slot) != 0) { + assert(false); + } +} + +// static +void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) { + return pthread_getspecific(slot); +} + +// static +void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) { + if (pthread_setspecific(slot, value) != 0) { + assert(false); + } +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/lib/thread_local_win.cc b/chromium/mojo/public/cpp/utility/lib/thread_local_win.cc new file mode 100644 index 00000000000..98841f7273a --- /dev/null +++ b/chromium/mojo/public/cpp/utility/lib/thread_local_win.cc @@ -0,0 +1,39 @@ +// 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/utility/lib/thread_local.h" + +#include <assert.h> +#include <windows.h> + +namespace mojo { +namespace internal { + +// static +void ThreadLocalPlatform::AllocateSlot(SlotType* slot) { + *slot = TlsAlloc(); + assert(*slot != TLS_OUT_OF_INDEXES); +} + +// static +void ThreadLocalPlatform::FreeSlot(SlotType slot) { + if (!TlsFree(slot)) { + assert(false); + } +} + +// static +void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) { + return TlsGetValue(slot); +} + +// static +void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) { + if (!TlsSetValue(slot, value)) { + assert(false); + } +} + +} // namespace internal +} // namespace mojo diff --git a/chromium/mojo/public/cpp/utility/mutex.h b/chromium/mojo/public/cpp/utility/mutex.h new file mode 100644 index 00000000000..35611c2ba9a --- /dev/null +++ b/chromium/mojo/public/cpp/utility/mutex.h @@ -0,0 +1,70 @@ +// 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_UTILITY_MUTEX_H_ +#define MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_ + +#ifdef _WIN32 +#error "Not implemented: See crbug.com/342893." +#endif + +#include <pthread.h> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +#ifdef NDEBUG +// Note: Make a C++ constant for |PTHREAD_MUTEX_INITIALIZER|. (We can't directly +// use the C macro in an initializer list, since it might expand to |{ ... }|.) +namespace internal { +const pthread_mutex_t kPthreadMutexInitializer = PTHREAD_MUTEX_INITIALIZER; +} +#endif + +class Mutex { + public: +#ifdef NDEBUG + Mutex() : mutex_(internal::kPthreadMutexInitializer) {} + ~Mutex() { pthread_mutex_destroy(&mutex_); } + + void Lock() { pthread_mutex_lock(&mutex_); } + void Unlock() { pthread_mutex_unlock(&mutex_); } + bool TryLock() { return pthread_mutex_trylock(&mutex_) == 0; } + + void AssertHeld() {} +#else + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + bool TryLock(); + + void AssertHeld(); +#endif + + private: + pthread_mutex_t mutex_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Mutex); +}; + +class MutexLock { + public: + explicit MutexLock(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); } + ~MutexLock() { mutex_->Unlock(); } + + private: + Mutex* const mutex_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(MutexLock); +}; + +// Catch bug where variable name is omitted (e.g., |MutexLock (&mu)|). +#define MutexLock(x) MOJO_COMPILE_ASSERT(0, mutex_lock_missing_variable_name); + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_ diff --git a/chromium/mojo/public/cpp/utility/run_loop.h b/chromium/mojo/public/cpp/utility/run_loop.h new file mode 100644 index 00000000000..74f870abc57 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/run_loop.h @@ -0,0 +1,108 @@ +// 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_UTILITY_RUN_LOOP_H_ +#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_ + +#include <map> + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +class RunLoopHandler; + +class RunLoop { + public: + RunLoop(); + ~RunLoop(); + + // Sets up state needed for RunLoop. This must be invoked before creating a + // RunLoop. + static void SetUp(); + + // Cleans state created by Setup(). + static void TearDown(); + + // Returns the RunLoop for the current thread. Returns NULL if not yet + // created. + static RunLoop* current(); + + // Registers a RunLoopHandler for the specified handle. Only one handler can + // be registered for a specified handle. + void AddHandler(RunLoopHandler* handler, + const Handle& handle, + MojoHandleSignals handle_signals, + MojoDeadline deadline); + void RemoveHandler(const Handle& handle); + bool HasHandler(const Handle& handle) const; + + // Runs the loop servicing handles as they are ready. This returns when Quit() + // is invoked, or there no more handles. + void Run(); + + // Runs the loop servicing any handles that are ready. Does not wait for + // handles to become ready before returning. Returns early if Quit() is + // invoked. + void RunUntilIdle(); + + void Quit(); + + private: + struct RunState; + struct WaitState; + + // Contains the data needed to track a request to AddHandler(). + struct HandlerData { + HandlerData() + : handler(NULL), + handle_signals(MOJO_HANDLE_SIGNAL_NONE), + deadline(0), + id(0) {} + + RunLoopHandler* handler; + MojoHandleSignals handle_signals; + MojoTimeTicks deadline; + // See description of |RunLoop::next_handler_id_| for details. + int id; + }; + + typedef std::map<Handle, HandlerData> HandleToHandlerData; + + // Waits for a handle to be ready. Returns after servicing at least one + // handle (or there are no more handles) unless |non_blocking| is true, + // in which case it will also return if servicing at least one handle + // would require blocking. Returns true if a RunLoopHandler was notified. + bool Wait(bool non_blocking); + + // Notifies any handlers whose deadline has expired. Returns true if a + // RunLoopHandler was notified. + bool NotifyDeadlineExceeded(); + + // Removes the first invalid handle. This is called if MojoWaitMany() finds an + // invalid handle. Returns true if a RunLoopHandler was notified. + bool RemoveFirstInvalidHandle(const WaitState& wait_state); + + // Returns the state needed to pass to WaitMany(). + WaitState GetWaitState(bool non_blocking) const; + + HandleToHandlerData handler_data_; + + // If non-NULL we're running (inside Run()). Member references a value on the + // stack. + RunState* run_state_; + + // An ever increasing value assigned to each HandlerData::id. Used to detect + // uniqueness while notifying. That is, while notifying expired timers we copy + // |handler_data_| and only notify handlers whose id match. If the id does not + // match it means the handler was removed then added so that we shouldn't + // notify it. + int next_handler_id_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoop); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_ diff --git a/chromium/mojo/public/cpp/utility/run_loop_handler.h b/chromium/mojo/public/cpp/utility/run_loop_handler.h new file mode 100644 index 00000000000..69838d5e57c --- /dev/null +++ b/chromium/mojo/public/cpp/utility/run_loop_handler.h @@ -0,0 +1,25 @@ +// 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_UTILITY_RUN_LOOP_HANDLER_H_ +#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_ + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +// Used by RunLoop to notify when a handle is either ready or has become +// invalid. +class RunLoopHandler { + public: + virtual void OnHandleReady(const Handle& handle) = 0; + virtual void OnHandleError(const Handle& handle, MojoResult result) = 0; + + protected: + virtual ~RunLoopHandler() {} +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_ diff --git a/chromium/mojo/public/cpp/utility/thread.h b/chromium/mojo/public/cpp/utility/thread.h new file mode 100644 index 00000000000..b7d10ee7037 --- /dev/null +++ b/chromium/mojo/public/cpp/utility/thread.h @@ -0,0 +1,62 @@ +// 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_UTILITY_THREAD_H_ +#define MOJO_PUBLIC_CPP_UTILITY_THREAD_H_ + +#ifdef _WIN32 +#error "Not implemented: See crbug.com/342893." +#endif + +#include <pthread.h> +#include <stddef.h> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// This class is thread-friendly, not thread-safe (e.g., you mustn't call +// |Join()| from multiple threads and/or simultaneously try to destroy the +// object). +class Thread { + public: + // TODO(vtl): Support non-joinable? priority? + class Options { + public: + Options() : stack_size_(0) {} + + // A stack size of 0 means the default. + size_t stack_size() const { return stack_size_; } + void set_stack_size(size_t stack_size) { stack_size_ = stack_size; } + + private: + size_t stack_size_; + + // Copy and assign allowed. + }; + + // TODO(vtl): Add name or name prefix? + Thread(); + explicit Thread(const Options& options); + virtual ~Thread(); + + void Start(); + void Join(); + + virtual void Run() = 0; + + private: + static void* ThreadRunTrampoline(void* arg); + + const Options options_; + pthread_t thread_; + bool started_; + bool joined_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Thread); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_UTILITY_THREAD_H_ |