OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ | |
6 #define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ | |
7 | |
8 #include <assert.h> | |
9 #include <stdio.h> | |
10 | |
11 #include <algorithm> | |
12 | |
13 #include "mojo/public/cpp/bindings/error_handler.h" | |
14 #include "mojo/public/cpp/bindings/lib/interface_ptr_internal.h" | |
15 #include "mojo/public/cpp/system/macros.h" | |
16 | |
17 namespace mojo { | |
18 | |
19 template <typename Interface> | |
20 class InterfacePtr { | |
21 MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfacePtr, RValue) | |
22 public: | |
23 InterfacePtr() {} | |
24 explicit InterfacePtr(Interface* impl) { state_.impl = impl; } | |
25 | |
26 InterfacePtr(RValue other) { other.object->state_.Swap(&state_); } | |
27 InterfacePtr& operator=(RValue other) { | |
28 other.object->state_.Swap(&state_); | |
29 return *this; | |
30 } | |
31 | |
32 ~InterfacePtr() {} | |
33 | |
34 Interface* get() const { | |
35 return state_.impl; | |
36 } | |
37 Interface* operator->() const { return get(); } | |
38 Interface* operator*() const { return get(); } | |
39 | |
40 void reset() { | |
41 State doomed; | |
42 state_.Swap(&doomed); | |
43 } | |
44 | |
45 void Bind(Interface* impl) { | |
46 reset(); | |
47 state_.impl = impl; | |
48 } | |
49 | |
50 bool encountered_error() const; | |
51 | |
52 void set_error_handler(ErrorHandler* error_handler) { | |
53 assert(state_.context); | |
54 state_.context->router()->set_error_handler(error_handler); | |
55 } | |
56 | |
57 // XXX figure out how to hide these! | |
58 | |
59 bool has_context() const { return !!state_.context; } | |
60 | |
61 void ConfigureProxy(ScopedMessagePipeHandle handle, | |
62 MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { | |
63 assert(!state_.impl); | |
64 assert(!state_.context); | |
65 | |
66 internal::InterfacePtrContext* context = | |
67 new internal::InterfacePtrContext(handle.Pass(), waiter); | |
68 ProxyWithStub* proxy = new ProxyWithStub(context->router()); | |
69 context->router()->set_incoming_receiver(&proxy->stub); | |
70 | |
71 state_.impl = proxy; | |
72 state_.context = context; | |
73 } | |
74 | |
75 void ConfigureStub(ScopedMessagePipeHandle handle, | |
76 MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { | |
77 assert(state_.impl); // Should have already been set! | |
78 assert(!state_.context); | |
79 | |
80 // Stub for binding to state_.impl | |
81 // Proxy for communicating to the client on the other end of the pipe. | |
82 | |
83 internal::InterfacePtrContext* context = | |
84 new internal::InterfacePtrContext(handle.Pass(), waiter); | |
85 ClientProxyWithStub* proxy = new ClientProxyWithStub(context->router()); | |
86 proxy->stub.set_sink(state_.impl); | |
87 context->router()->set_incoming_receiver(&proxy->stub); | |
88 | |
89 state_.impl->SetClient(proxy); | |
90 | |
91 state_.client = proxy; | |
92 state_.context = context; | |
93 } | |
94 | |
95 void Detach() { | |
96 new DetachedState(&state_); | |
97 } | |
98 | |
99 internal::Router* router_for_testing() { return state_.context->router(); } | |
100 | |
101 private: | |
102 class ProxyWithStub : public Interface::Proxy_ { | |
103 public: | |
104 explicit ProxyWithStub(MessageReceiver* receiver) | |
105 : Interface::Proxy_(receiver) { | |
106 } | |
107 virtual void SetClient(typename Interface::Client_* client) MOJO_OVERRIDE { | |
108 stub.set_sink(client); | |
109 } | |
110 typename Interface::Client_::Stub_ stub; | |
111 private: | |
112 MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyWithStub); | |
113 }; | |
114 | |
115 class ClientProxyWithStub : public Interface::Client_::Proxy_ { | |
116 public: | |
117 explicit ClientProxyWithStub(MessageReceiver* receiver) | |
118 : Interface::Client_::Proxy_(receiver) { | |
119 } | |
120 typename Interface::Stub_ stub; | |
121 private: | |
122 MOJO_DISALLOW_COPY_AND_ASSIGN(ClientProxyWithStub); | |
123 }; | |
124 | |
125 struct State { | |
126 State() : impl(NULL), client(NULL), context(NULL) {} | |
127 | |
128 ~State() { | |
129 // Destruction order matters here. We delete |impl| first, even though | |
130 // |context| may have a reference to it, so that |~Interface| may have a | |
131 // shot at generating new outbound messages (ie, nvoking client methods). | |
132 delete impl; | |
133 delete context; | |
134 delete client; | |
135 } | |
136 | |
137 void Swap(State* other) { | |
138 std::swap(other->impl, impl); | |
139 std::swap(other->client, client); | |
140 std::swap(other->context, context); | |
141 } | |
142 | |
143 Interface* impl; | |
144 typename Interface::Client_* client; | |
145 internal::InterfacePtrContext* context; | |
146 | |
147 MOJO_DISALLOW_COPY_AND_ASSIGN(State); | |
148 }; | |
149 | |
150 class DetachedState : public ErrorHandler { | |
151 public: | |
152 explicit DetachedState(State* state) { | |
153 internal::LogDetachedState(this, +1); | |
154 | |
155 state_.Swap(state); | |
156 | |
157 assert(state_.context); | |
158 assert(!state_.context->router()->encountered_error()); | |
159 | |
160 // Register to observe when the pipe is broken. | |
161 state_.context->router()->set_error_handler(this); | |
162 } | |
163 | |
164 virtual void OnError() MOJO_OVERRIDE { | |
165 internal::LogDetachedState(this, -1); | |
166 | |
167 delete this; | |
168 } | |
169 | |
170 private: | |
171 State state_; | |
172 | |
173 MOJO_DISALLOW_COPY_AND_ASSIGN(DetachedState); | |
174 }; | |
175 | |
176 State state_; | |
177 }; | |
178 | |
179 // Takes a handle to the proxy end-point of a pipe. On the other end is | |
180 // presumed to be an interface implementation of type |Interface|. Returns a | |
181 // generated proxy to that interface, which may be used on the current thread. | |
182 // It is valid to call SetClient on the returned Interface to set an instance | |
183 // of Interface::Client. | |
184 // | |
DaveMoore
2014/05/06 21:30:54
Maybe there should be a variant of this that takes
darin (slow to review)
2014/05/06 21:39:11
Yeah, that's something I've been considering as we
| |
185 // XXX not sure if MakeProxy is the best name here. | |
186 template <typename Interface> | |
187 InterfacePtr<Interface> MakeProxy( | |
188 ScopedMessagePipeHandle handle, | |
189 MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { | |
190 InterfacePtr<Interface> ptr; | |
191 if (handle.is_valid()) | |
192 ptr.ConfigureProxy(handle.Pass(), waiter); | |
193 return ptr.Pass(); | |
194 } | |
195 | |
196 // Takes a heap-allocated interface implementation and binds its lifetime to | |
197 // that of a MessagePipe. A handle to the proxy end-point of the pipe is | |
198 // returned. If that pipe is closed, then the interface implementation will be | |
199 // deleted. | |
200 // | |
201 // The interface implementation is also bound to the current thread. Its | |
202 // methods will only be called on the current thread, and if the current thread | |
203 // exits, then it will also be deleted and its end point of the pipe will be | |
204 // closed. | |
205 // | |
206 // Before returning the interface implementation will receive a SetClient call, | |
207 // providing it with a proxy to the client on the other end of the pipe. | |
208 // | |
209 // XXX not sure if BindToPipe is the best name here. | |
210 template <typename Interface> | |
211 ScopedMessagePipeHandle BindToPipe(Interface* impl) { | |
212 InterfacePtr<Interface> ptr(impl); | |
213 MessagePipe pipe; | |
214 ptr.ConfigureStub(pipe.handle0.Pass()); | |
215 ptr.Detach(); | |
216 return pipe.handle1.Pass(); | |
217 } | |
218 | |
219 } // namespace mojo | |
220 | |
221 #endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ | |
OLD | NEW |