diff options
Diffstat (limited to 'mojo/public/cpp')
24 files changed, 739 insertions, 505 deletions
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn index 66b8733..9753c73 100644 --- a/mojo/public/cpp/bindings/BUILD.gn +++ b/mojo/public/cpp/bindings/BUILD.gn @@ -9,10 +9,10 @@ source_set("bindings") { "buffer.h", "callback.h", "error_handler.h", - "interface.h", + "interface_ptr.h", "message.h", + "no_interface.h", "passable.h", - "remote_ptr.h", "sync_dispatcher.h", "type_converter.h", "lib/array.cc", @@ -27,13 +27,13 @@ source_set("bindings") { "lib/connector.h", "lib/fixed_buffer.cc", "lib/fixed_buffer.h", - "lib/interface.cc", "lib/message.cc", "lib/message_builder.cc", "lib/message_builder.h", "lib/message_internal.h", "lib/message_queue.cc", "lib/message_queue.h", + "lib/no_interface.cc", "lib/router.cc", "lib/router.h", "lib/scratch_buffer.cc", diff --git a/mojo/public/cpp/bindings/error_handler.h b/mojo/public/cpp/bindings/error_handler.h index 25c0d65..a6f0a4a 100644 --- a/mojo/public/cpp/bindings/error_handler.h +++ b/mojo/public/cpp/bindings/error_handler.h @@ -7,10 +7,20 @@ namespace mojo { +// This interface is used to report connection errors. class ErrorHandler { public: virtual ~ErrorHandler() {} - virtual void OnError() = 0; + virtual void OnConnectionError() = 0; +}; + +// Used when you'd like to extend a base class with the same method signature +// as ErrorHandler. +template <typename Base> +class WithErrorHandler : public Base { + public: + virtual ~WithErrorHandler() {} + virtual void OnConnectionError() = 0; }; } // namespace mojo diff --git a/mojo/public/cpp/bindings/interface.h b/mojo/public/cpp/bindings/interface.h deleted file mode 100644 index bba8fef..0000000 --- a/mojo/public/cpp/bindings/interface.h +++ /dev/null @@ -1,92 +0,0 @@ -// 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_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_H_ - -#include <assert.h> - -#include "mojo/public/cpp/bindings/message.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 NoInterface; - -class NoInterfaceStub : public MessageReceiver { - public: - NoInterfaceStub(NoInterface* unused) {} - virtual bool Accept(Message* message) MOJO_OVERRIDE; - virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) - MOJO_OVERRIDE; -}; - -class NoInterface { - public: - typedef NoInterfaceStub _Stub; - typedef NoInterface _Peer; -}; - - -// AnyInterface is for use in cases where any interface would do (e.g., see the -// Shell::Connect method). - -typedef NoInterface AnyInterface; - - -// InterfaceHandle<S> - -template <typename S> -class InterfaceHandle : public MessagePipeHandle { - public: - InterfaceHandle() {} - explicit InterfaceHandle(MojoHandle value) : MessagePipeHandle(value) {} -}; - - -// Interface<S> - -template <typename S> -struct Interface { - typedef InterfaceHandle<S> Handle; - typedef ScopedHandleBase<InterfaceHandle<S> > ScopedHandle; -}; - -template <> -struct Interface<mojo::NoInterface> { - typedef MessagePipeHandle Handle; - typedef ScopedMessagePipeHandle ScopedHandle; -}; - - -// InterfacePipe<S,P> is used to construct a MessagePipe with typed interfaces -// on either end. - -template <typename S, typename P = typename S::_Peer> -class InterfacePipe { - public: - InterfacePipe() { - typename Interface<S>::Handle h0; - typename Interface<P>::Handle h1; - MojoResult result MOJO_ALLOW_UNUSED = - MojoCreateMessagePipe(h0.mutable_value(), h1.mutable_value()); - assert(result == MOJO_RESULT_OK); - handle_to_self.reset(h0); - handle_to_peer.reset(h1); - } - - typename Interface<S>::ScopedHandle handle_to_self; - typename Interface<P>::ScopedHandle handle_to_peer; -}; - -// TODO(darin): Once we have the ability to use C++11 features, consider -// defining a template alias for ScopedInterfaceHandle<S>. - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_H_ diff --git a/mojo/public/cpp/bindings/interface_impl.h b/mojo/public/cpp/bindings/interface_impl.h new file mode 100644 index 0000000..ec6bc91 --- /dev/null +++ b/mojo/public/cpp/bindings/interface_impl.h @@ -0,0 +1,79 @@ +// 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/lib/interface_impl_internal.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. +// +// NOTE: A base class of WithErrorHandler<Interface> is used to avoid multiple +// inheritance. This base class inserts the signature of ErrorHandler into the +// inheritance chain. +template <typename Interface> +class InterfaceImpl : public WithErrorHandler<Interface> { + public: + InterfaceImpl() : internal_state_(this) {} + virtual ~InterfaceImpl() {} + + // Subclasses must handle connection errors. + virtual void OnConnectionError() = 0; + + // 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 will receive a SetClient call, providing it +// with a proxy to the client on the other end of the pipe. +template <typename Impl> +Impl* BindToPipe(Impl* instance, + ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = 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 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* BindToProxy(Impl* instance, + InterfacePtr<Interface>* ptr, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + instance->internal_state()->BindProxy(ptr, waiter); + return instance; +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h new file mode 100644 index 0000000..91bd6ba --- /dev/null +++ b/mojo/public/cpp/bindings/interface_ptr.h @@ -0,0 +1,116 @@ +// 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/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) { + other.object->internal_state_.Swap(&internal_state_); + } + InterfacePtr& operator=(RValue other) { + other.object->internal_state_.Swap(&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, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + reset(); + internal_state_.ConfigureProxy(handle.Pass(), waiter); + } + + // 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 ResetAndReturnMessagePipe() { + State state; + internal_state_.Swap(&state); + return state.router() ? + state.router()->ReleaseMessagePipe() : 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 SetClient on the returned Interface to set an instance +// of Interface::Client. +template <typename Interface> +InterfacePtr<Interface> MakeProxy( + ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = 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/mojo/public/cpp/bindings/lib/array_internal.h b/mojo/public/cpp/bindings/lib/array_internal.h index 4ecad35..865bf1c 100644 --- a/mojo/public/cpp/bindings/lib/array_internal.h +++ b/mojo/public/cpp/bindings/lib/array_internal.h @@ -8,7 +8,6 @@ #include <new> #include "mojo/public/cpp/bindings/buffer.h" -#include "mojo/public/cpp/bindings/interface.h" #include "mojo/public/cpp/bindings/lib/bindings_internal.h" #include "mojo/public/cpp/bindings/lib/bindings_serialization.h" #include "mojo/public/cpp/bindings/passable.h" diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc index aa6c45e..d9ce9d1 100644 --- a/mojo/public/cpp/bindings/lib/connector.cc +++ b/mojo/public/cpp/bindings/lib/connector.cc @@ -38,7 +38,17 @@ void Connector::CloseMessagePipe() { Close(message_pipe_.Pass()); } +ScopedMessagePipeHandle Connector::ReleaseMessagePipe() { + if (async_wait_id_) { + waiter_->CancelWait(waiter_, 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; @@ -99,7 +109,7 @@ void Connector::OnHandleReady(MojoResult result) { } if (error_ && error_handler_) - error_handler_->OnError(); + error_handler_->OnConnectionError(); } void Connector::WaitToReadMore() { diff --git a/mojo/public/cpp/bindings/lib/connector.h b/mojo/public/cpp/bindings/lib/connector.h index f32a170..6e9c1b9 100644 --- a/mojo/public/cpp/bindings/lib/connector.h +++ b/mojo/public/cpp/bindings/lib/connector.h @@ -53,9 +53,14 @@ class Connector : public MessageReceiver { // waiting to read from the pipe. bool encountered_error() const { return error_; } - // Closes the pipe, triggering the error state. + // 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 ReleaseMessagePipe(); + // MessageReceiver implementation: virtual bool Accept(Message* message) MOJO_OVERRIDE; virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) diff --git a/mojo/public/cpp/bindings/lib/interface_impl_internal.h b/mojo/public/cpp/bindings/lib/interface_impl_internal.h new file mode 100644 index 0000000..50fe566 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/interface_impl_internal.h @@ -0,0 +1,72 @@ +// 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/system/macros.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfaceImplState : public ErrorHandler { + public: + explicit InterfaceImplState(WithErrorHandler<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, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass(), waiter); + Bind(pipe.handle1.Pass(), waiter); + } + + void Bind(ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter) { + assert(!router_); + + router_ = new Router(handle.Pass(), waiter); + router_->set_incoming_receiver(&stub_); + router_->set_error_handler(this); + + proxy_ = new typename Interface::Client_::Proxy_(router_); + + stub_.sink()->SetClient(proxy_); + } + + Router* router() { return router_; } + + private: + virtual void OnConnectionError() MOJO_OVERRIDE { + static_cast<WithErrorHandler<Interface>*>(stub_.sink())-> + OnConnectionError(); + } + + internal::Router* router_; + typename Interface::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/mojo/public/cpp/bindings/lib/interface_ptr_internal.h b/mojo/public/cpp/bindings/lib/interface_ptr_internal.h new file mode 100644 index 0000000..041a31c --- /dev/null +++ b/mojo/public/cpp/bindings/lib/interface_ptr_internal.h @@ -0,0 +1,108 @@ +// 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 <stdio.h> + +#include "mojo/public/cpp/bindings/lib/router.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfacePtrState { + public: + InterfacePtrState() : instance_(NULL), client_(NULL), router_(NULL) {} + + ~InterfacePtrState() { + // Destruction order matters here. We delete |instance_| 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 instance_; + delete router_; + delete client_; + } + + Interface* instance() const { return instance_; } + void set_instance(Interface* instance) { instance_ = instance; } + + Router* router() const { return router_; } + + bool is_configured_as_proxy() const { + // This question only makes sense if we have a bound pipe. + return router_ && !client_; + } + + void Swap(InterfacePtrState* other) { + std::swap(other->instance_, instance_); + std::swap(other->client_, client_); + std::swap(other->router_, router_); + } + + void ConfigureProxy(ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + assert(!instance_); + assert(!router_); + + router_ = new Router(handle.Pass(), waiter); + ProxyWithStub* proxy = new ProxyWithStub(router_); + router_->set_incoming_receiver(&proxy->stub); + + instance_ = proxy; + } + + void ConfigureStub(ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + assert(instance_); // Should have already been set! + assert(!router_); + + // Stub for binding to state_.instance + // Proxy for communicating to the client on the other end of the pipe. + + router_ = new Router(handle.Pass(), waiter); + ClientProxyWithStub* proxy = new ClientProxyWithStub(router_); + proxy->stub.set_sink(instance_); + router_->set_incoming_receiver(&proxy->stub); + + instance_->SetClient(proxy); + client_ = proxy; + } + + private: + class ProxyWithStub : public Interface::Proxy_ { + public: + explicit ProxyWithStub(MessageReceiver* receiver) + : Interface::Proxy_(receiver) { + } + virtual void SetClient(typename Interface::Client_* client) MOJO_OVERRIDE { + stub.set_sink(client); + } + typename Interface::Client_::Stub_ stub; + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyWithStub); + }; + + class ClientProxyWithStub : public Interface::Client_::Proxy_ { + public: + explicit ClientProxyWithStub(MessageReceiver* receiver) + : Interface::Client_::Proxy_(receiver) { + } + typename Interface::Stub_ stub; + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(ClientProxyWithStub); + }; + + Interface* instance_; + typename Interface::Client_* client_; + 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/mojo/public/cpp/bindings/lib/interface.cc b/mojo/public/cpp/bindings/lib/no_interface.cc index 3b552be..7ce223a 100644 --- a/mojo/public/cpp/bindings/lib/interface.cc +++ b/mojo/public/cpp/bindings/lib/no_interface.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "mojo/public/cpp/bindings/interface.h" +#include "mojo/public/cpp/bindings/no_interface.h" namespace mojo { diff --git a/mojo/public/cpp/bindings/lib/router.h b/mojo/public/cpp/bindings/lib/router.h index 08c184e..220af7d 100644 --- a/mojo/public/cpp/bindings/lib/router.h +++ b/mojo/public/cpp/bindings/lib/router.h @@ -43,6 +43,14 @@ class Router : public MessageReceiver { // waiting to read from the pipe. bool encountered_error() const { return connector_.encountered_error(); } + void CloseMessagePipe() { + connector_.CloseMessagePipe(); + } + + ScopedMessagePipeHandle ReleaseMessagePipe() { + return connector_.ReleaseMessagePipe(); + } + // MessageReceiver implementation: virtual bool Accept(Message* message) MOJO_OVERRIDE; virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) diff --git a/mojo/public/cpp/bindings/no_interface.h b/mojo/public/cpp/bindings/no_interface.h new file mode 100644 index 0000000..02682d4 --- /dev/null +++ b/mojo/public/cpp/bindings/no_interface.h @@ -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. + +#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/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: + typedef NoInterfaceProxy Proxy_; + typedef NoInterfaceStub Stub_; + typedef NoInterface Client_; + virtual ~NoInterface() {} + virtual void SetClient(NoInterface* client) {} +}; + +class NoInterfaceProxy : public NoInterface { + public: + explicit NoInterfaceProxy(MessageReceiver* receiver) {} +}; + +class NoInterfaceStub : public MessageReceiver { + public: + NoInterfaceStub() {} + void set_sink(NoInterface* sink) {} + 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/mojo/public/cpp/bindings/remote_ptr.h b/mojo/public/cpp/bindings/remote_ptr.h deleted file mode 100644 index e1b9a5b..0000000 --- a/mojo/public/cpp/bindings/remote_ptr.h +++ /dev/null @@ -1,161 +0,0 @@ -// 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_REMOTE_PTR_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_REMOTE_PTR_H_ - -#include <assert.h> - -#include "mojo/public/cpp/bindings/interface.h" -#include "mojo/public/cpp/bindings/lib/router.h" -#include "mojo/public/cpp/system/macros.h" - -namespace mojo { - -// A RemotePtr is a smart-pointer for managing the connection of a message pipe -// to an interface proxy. -// -// EXAMPLE: -// -// Given foo.mojom containing the following interfaces: -// -// [Peer=FooClient] -// interface Foo { -// void Ping(); -// }; -// -// [Peer=Foo] -// interface FooClient { -// void Pong(); -// }; -// -// On the client side of a service, RemotePtr might be used like so: -// -// class FooClientImpl : public FooClient { -// public: -// explicit FooClientImpl(ScopedFooHandle handle) -// : foo_(handle.Pass(), this) { -// foo_.Ping(); -// } -// virtual void Pong() { -// ... -// } -// private: -// mojo::RemotePtr<Foo> foo_; -// }; -// -// On the implementation side of a service, RemotePtr might be used like so: -// -// class FooImpl : public Foo { -// public: -// explicit FooImpl(ScopedFooClientHandle handle) -// : client_(handle.Pass(), this) { -// } -// virtual void Ping() { -// client_->Pong(); -// } -// private: -// mojo::RemotePtr<FooClient> client_; -// }; -// -// NOTE: -// -// 1- It is valid to pass NULL for the peer if you are not interested in -// receiving incoming messages. Those messages will still be consumed. -// -// 2- You may optionally register an ErrorHandler on the RemotePtr to be -// notified if the peer has gone away. Alternatively, you may poll the -// |encountered_error()| method to check if the peer has gone away. -// -template <typename S> -class RemotePtr { - struct State; - MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(RemotePtr, RValue) - - public: - RemotePtr() : state_(NULL) {} - explicit RemotePtr(typename Interface<S>::ScopedHandle interface_handle, - typename S::_Peer* peer, - ErrorHandler* error_handler = NULL, - MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) - : state_(new State(ScopedMessagePipeHandle(interface_handle.Pass()), peer, - error_handler, waiter)) { - } - - // Move-only constructor and operator=. - RemotePtr(RValue other) : state_(other.object->release()) {} - RemotePtr& operator=(RValue other) { - delete state_; - state_ = other.object->release(); - return *this; - } - - ~RemotePtr() { - delete state_; - } - - bool is_null() const { - return !state_; - } - - S* get() { - assert(state_); - return &state_->proxy; - } - - S* operator->() { - return get(); - } - - void reset() { - delete state_; - state_ = NULL; - } - - void reset(typename Interface<S>::ScopedHandle interface_handle, - typename S::_Peer* peer, - ErrorHandler* error_handler = NULL, - MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { - delete state_; - state_ = new State(ScopedMessagePipeHandle(interface_handle.Pass()), peer, - error_handler, waiter); - } - - bool encountered_error() const { - assert(state_); - return state_->router.encountered_error(); - } - - internal::Router* router_for_testing() { - return &state_->router; - } - - private: - struct State { - State(ScopedMessagePipeHandle message_pipe, typename S::_Peer* peer, - ErrorHandler* error_handler, MojoAsyncWaiter* waiter) - : router(message_pipe.Pass(), waiter), - proxy(&router), - stub(peer) { - router.set_error_handler(error_handler); - if (peer) - router.set_incoming_receiver(&stub); - } - internal::Router router; - typename S::_Proxy proxy; - typename S::_Peer::_Stub stub; - }; - - State* release() { - State* state = state_; - state_ = NULL; - return state; - } - - State* state_; -}; - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_REMOTE_PTR_H_ diff --git a/mojo/public/cpp/bindings/sync_dispatcher.h b/mojo/public/cpp/bindings/sync_dispatcher.h index e267a17..7521180 100644 --- a/mojo/public/cpp/bindings/sync_dispatcher.h +++ b/mojo/public/cpp/bindings/sync_dispatcher.h @@ -16,11 +16,11 @@ class MessageReceiver; bool WaitForMessageAndDispatch(MessagePipeHandle handle, mojo::MessageReceiver* receiver); -template<typename S> class SyncDispatcher { +template<typename Interface> class SyncDispatcher { public: - SyncDispatcher(ScopedMessagePipeHandle message_pipe, S* sink) - : message_pipe_(message_pipe.Pass()), - stub_(sink) { + SyncDispatcher(ScopedMessagePipeHandle message_pipe, Interface* sink) + : message_pipe_(message_pipe.Pass()) { + stub_.set_sink(sink); } bool WaitAndDispatchOneMessage() { @@ -29,7 +29,7 @@ template<typename S> class SyncDispatcher { private: ScopedMessagePipeHandle message_pipe_; - typename S::_Stub stub_; + typename Interface::Stub_ stub_; }; } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/array_unittest.cc b/mojo/public/cpp/bindings/tests/array_unittest.cc index dccd716..4bef4cd 100644 --- a/mojo/public/cpp/bindings/tests/array_unittest.cc +++ b/mojo/public/cpp/bindings/tests/array_unittest.cc @@ -4,7 +4,6 @@ #include "mojo/public/cpp/bindings/allocation_scope.h" #include "mojo/public/cpp/bindings/array.h" -#include "mojo/public/cpp/bindings/interface.h" #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/bindings/lib/scratch_buffer.h" #include "mojo/public/cpp/environment/environment.h" @@ -141,31 +140,6 @@ TEST(ArrayTest, MessagePipeHandlesAreClosed) { EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value)); } -// Tests that Array<InterfaceHandle<S>> supports closing handles. -TEST(ArrayTest, InterfaceHandlesAreClosed) { - Environment env; - - InterfacePipe<sample::Port, sample::Port> pipe; - - MojoHandle pipe0_value = pipe.handle_to_self.get().value(); - MojoHandle pipe1_value = pipe.handle_to_peer.get().value(); - - { - AllocationScope scope; - - Array<sample::PortHandle>::Builder handles_builder(2); - handles_builder[0] = pipe.handle_to_self.Pass(); - handles_builder[1].reset(pipe.handle_to_peer.release()); - - MOJO_ALLOW_UNUSED Array<sample::PortHandle> handles = - handles_builder.Finish(); - } - - // We expect the pipes to have been closed. - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe0_value)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value)); -} - } // namespace } // namespace test } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc index 7df6db6..2cbd789 100644 --- a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc +++ b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "mojo/public/cpp/bindings/allocation_scope.h" -#include "mojo/public/cpp/bindings/remote_ptr.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "mojo/public/cpp/utility/run_loop.h" @@ -17,10 +16,14 @@ namespace { const char kText1[] = "hello"; const char kText2[] = "world"; -class SampleFactoryImpl : public sample::Factory { +class SampleFactoryImpl : public InterfaceImpl<sample::Factory> { public: - explicit SampleFactoryImpl(sample::ScopedFactoryClientHandle handle) - : client_(handle.Pass(), this) { + virtual void OnConnectionError() MOJO_OVERRIDE { + delete this; + } + + virtual void SetClient(sample::FactoryClient* client) MOJO_OVERRIDE { + client_ = client; } virtual void DoStuff(const sample::Request& request, @@ -70,69 +73,17 @@ class SampleFactoryImpl : public sample::Factory { } private: - RemotePtr<sample::FactoryClient> client_; + sample::FactoryClient* client_; ScopedMessagePipeHandle pipe1_; }; class SampleFactoryClientImpl : public sample::FactoryClient { public: - explicit SampleFactoryClientImpl(sample::ScopedFactoryHandle handle) - : factory_(handle.Pass(), this), - got_response_(false) { - } - - void Start() { - expected_text_reply_ = kText1; - - ScopedMessagePipeHandle pipe0; - CreateMessagePipe(&pipe0, &pipe1_); - - EXPECT_TRUE(WriteTextMessage(pipe1_.get(), kText1)); - - ScopedMessagePipeHandle pipe2; - CreateMessagePipe(&pipe2, &pipe3_); - - EXPECT_TRUE(WriteTextMessage(pipe3_.get(), kText2)); - - AllocationScope scope; - sample::Request::Builder request; - request.set_x(1); - request.set_pipe(pipe2.Pass()); - factory_->DoStuff(request.Finish(), pipe0.Pass()); - } - - void StartNoPipes() { - expected_text_reply_.clear(); - - AllocationScope scope; - sample::Request::Builder request; - request.set_x(1); - factory_->DoStuff(request.Finish(), ScopedMessagePipeHandle().Pass()); + SampleFactoryClientImpl() : got_response_(false) { } - // Writes a string to a data pipe and passes the data pipe (consumer) to the - // factory. - void StartDataPipe() { - expected_text_reply_.clear(); - - ScopedDataPipeProducerHandle producer_handle; - ScopedDataPipeConsumerHandle consumer_handle; - MojoCreateDataPipeOptions options = { - sizeof(MojoCreateDataPipeOptions), - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, - 1, - 1024}; - ASSERT_EQ(MOJO_RESULT_OK, - CreateDataPipe(&options, &producer_handle, &consumer_handle)); - expected_text_reply_ = "got it"; - // +1 for \0. - uint32_t data_size = static_cast<uint32_t>(expected_text_reply_.size() + 1); - ASSERT_EQ(MOJO_RESULT_OK, - WriteDataRaw(producer_handle.get(), expected_text_reply_.c_str(), - &data_size, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); - - AllocationScope scope; - factory_->DoStuff2(consumer_handle.Pass()); + void set_expected_text_reply(const std::string& expected_text_reply) { + expected_text_reply_ = expected_text_reply; } bool got_response() const { @@ -167,7 +118,6 @@ class SampleFactoryClientImpl : public sample::FactoryClient { } private: - RemotePtr<sample::Factory> factory_; ScopedMessagePipeHandle pipe1_; ScopedMessagePipeHandle pipe3_; std::string expected_text_reply_; @@ -176,6 +126,10 @@ class SampleFactoryClientImpl : public sample::FactoryClient { class HandlePassingTest : public testing::Test { public: + virtual void TearDown() { + PumpMessages(); + } + void PumpMessages() { loop_.RunUntilIdle(); } @@ -186,12 +140,31 @@ class HandlePassingTest : public testing::Test { }; TEST_F(HandlePassingTest, Basic) { - InterfacePipe<sample::Factory> pipe; + sample::FactoryPtr factory; + BindToProxy(new SampleFactoryImpl(), &factory); + + SampleFactoryClientImpl factory_client; + factory_client.set_expected_text_reply(kText1); + + factory->SetClient(&factory_client); + + ScopedMessagePipeHandle pipe0, pipe1; + CreateMessagePipe(&pipe0, &pipe1); + + EXPECT_TRUE(WriteTextMessage(pipe1.get(), kText1)); + + ScopedMessagePipeHandle pipe2, pipe3; + CreateMessagePipe(&pipe2, &pipe3); - SampleFactoryImpl factory(pipe.handle_to_peer.Pass()); - SampleFactoryClientImpl factory_client(pipe.handle_to_self.Pass()); + EXPECT_TRUE(WriteTextMessage(pipe3.get(), kText2)); - factory_client.Start(); + { + AllocationScope scope; + sample::Request::Builder request; + request.set_x(1); + request.set_pipe(pipe2.Pass()); + factory->DoStuff(request.Finish(), pipe0.Pass()); + } EXPECT_FALSE(factory_client.got_response()); @@ -201,12 +174,18 @@ TEST_F(HandlePassingTest, Basic) { } TEST_F(HandlePassingTest, PassInvalid) { - InterfacePipe<sample::Factory> pipe; + sample::FactoryPtr factory; + BindToProxy(new SampleFactoryImpl(), &factory); - SampleFactoryImpl factory(pipe.handle_to_peer.Pass()); - SampleFactoryClientImpl factory_client(pipe.handle_to_self.Pass()); + SampleFactoryClientImpl factory_client; + factory->SetClient(&factory_client); - factory_client.StartNoPipes(); + { + AllocationScope scope; + sample::Request::Builder request; + request.set_x(1); + factory->DoStuff(request.Finish(), ScopedMessagePipeHandle().Pass()); + } EXPECT_FALSE(factory_client.got_response()); @@ -217,12 +196,35 @@ TEST_F(HandlePassingTest, PassInvalid) { // Verifies DataPipeConsumer can be passed and read from. TEST_F(HandlePassingTest, DataPipe) { - InterfacePipe<sample::Factory> pipe; + sample::FactoryPtr factory; + BindToProxy(new SampleFactoryImpl(), &factory); + + SampleFactoryClientImpl factory_client; + factory->SetClient(&factory_client); - SampleFactoryImpl factory(pipe.handle_to_peer.Pass()); - SampleFactoryClientImpl factory_client(pipe.handle_to_self.Pass()); + // Writes a string to a data pipe and passes the data pipe (consumer) to the + // factory. + ScopedDataPipeProducerHandle producer_handle; + ScopedDataPipeConsumerHandle consumer_handle; + MojoCreateDataPipeOptions options = { + sizeof(MojoCreateDataPipeOptions), + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, + 1, + 1024}; + ASSERT_EQ(MOJO_RESULT_OK, + CreateDataPipe(&options, &producer_handle, &consumer_handle)); + std::string expected_text_reply = "got it"; + factory_client.set_expected_text_reply(expected_text_reply); + // +1 for \0. + uint32_t data_size = static_cast<uint32_t>(expected_text_reply.size() + 1); + ASSERT_EQ(MOJO_RESULT_OK, + WriteDataRaw(producer_handle.get(), expected_text_reply.c_str(), + &data_size, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); - ASSERT_NO_FATAL_FAILURE(factory_client.StartDataPipe()); + { + AllocationScope scope; + factory->DoStuff2(consumer_handle.Pass()); + } EXPECT_FALSE(factory_client.got_response()); @@ -232,8 +234,11 @@ TEST_F(HandlePassingTest, DataPipe) { } TEST_F(HandlePassingTest, PipesAreClosed) { - InterfacePipe<sample::Factory> pipe; - RemotePtr<sample::Factory> factory(pipe.handle_to_self.Pass(), NULL); + sample::FactoryPtr factory; + BindToProxy(new SampleFactoryImpl(), &factory); + + SampleFactoryClientImpl factory_client; + factory->SetClient(&factory_client); MessagePipe extra_pipe; diff --git a/mojo/public/cpp/bindings/tests/remote_ptr_unittest.cc b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc index 13311d4..3f9a80d 100644 --- a/mojo/public/cpp/bindings/tests/remote_ptr_unittest.cc +++ b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "mojo/public/cpp/bindings/error_handler.h" -#include "mojo/public/cpp/bindings/remote_ptr.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/utility/run_loop.h" #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" @@ -21,7 +20,7 @@ class ErrorObserver : public ErrorHandler { bool encountered_error() const { return encountered_error_; } - virtual void OnError() MOJO_OVERRIDE { + virtual void OnConnectionError() MOJO_OVERRIDE { encountered_error_ = true; } @@ -29,13 +28,19 @@ class ErrorObserver : public ErrorHandler { bool encountered_error_; }; -class MathCalculatorImpl : public math::Calculator { +class MathCalculatorImpl : public InterfaceImpl<math::Calculator> { public: virtual ~MathCalculatorImpl() {} - explicit MathCalculatorImpl(math::ScopedCalculatorUIHandle ui_handle) - : ui_(ui_handle.Pass(), this), - total_(0.0) { + MathCalculatorImpl() : total_(0.0) { + } + + virtual void OnConnectionError() MOJO_OVERRIDE { + delete this; + } + + virtual void SetClient(math::CalculatorUI* ui) MOJO_OVERRIDE { + ui_ = ui; } virtual void Clear() MOJO_OVERRIDE { @@ -53,16 +58,16 @@ class MathCalculatorImpl : public math::Calculator { } private: - RemotePtr<math::CalculatorUI> ui_; + math::CalculatorUI* ui_; double total_; }; class MathCalculatorUIImpl : public math::CalculatorUI { public: - explicit MathCalculatorUIImpl(math::ScopedCalculatorHandle calculator_handle, - ErrorHandler* error_handler = NULL) - : calculator_(calculator_handle.Pass(), this, error_handler), + explicit MathCalculatorUIImpl(math::CalculatorPtr calculator) + : calculator_(calculator.Pass()), output_(0.0) { + calculator_->SetClient(this); } bool encountered_error() const { @@ -95,30 +100,31 @@ class MathCalculatorUIImpl : public math::CalculatorUI { output_ = value; } - RemotePtr<math::Calculator> calculator_; + math::CalculatorPtr calculator_; double output_; }; -class RemotePtrTest : public testing::Test { +class InterfacePtrTest : public testing::Test { public: - void PumpMessages() { + virtual ~InterfacePtrTest() { loop_.RunUntilIdle(); } - protected: - InterfacePipe<math::CalculatorUI> pipe_; + void PumpMessages() { + loop_.RunUntilIdle(); + } private: Environment env_; RunLoop loop_; }; -TEST_F(RemotePtrTest, EndToEnd) { - // Suppose this is instantiated in a process that has pipe0_. - MathCalculatorImpl calculator(pipe_.handle_to_self.Pass()); +TEST_F(InterfacePtrTest, EndToEnd) { + math::CalculatorPtr calc; + BindToProxy(new MathCalculatorImpl(), &calc); // Suppose this is instantiated in a process that has pipe1_. - MathCalculatorUIImpl calculator_ui(pipe_.handle_to_peer.Pass()); + MathCalculatorUIImpl calculator_ui(calc.Pass()); calculator_ui.Add(2.0); calculator_ui.Multiply(5.0); @@ -128,43 +134,48 @@ TEST_F(RemotePtrTest, EndToEnd) { EXPECT_EQ(10.0, calculator_ui.GetOutput()); } -TEST_F(RemotePtrTest, Movable) { - RemotePtr<math::Calculator> a; - RemotePtr<math::Calculator> b(pipe_.handle_to_peer.Pass(), NULL); +TEST_F(InterfacePtrTest, Movable) { + math::CalculatorPtr a; + math::CalculatorPtr b; + BindToProxy(new MathCalculatorImpl(), &b); - EXPECT_TRUE(a.is_null()); - EXPECT_FALSE(b.is_null()); + EXPECT_TRUE(!a.get()); + EXPECT_FALSE(!b.get()); a = b.Pass(); - EXPECT_FALSE(a.is_null()); - EXPECT_TRUE(b.is_null()); + EXPECT_FALSE(!a.get()); + EXPECT_TRUE(!b.get()); } -TEST_F(RemotePtrTest, Resettable) { - RemotePtr<math::Calculator> a; +TEST_F(InterfacePtrTest, Resettable) { + math::CalculatorPtr a; - EXPECT_TRUE(a.is_null()); + EXPECT_TRUE(!a.get()); - math::CalculatorHandle handle = pipe_.handle_to_peer.get(); + MessagePipe pipe; - a.reset(pipe_.handle_to_peer.Pass(), NULL); + // Save this so we can test it later. + Handle handle = pipe.handle0.get(); - EXPECT_FALSE(a.is_null()); + a = MakeProxy<math::Calculator>(pipe.handle0.Pass()); + + EXPECT_FALSE(!a.get()); a.reset(); - EXPECT_TRUE(a.is_null()); + EXPECT_TRUE(!a.get()); + EXPECT_FALSE(a.internal_state()->router()); // Test that handle was closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle)); } -TEST_F(RemotePtrTest, EncounteredError) { - MathCalculatorImpl* calculator = - new MathCalculatorImpl(pipe_.handle_to_self.Pass()); +TEST_F(InterfacePtrTest, EncounteredError) { + math::CalculatorPtr proxy; + MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); - MathCalculatorUIImpl calculator_ui(pipe_.handle_to_peer.Pass()); + MathCalculatorUIImpl calculator_ui(proxy.Pass()); calculator_ui.Add(2.0); PumpMessages(); @@ -174,8 +185,8 @@ TEST_F(RemotePtrTest, EncounteredError) { calculator_ui.Multiply(5.0); EXPECT_FALSE(calculator_ui.encountered_error()); - // Close the other side of the pipe. - delete calculator; + // Close the server. + server->internal_state()->router()->CloseMessagePipe(); // The state change isn't picked up locally yet. EXPECT_FALSE(calculator_ui.encountered_error()); @@ -186,13 +197,14 @@ TEST_F(RemotePtrTest, EncounteredError) { EXPECT_TRUE(calculator_ui.encountered_error()); } -TEST_F(RemotePtrTest, EncounteredErrorCallback) { - MathCalculatorImpl* calculator = - new MathCalculatorImpl(pipe_.handle_to_self.Pass()); +TEST_F(InterfacePtrTest, EncounteredErrorCallback) { + math::CalculatorPtr proxy; + MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); ErrorObserver error_observer; - MathCalculatorUIImpl calculator_ui(pipe_.handle_to_peer.Pass(), - &error_observer); + proxy.set_error_handler(&error_observer); + + MathCalculatorUIImpl calculator_ui(proxy.Pass()); calculator_ui.Add(2.0); PumpMessages(); @@ -202,8 +214,8 @@ TEST_F(RemotePtrTest, EncounteredErrorCallback) { calculator_ui.Multiply(5.0); EXPECT_FALSE(calculator_ui.encountered_error()); - // Close the other side of the pipe. - delete calculator; + // Close the server. + server->internal_state()->router()->CloseMessagePipe(); // The state change isn't picked up locally yet. EXPECT_FALSE(calculator_ui.encountered_error()); @@ -218,11 +230,12 @@ TEST_F(RemotePtrTest, EncounteredErrorCallback) { EXPECT_TRUE(error_observer.encountered_error()); } -TEST_F(RemotePtrTest, NoPeerAttribute) { +TEST_F(InterfacePtrTest, NoClientAttribute) { // This is a test to ensure the following compiles. The sample::Port interface - // does not have an explicit Peer attribute. - InterfacePipe<sample::Port, NoInterface> pipe; - RemotePtr<sample::Port> port(pipe.handle_to_self.Pass(), NULL); + // does not have an explicit Client attribute. + sample::PortPtr port; + MessagePipe pipe; + port.Bind(pipe.handle0.Pass()); } } // namespace diff --git a/mojo/public/cpp/bindings/tests/request_response_unittest.cc b/mojo/public/cpp/bindings/tests/request_response_unittest.cc index 94ed91f..d163f7d 100644 --- a/mojo/public/cpp/bindings/tests/request_response_unittest.cc +++ b/mojo/public/cpp/bindings/tests/request_response_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "mojo/public/cpp/bindings/allocation_scope.h" -#include "mojo/public/cpp/bindings/remote_ptr.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "mojo/public/cpp/utility/run_loop.h" @@ -15,10 +14,14 @@ namespace mojo { namespace test { namespace { -class ProviderImpl : public sample::Provider { +class ProviderImpl : public InterfaceImpl<sample::Provider> { public: - explicit ProviderImpl(sample::ScopedProviderClientHandle handle) - : client_(handle.Pass(), this) { + virtual void OnConnectionError() MOJO_OVERRIDE { + delete this; + } + + virtual void SetClient(sample::ProviderClient* client) MOJO_OVERRIDE { + // Ignored. TODO(darin): Eliminate ProviderClient. } virtual void EchoString( @@ -51,9 +54,6 @@ class ProviderImpl : public sample::Provider { MOJO_OVERRIDE { callback.Run(a); } - - private: - RemotePtr<sample::ProviderClient> client_; }; class StringRecorder { @@ -94,6 +94,10 @@ class MessagePipeWriter { class RequestResponseTest : public testing::Test { public: + virtual ~RequestResponseTest() { + loop_.RunUntilIdle(); + } + void PumpMessages() { loop_.RunUntilIdle(); } @@ -104,9 +108,8 @@ class RequestResponseTest : public testing::Test { }; TEST_F(RequestResponseTest, EchoString) { - InterfacePipe<sample::Provider> pipe; - ProviderImpl provider_impl(pipe.handle_to_peer.Pass()); - RemotePtr<sample::Provider> provider(pipe.handle_to_self.Pass(), NULL); + sample::ProviderPtr provider; + BindToProxy(new ProviderImpl(), &provider); std::string buf; { @@ -120,9 +123,8 @@ TEST_F(RequestResponseTest, EchoString) { } TEST_F(RequestResponseTest, EchoStrings) { - InterfacePipe<sample::Provider> pipe; - ProviderImpl provider_impl(pipe.handle_to_peer.Pass()); - RemotePtr<sample::Provider> provider(pipe.handle_to_self.Pass(), NULL); + sample::ProviderPtr provider; + BindToProxy(new ProviderImpl(), &provider); std::string buf; { @@ -136,9 +138,8 @@ TEST_F(RequestResponseTest, EchoStrings) { } TEST_F(RequestResponseTest, EchoMessagePipeHandle) { - InterfacePipe<sample::Provider> pipe; - ProviderImpl provider_impl(pipe.handle_to_peer.Pass()); - RemotePtr<sample::Provider> provider(pipe.handle_to_self.Pass(), NULL); + sample::ProviderPtr provider; + BindToProxy(new ProviderImpl(), &provider); MessagePipe pipe2; { @@ -156,9 +157,8 @@ TEST_F(RequestResponseTest, EchoMessagePipeHandle) { } TEST_F(RequestResponseTest, EchoEnum) { - InterfacePipe<sample::Provider> pipe; - ProviderImpl provider_impl(pipe.handle_to_peer.Pass()); - RemotePtr<sample::Provider> provider(pipe.handle_to_self.Pass(), NULL); + sample::ProviderPtr provider; + BindToProxy(new ProviderImpl(), &provider); sample::Enum value; { diff --git a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc index 9a4cf36..c13517d 100644 --- a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc +++ b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc @@ -266,7 +266,14 @@ void DumpHex(const uint8_t* bytes, uint32_t num_bytes) { class ServiceImpl : public Service { public: - virtual void Frobinate(const Foo& foo, BazOptions baz, ScopedPortHandle port) + ServiceImpl() : client_(NULL) { + } + + virtual void SetClient(ServiceClient* client) MOJO_OVERRIDE { + client_ = client; + } + + virtual void Frobinate(const Foo& foo, BazOptions baz, PortPtr port) MOJO_OVERRIDE { // Users code goes here to handle the incoming Frobinate message. @@ -283,6 +290,20 @@ class ServiceImpl : public Service { Print(depth, "port", port.get()); } } + + private: + ServiceClient* client_; +}; + +class ServiceProxyImpl : public ServiceProxy { + public: + explicit ServiceProxyImpl(mojo::MessageReceiver* receiver) + : ServiceProxy(receiver) { + } + + virtual void SetClient(ServiceClient* client) MOJO_OVERRIDE { + assert(false); + } }; class SimpleMessageReceiver : public mojo::MessageReceiver { @@ -299,7 +320,8 @@ class SimpleMessageReceiver : public mojo::MessageReceiver { // the system. It receives the incoming message. ServiceImpl impl; - ServiceStub stub(&impl); + ServiceStub stub; + stub.set_sink(&impl); return stub.Accept(message); } @@ -315,7 +337,7 @@ TEST(BindingsSampleTest, Basic) { SimpleMessageReceiver receiver; // User has a proxy to a Service somehow. - Service* service = new ServiceProxy(&receiver); + Service* service = new ServiceProxyImpl(&receiver); // User constructs a message to send. @@ -328,8 +350,8 @@ TEST(BindingsSampleTest, Basic) { Foo foo = MakeFoo(); CheckFoo(foo); - mojo::InterfacePipe<Port, mojo::AnyInterface> pipe; - service->Frobinate(foo, Service::BAZ_EXTRA, pipe.handle_to_self.Pass()); + PortPtr port; + service->Frobinate(foo, Service::BAZ_EXTRA, port.Pass()); } TEST(BindingsSampleTest, DefaultValues) { diff --git a/mojo/public/cpp/shell/application.h b/mojo/public/cpp/shell/application.h index ffca7fe..933077b 100644 --- a/mojo/public/cpp/shell/application.h +++ b/mojo/public/cpp/shell/application.h @@ -7,7 +7,6 @@ #include <vector> -#include "mojo/public/cpp/bindings/remote_ptr.h" #include "mojo/public/cpp/shell/service.h" #include "mojo/public/cpp/system/core.h" #include "mojo/public/interfaces/shell/shell.mojom.h" @@ -16,7 +15,7 @@ namespace mojo { class Application : public internal::ServiceConnectorBase::Owner { public: - explicit Application(ScopedShellHandle shell_handle); + explicit Application(ScopedMessagePipeHandle shell_handle); explicit Application(MojoHandle shell_handle); virtual ~Application(); @@ -27,6 +26,11 @@ class Application : public internal::ServiceConnectorBase::Owner { virtual void RemoveServiceConnector( internal::ServiceConnectorBase* service_connector) MOJO_OVERRIDE; + template <typename Interface> + void ConnectTo(const std::string& url, InterfacePtr<Interface>* ptr) { + mojo::ConnectTo(shell(), url, ptr); + } + protected: // ShellClient methods. virtual void AcceptConnection(const mojo::String& url, diff --git a/mojo/public/cpp/shell/lib/application.cc b/mojo/public/cpp/shell/lib/application.cc index 3224202..161e4e0 100644 --- a/mojo/public/cpp/shell/lib/application.cc +++ b/mojo/public/cpp/shell/lib/application.cc @@ -6,13 +6,13 @@ namespace mojo { -Application::Application(ScopedShellHandle shell_handle) +Application::Application(ScopedMessagePipeHandle shell_handle) : internal::ServiceConnectorBase::Owner(shell_handle.Pass()) { } Application::Application(MojoHandle shell_handle) : internal::ServiceConnectorBase::Owner( - mojo::MakeScopedHandle(ShellHandle(shell_handle)).Pass()) {} + mojo::MakeScopedHandle(MessagePipeHandle(shell_handle)).Pass()) {} Application::~Application() { for (ServiceConnectorList::iterator it = service_connectors_.begin(); diff --git a/mojo/public/cpp/shell/lib/service.cc b/mojo/public/cpp/shell/lib/service.cc index e408481..2f2e542 100644 --- a/mojo/public/cpp/shell/lib/service.cc +++ b/mojo/public/cpp/shell/lib/service.cc @@ -7,8 +7,9 @@ namespace mojo { namespace internal { -ServiceConnectorBase::Owner::Owner(ScopedShellHandle shell_handle) - : shell_(shell_handle.Pass(), this) { +ServiceConnectorBase::Owner::Owner(ScopedMessagePipeHandle shell_handle) + : shell_(MakeProxy<Shell>(shell_handle.Pass())) { + shell_->SetClient(this); } ServiceConnectorBase::Owner::~Owner() {} diff --git a/mojo/public/cpp/shell/service.h b/mojo/public/cpp/shell/service.h index 7dd08ff..c546289 100644 --- a/mojo/public/cpp/shell/service.h +++ b/mojo/public/cpp/shell/service.h @@ -5,11 +5,11 @@ #ifndef MOJO_PUBLIC_SHELL_SERVICE_H_ #define MOJO_PUBLIC_SHELL_SERVICE_H_ +#include <assert.h> + #include <vector> -#include "mojo/public/cpp/bindings/error_handler.h" -#include "mojo/public/cpp/bindings/remote_ptr.h" -#include "mojo/public/cpp/system/core.h" +#include "mojo/public/cpp/bindings/allocation_scope.h" #include "mojo/public/interfaces/shell/shell.mojom.h" // Utility classes for creating ShellClients that vend service instances. @@ -19,11 +19,9 @@ // class FooImpl : public Foo { // public: // FooImpl(); -// void Initialize(ServiceConnector<FooImpl>* service_connector, -// ScopedMessagePipeHandle client_handle +// void Initialize(); // private: // ServiceConnector<FooImpl>* service_connector_; -// RemotePtr<FooPeer> client_; // }; // // @@ -66,8 +64,8 @@ class ServiceConnectorBase { public: class Owner : public ShellClient { public: - Owner(ScopedShellHandle shell_handle); - ~Owner(); + Owner(ScopedMessagePipeHandle shell_handle); + virtual ~Owner(); Shell* shell() { return shell_.get(); } virtual void AddServiceConnector( internal::ServiceConnectorBase* service_connector) = 0; @@ -79,7 +77,7 @@ class ServiceConnectorBase { Owner* owner) { service_connector->owner_ = owner; } - RemotePtr<Shell> shell_; + ShellPtr shell_; }; ServiceConnectorBase() : owner_(NULL) {} virtual ~ServiceConnectorBase(); @@ -98,27 +96,33 @@ class ServiceConnector : public internal::ServiceConnectorBase { ServiceConnector(Context* context = NULL) : context_(context) {} virtual ~ServiceConnector() { - for (typename ServiceList::iterator it = services_.begin(); - it != services_.end(); ++it) { + 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 AcceptConnection(const std::string& url, - ScopedMessagePipeHandle client_handle) - MOJO_OVERRIDE { - ServiceImpl* service = new ServiceImpl(); - service->Initialize(this, client_handle.Pass()); - services_.push_back(service); + ScopedMessagePipeHandle handle) MOJO_OVERRIDE { + ServiceImpl* impl = BindToPipe(new ServiceImpl(), handle.Pass()); + impl->set_connector(this); + + connections_.push_back(impl); + + impl->Initialize(); } - void RemoveService(ServiceImpl* service) { - for (typename ServiceList::iterator it = services_.begin(); - it != services_.end(); ++it) { - if (*it == service) { - services_.erase(it); - delete service; - if (services_.empty()) + 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); + if (connections_.empty()) owner_->RemoveServiceConnector(this); return; } @@ -128,58 +132,63 @@ class ServiceConnector : public internal::ServiceConnectorBase { Context* context() const { return context_; } private: - typedef std::vector<ServiceImpl*> ServiceList; - ServiceList services_; + typedef std::vector<ServiceImpl*> ConnectionList; + ConnectionList connections_; Context* context_; }; // Specialization of ServiceConnection. // ServiceInterface: Service interface. -// ServiceImpl: Implementation of Service interface. +// ServiceImpl: Subclass of ServiceConnection<...>. // Context: Optional type of shared context. template <class ServiceInterface, class ServiceImpl, typename Context=void> -class ServiceConnection : public ServiceInterface { - public: +class ServiceConnection : public InterfaceImpl<ServiceInterface> { + protected: + // NOTE: shell() and context() are not available at construction time. + // Initialize() will be called once those are available. + ServiceConnection() : service_connector_(NULL) {} + virtual ~ServiceConnection() {} - protected: - ServiceConnection() : reaper_(this), service_connector_(NULL) {} - - void Initialize(ServiceConnector<ServiceImpl, Context>* service_connector, - ScopedMessagePipeHandle client_handle) { - service_connector_ = service_connector; - client_.reset( - MakeScopedHandle( - InterfaceHandle<typename ServiceInterface::_Peer>( - client_handle.release().value())).Pass(), - this, - &reaper_); + virtual void OnConnectionError() MOJO_OVERRIDE { + service_connector_->RemoveConnection(static_cast<ServiceImpl*>(this)); + } + + // Shadow this method in ServiceImpl to perform one-time initialization. + // At the time this is called, shell() and context() will be available. + // NOTE: No need to call the base class Initialize from your subclass. It + // will always be a no-op. + void Initialize() {} + + Shell* shell() { + return service_connector_->shell(); } - Shell* shell() { return service_connector_->shell(); } - Context* context() const { return service_connector_->context(); } - typename ServiceInterface::_Peer* client() { return client_.get(); } + Context* context() const { + return service_connector_->context(); + } private: - // The Reaper class allows us to handle errors on the client proxy without - // polluting the name space of the ServiceConnection<> class. - class Reaper : public ErrorHandler { - public: - Reaper(ServiceConnection<ServiceInterface, ServiceImpl, Context>* service) - : service_(service) {} - virtual void OnError() { - service_->service_connector_->RemoveService( - static_cast<ServiceImpl*>(service_)); - } - private: - ServiceConnection<ServiceInterface, ServiceImpl, Context>* service_; - }; friend class ServiceConnector<ServiceImpl, Context>; - Reaper reaper_; + + // Called shortly after this class is instantiated. + void set_connector(ServiceConnector<ServiceImpl, Context>* connector) { + service_connector_ = connector; + } + ServiceConnector<ServiceImpl, Context>* service_connector_; - RemotePtr<typename ServiceInterface::_Peer> client_; }; +template <typename Interface> +inline void ConnectTo(Shell* shell, const std::string& url, + InterfacePtr<Interface>* ptr) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass()); + + AllocationScope scope; + shell->Connect(url, pipe.handle1.Pass()); +} + } // namespace mojo #endif // MOJO_PUBLIC_SHELL_SERVICE_H_ |