Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2094)

Side by Side Diff: mojo/public/cpp/bindings/lib/interface_ptr_state.h

Issue 1473273003: Mojo C++ bindings: InterfacePtr<T> and Binding<T> use MultiplexRouter when T passes associated inte… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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_LIB_INTERFACE_PTR_STATE_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_
7
8 #include <algorithm> // For |std::swap()|.
9
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "mojo/public/cpp/bindings/associated_group.h"
15 #include "mojo/public/cpp/bindings/callback.h"
16 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
17 #include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
18 #include "mojo/public/cpp/bindings/lib/filter_chain.h"
19 #include "mojo/public/cpp/bindings/lib/interface_endpoint_client.h"
20 #include "mojo/public/cpp/bindings/lib/interface_id.h"
21 #include "mojo/public/cpp/bindings/lib/message_header_validator.h"
22 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
23 #include "mojo/public/cpp/bindings/lib/router.h"
24 #include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h"
25
26 struct MojoAsyncWaiter;
27
28 namespace mojo {
29 namespace internal {
30
31 template <typename Interface, bool use_multiplex_router>
32 class InterfacePtrState;
33
34 // Uses a single-threaded, dedicated router. If |Interface| doesn't have any
35 // methods to pass associated interface pointers or requests, there won't be
36 // multiple interfaces running on the underlying message pipe. In that case, we
37 // can use this specialization to reduce cost.
38 template <typename Interface>
39 class InterfacePtrState<Interface, false> {
40 public:
41 InterfacePtrState()
42 : proxy_(nullptr), router_(nullptr), waiter_(nullptr), version_(0u) {}
43
44 ~InterfacePtrState() {
45 // Destruction order matters here. We delete |proxy_| first, even though
46 // |router_| may have a reference to it, so that destructors for any request
47 // callbacks still pending can interact with the InterfacePtr.
48 delete proxy_;
49 delete router_;
50 }
51
52 Interface* instance() {
53 ConfigureProxyIfNecessary();
54
55 // This will be null if the object is not bound.
56 return proxy_;
57 }
58
59 uint32_t version() const { return version_; }
60
61 void QueryVersion(const Callback<void(uint32_t)>& callback) {
62 ConfigureProxyIfNecessary();
63
64 // It is safe to capture |this| because the callback won't be run after this
65 // object goes away.
66 auto callback_wrapper = [this, callback](uint32_t version) {
67 this->version_ = version;
68 callback.Run(version);
69 };
70
71 // Do a static cast in case the interface contains methods with the same
72 // name.
73 static_cast<ControlMessageProxy*>(proxy_)->QueryVersion(callback_wrapper);
74 }
75
76 void RequireVersion(uint32_t version) {
77 ConfigureProxyIfNecessary();
78
79 if (version <= version_)
80 return;
81
82 version_ = version;
83 // Do a static cast in case the interface contains methods with the same
84 // name.
85 static_cast<ControlMessageProxy*>(proxy_)->RequireVersion(version);
86 }
87
88 void Swap(InterfacePtrState* other) {
89 using std::swap;
90 swap(other->proxy_, proxy_);
91 swap(other->router_, router_);
92 handle_.swap(other->handle_);
93 swap(other->waiter_, waiter_);
94 swap(other->version_, version_);
95 }
96
97 void Bind(InterfacePtrInfo<Interface> info, const MojoAsyncWaiter* waiter) {
98 DCHECK(!proxy_);
99 DCHECK(!router_);
100 DCHECK(!handle_.is_valid());
101 DCHECK(!waiter_);
102 DCHECK_EQ(0u, version_);
103 DCHECK(info.is_valid());
104
105 handle_ = info.PassHandle();
106 waiter_ = waiter;
107 version_ = info.version();
108 }
109
110 bool WaitForIncomingResponse() {
111 ConfigureProxyIfNecessary();
112
113 DCHECK(router_);
114 return router_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
115 }
116
117 // After this method is called, the object is in an invalid state and
118 // shouldn't be reused.
119 InterfacePtrInfo<Interface> PassInterface() {
120 return InterfacePtrInfo<Interface>(
121 router_ ? router_->PassMessagePipe() : handle_.Pass(), version_);
122 }
123
124 bool is_bound() const { return handle_.is_valid() || router_; }
125
126 bool encountered_error() const {
127 return router_ ? router_->encountered_error() : false;
128 }
129
130 void set_connection_error_handler(const Closure& error_handler) {
131 ConfigureProxyIfNecessary();
132
133 DCHECK(router_);
134 router_->set_connection_error_handler(error_handler);
135 }
136
137 // Returns true if bound and awaiting a response to a message.
138 bool has_pending_callbacks() const {
139 return router_ && router_->has_pending_responders();
140 }
141
142 AssociatedGroup* associated_group() { return nullptr; }
143
144 void EnableTestingMode() {
145 ConfigureProxyIfNecessary();
146 router_->EnableTestingMode();
147 }
148
149 private:
150 using Proxy = typename Interface::Proxy_;
151
152 void ConfigureProxyIfNecessary() {
153 // The proxy has been configured.
154 if (proxy_) {
155 DCHECK(router_);
156 return;
157 }
158 // The object hasn't been bound.
159 if (!waiter_) {
160 DCHECK(!handle_.is_valid());
161 return;
162 }
163
164 FilterChain filters;
165 filters.Append<MessageHeaderValidator>();
166 filters.Append<typename Interface::ResponseValidator_>();
167
168 router_ = new Router(handle_.Pass(), filters.Pass(), waiter_);
169 waiter_ = nullptr;
170
171 proxy_ = new Proxy(router_);
172 }
173
174 Proxy* proxy_;
175 Router* router_;
176
177 // |proxy_| and |router_| are not initialized until read/write with the
178 // message pipe handle is needed. |handle_| and |waiter_| are valid between
179 // the Bind() call and the initialization of |proxy_| and |router_|.
180 ScopedMessagePipeHandle handle_;
181 const MojoAsyncWaiter* waiter_;
182
183 uint32_t version_;
184
185 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
186 };
187
188 // Uses a multiplexing router. If |Interface| has methods to pass associated
189 // interface pointers or requests, this specialization should be used.
190 template <typename Interface>
191 class InterfacePtrState<Interface, true> {
192 public:
193 InterfacePtrState() : waiter_(nullptr), version_(0u) {}
194
195 ~InterfacePtrState() {
196 endpoint_client_.reset();
197 proxy_.reset();
198 if (router_)
199 router_->CloseMessagePipe();
200 }
201
202 Interface* instance() {
203 ConfigureProxyIfNecessary();
204
205 // This will be null if the object is not bound.
206 return proxy_.get();
207 }
208
209 uint32_t version() const { return version_; }
210
211 void QueryVersion(const Callback<void(uint32_t)>& callback) {
212 ConfigureProxyIfNecessary();
213
214 // It is safe to capture |this| because the callback won't be run after this
215 // object goes away.
216 auto callback_wrapper = [this, callback](uint32_t version) {
217 this->version_ = version;
218 callback.Run(version);
219 };
220
221 // Do a static cast in case the interface contains methods with the same
222 // name.
223 static_cast<ControlMessageProxy*>(proxy_.get())
224 ->QueryVersion(callback_wrapper);
225 }
226
227 void RequireVersion(uint32_t version) {
228 ConfigureProxyIfNecessary();
229
230 if (version <= version_)
231 return;
232
233 version_ = version;
234 // Do a static cast in case the interface contains methods with the same
235 // name.
236 static_cast<ControlMessageProxy*>(proxy_.get())->RequireVersion(version);
237 }
238
239 void Swap(InterfacePtrState* other) {
240 using std::swap;
241 swap(other->router_, router_);
242 swap(other->endpoint_client_, endpoint_client_);
243 swap(other->proxy_, proxy_);
244 handle_.swap(other->handle_);
245 swap(other->waiter_, waiter_);
246 swap(other->version_, version_);
247 }
248
249 void Bind(InterfacePtrInfo<Interface> info, const MojoAsyncWaiter* waiter) {
250 DCHECK(!router_);
251 DCHECK(!endpoint_client_);
252 DCHECK(!proxy_);
253 DCHECK(!handle_.is_valid());
254 DCHECK(!waiter_);
255 DCHECK_EQ(0u, version_);
256 DCHECK(info.is_valid());
257
258 handle_ = info.PassHandle();
259 waiter_ = waiter;
260 version_ = info.version();
261 }
262
263 // After this method is called, the object is in an invalid state and
264 // shouldn't be reused.
265 InterfacePtrInfo<Interface> PassInterface() {
266 endpoint_client_.reset();
267 proxy_.reset();
268 return InterfacePtrInfo<Interface>(
269 router_ ? router_->PassMessagePipe() : handle_.Pass(), version_);
270 }
271
272 bool is_bound() const { return handle_.is_valid() || endpoint_client_; }
273
274 bool encountered_error() const {
275 return endpoint_client_ ? endpoint_client_->encountered_error() : false;
276 }
277
278 void set_connection_error_handler(const Closure& error_handler) {
279 ConfigureProxyIfNecessary();
280
281 DCHECK(endpoint_client_);
282 endpoint_client_->set_connection_error_handler(error_handler);
283 }
284
285 // Returns true if bound and awaiting a response to a message.
286 bool has_pending_callbacks() const {
287 return endpoint_client_ && endpoint_client_->has_pending_responders();
288 }
289
290 AssociatedGroup* associated_group() {
291 ConfigureProxyIfNecessary();
292 return endpoint_client_->associated_group();
293 }
294
295 void EnableTestingMode() {
296 ConfigureProxyIfNecessary();
297 router_->EnableTestingMode();
298 }
299
300 // Intentionally not defined:
301 // bool WaitForIncomingResponse();
302
303 private:
304 using Proxy = typename Interface::Proxy_;
305
306 void ConfigureProxyIfNecessary() {
307 // The proxy has been configured.
308 if (proxy_) {
309 DCHECK(router_);
310 DCHECK(endpoint_client_);
311 return;
312 }
313 // The object hasn't been bound.
314 if (!waiter_) {
315 DCHECK(!handle_.is_valid());
316 return;
317 }
318
319 router_ = new MultiplexRouter(true, handle_.Pass(), waiter_);
320 endpoint_client_.reset(new InterfaceEndpointClient(
321 router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr,
322 make_scoped_ptr(new typename Interface::ResponseValidator_())));
323 proxy_.reset(new Proxy(endpoint_client_.get(), endpoint_client_->router()));
324
325 waiter_ = nullptr;
326 }
327
328 scoped_refptr<MultiplexRouter> router_;
329
330 scoped_ptr<InterfaceEndpointClient> endpoint_client_;
331 scoped_ptr<Proxy> proxy_;
332
333 // |router_| (as well as other members above) is not initialized until
334 // read/write with the message pipe handle is needed. |handle_| and |waiter_|
335 // are valid between the Bind() call and the initialization of |router_|.
336 ScopedMessagePipeHandle handle_;
337 const MojoAsyncWaiter* waiter_;
338
339 uint32_t version_;
340
341 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
342 };
343
344 } // namespace internal
345 } // namespace mojo
346
347 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/lib/interface_ptr_internal.h ('k') | mojo/public/cpp/bindings/lib/multiplex_router.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698