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

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 kUsesMultiplexRouter>
sky 2015/11/24 22:20:45 Same naming comment here.
yzshen1 2015/11/25 00:26:36 Done.
32 class InterfacePtrState;
33
34 template <typename Interface>
35 class InterfacePtrState<Interface, false> {
sky 2015/11/24 22:20:45 Again, please add descriptions for all classes.
yzshen1 2015/11/25 00:26:36 Done.
36 public:
37 InterfacePtrState()
38 : proxy_(nullptr), router_(nullptr), waiter_(nullptr), version_(0u) {}
39
40 ~InterfacePtrState() {
41 // Destruction order matters here. We delete |proxy_| first, even though
42 // |router_| may have a reference to it, so that destructors for any request
43 // callbacks still pending can interact with the InterfacePtr.
44 delete proxy_;
45 delete router_;
46 }
47
48 Interface* instance() {
49 ConfigureProxyIfNecessary();
50
51 // This will be null if the object is not bound.
52 return proxy_;
53 }
54
55 uint32_t version() const { return version_; }
56
57 void QueryVersion(const Callback<void(uint32_t)>& callback) {
58 ConfigureProxyIfNecessary();
59
60 // It is safe to capture |this| because the callback won't be run after this
61 // object goes away.
62 auto callback_wrapper = [this, callback](uint32_t version) {
63 this->version_ = version;
64 callback.Run(version);
65 };
66
67 // Do a static cast in case the interface contains methods with the same
68 // name.
69 static_cast<ControlMessageProxy*>(proxy_)->QueryVersion(callback_wrapper);
sky 2015/11/24 22:20:45 How do you know the callback happens while this is
yzshen1 2015/11/25 00:26:36 If this object goes away, the callback is not call
70 }
71
72 void RequireVersion(uint32_t version) {
73 ConfigureProxyIfNecessary();
74
75 if (version <= version_)
76 return;
77
78 version_ = version;
79 // Do a static cast in case the interface contains methods with the same
80 // name.
81 static_cast<ControlMessageProxy*>(proxy_)->RequireVersion(version);
82 }
83
84 void Swap(InterfacePtrState* other) {
85 using std::swap;
86 swap(other->proxy_, proxy_);
87 swap(other->router_, router_);
88 handle_.swap(other->handle_);
89 swap(other->waiter_, waiter_);
90 swap(other->version_, version_);
91 }
92
93 void Bind(InterfacePtrInfo<Interface> info, const MojoAsyncWaiter* waiter) {
94 DCHECK(!proxy_);
95 DCHECK(!router_);
96 DCHECK(!handle_.is_valid());
97 DCHECK(!waiter_);
98 DCHECK_EQ(0u, version_);
99 DCHECK(info.is_valid());
100
101 handle_ = info.PassHandle();
102 waiter_ = waiter;
103 version_ = info.version();
104 }
105
106 bool WaitForIncomingResponse() {
107 ConfigureProxyIfNecessary();
108
109 DCHECK(router_);
110 return router_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
111 }
112
113 // After this method is called, the object is in an invalid state and
114 // shouldn't be reused.
115 InterfacePtrInfo<Interface> PassInterface() {
116 return InterfacePtrInfo<Interface>(
117 router_ ? router_->PassMessagePipe() : handle_.Pass(), version_);
118 }
119
120 bool is_bound() const { return handle_.is_valid() || router_; }
121
122 bool encountered_error() const {
123 return router_ ? router_->encountered_error() : false;
124 }
125
126 void set_connection_error_handler(const Closure& error_handler) {
127 ConfigureProxyIfNecessary();
128
129 DCHECK(router_);
130 router_->set_connection_error_handler(error_handler);
131 }
132
133 // Returns true if bound and awaiting a response to a message.
134 bool has_pending_callbacks() const {
135 return router_ && router_->has_pending_responders();
136 }
137
138 AssociatedGroup* associated_group() { return nullptr; }
139
140 void EnableTestingMode() {
141 ConfigureProxyIfNecessary();
142 router_->EnableTestingMode();
143 }
144
145 private:
146 using Proxy = typename Interface::Proxy_;
147
148 void ConfigureProxyIfNecessary() {
149 // The proxy has been configured.
150 if (proxy_) {
151 DCHECK(router_);
152 return;
153 }
154 // The object hasn't been bound.
155 if (!waiter_) {
156 DCHECK(!handle_.is_valid());
157 return;
158 }
159
160 FilterChain filters;
161 filters.Append<MessageHeaderValidator>();
162 filters.Append<typename Interface::ResponseValidator_>();
163
164 router_ = new Router(handle_.Pass(), filters.Pass(), waiter_);
165 waiter_ = nullptr;
166
167 proxy_ = new Proxy(router_);
168 }
169
170 Proxy* proxy_;
171 Router* router_;
172
173 // |proxy_| and |router_| are not initialized until read/write with the
174 // message pipe handle is needed. |handle_| and |waiter_| are valid between
175 // the Bind() call and the initialization of |proxy_| and |router_|.
176 ScopedMessagePipeHandle handle_;
177 const MojoAsyncWaiter* waiter_;
178
179 uint32_t version_;
180
181 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
182 };
183
184 template <typename Interface>
185 class InterfacePtrState<Interface, true> {
186 public:
187 InterfacePtrState() : waiter_(nullptr), version_(0u) {}
188
189 ~InterfacePtrState() {
190 endpoint_client_.reset();
191 proxy_.reset();
192 if (router_)
193 router_->CloseMessagePipe();
194 }
195
196 Interface* instance() {
197 ConfigureProxyIfNecessary();
198
199 // This will be null if the object is not bound.
200 return proxy_.get();
201 }
202
203 uint32_t version() const { return version_; }
204
205 void QueryVersion(const Callback<void(uint32_t)>& callback) {
206 ConfigureProxyIfNecessary();
207
208 // It is safe to capture |this| because the callback won't be run after this
209 // object goes away.
210 auto callback_wrapper = [this, callback](uint32_t version) {
211 this->version_ = version;
212 callback.Run(version);
213 };
214
215 // Do a static cast in case the interface contains methods with the same
216 // name.
217 static_cast<ControlMessageProxy*>(proxy_.get())
218 ->QueryVersion(callback_wrapper);
219 }
220
221 void RequireVersion(uint32_t version) {
222 ConfigureProxyIfNecessary();
223
224 if (version <= version_)
225 return;
226
227 version_ = version;
228 // Do a static cast in case the interface contains methods with the same
229 // name.
230 static_cast<ControlMessageProxy*>(proxy_.get())->RequireVersion(version);
231 }
232
233 void Swap(InterfacePtrState* other) {
234 using std::swap;
235 swap(other->router_, router_);
236 swap(other->endpoint_client_, endpoint_client_);
237 swap(other->proxy_, proxy_);
238 handle_.swap(other->handle_);
239 swap(other->waiter_, waiter_);
240 swap(other->version_, version_);
241 }
242
243 void Bind(InterfacePtrInfo<Interface> info, const MojoAsyncWaiter* waiter) {
244 DCHECK(!router_);
245 DCHECK(!endpoint_client_);
246 DCHECK(!proxy_);
247 DCHECK(!handle_.is_valid());
248 DCHECK(!waiter_);
249 DCHECK_EQ(0u, version_);
250 DCHECK(info.is_valid());
251
252 handle_ = info.PassHandle();
253 waiter_ = waiter;
254 version_ = info.version();
255 }
256
257 bool WaitForIncomingResponse() {
258 ConfigureProxyIfNecessary();
259
260 DCHECK(router_);
261 return router_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
262 }
263
264 // After this method is called, the object is in an invalid state and
265 // shouldn't be reused.
266 InterfacePtrInfo<Interface> PassInterface() {
267 endpoint_client_.reset();
268 proxy_.reset();
269 return InterfacePtrInfo<Interface>(
270 router_ ? router_->PassMessagePipe() : handle_.Pass(), version_);
271 }
272
273 bool is_bound() const { return handle_.is_valid() || endpoint_client_; }
274
275 bool encountered_error() const {
276 return endpoint_client_ ? endpoint_client_->encountered_error() : false;
277 }
278
279 void set_connection_error_handler(const Closure& error_handler) {
280 ConfigureProxyIfNecessary();
281
282 DCHECK(endpoint_client_);
283 endpoint_client_->set_connection_error_handler(error_handler);
284 }
285
286 // Returns true if bound and awaiting a response to a message.
287 bool has_pending_callbacks() const {
288 return endpoint_client_ && endpoint_client_->has_pending_responders();
289 }
290
291 AssociatedGroup* associated_group() {
292 ConfigureProxyIfNecessary();
293 return endpoint_client_->associated_group();
294 }
295
296 void EnableTestingMode() {
297 ConfigureProxyIfNecessary();
298 router_->EnableTestingMode();
299 }
300
301 private:
302 using Proxy = typename Interface::Proxy_;
303
304 void ConfigureProxyIfNecessary() {
305 // The proxy has been configured.
306 if (proxy_) {
307 DCHECK(router_);
308 DCHECK(endpoint_client_);
309 return;
310 }
311 // The object hasn't been bound.
312 if (!waiter_) {
313 DCHECK(!handle_.is_valid());
314 return;
315 }
316
317 router_ = new MultiplexRouter(true, handle_.Pass(), waiter_);
318 endpoint_client_.reset(new InterfaceEndpointClient(
319 router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr,
320 make_scoped_ptr(new typename Interface::ResponseValidator_())));
321 proxy_.reset(new Proxy(endpoint_client_.get(), endpoint_client_->router()));
322
323 waiter_ = nullptr;
324 }
325
326 scoped_refptr<MultiplexRouter> router_;
327
328 scoped_ptr<InterfaceEndpointClient> endpoint_client_;
329 scoped_ptr<Proxy> proxy_;
330
331 // |router_| (as well as other members above) is not initialized until
332 // read/write with the message pipe handle is needed. |handle_| and |waiter_|
333 // are valid between the Bind() call and the initialization of |router_|.
334 ScopedMessagePipeHandle handle_;
335 const MojoAsyncWaiter* waiter_;
336
337 uint32_t version_;
338
339 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState);
340 };
341
342 } // namespace internal
343 } // namespace mojo
344
345 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698