OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ | 5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ |
6 #define MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ | 6 #define MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ |
7 | 7 |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 static RequestType GetProxy(ProxyType* proxy) { | 28 static RequestType GetProxy(ProxyType* proxy) { |
29 return mojo::GetProxy(proxy); | 29 return mojo::GetProxy(proxy); |
30 } | 30 } |
31 }; | 31 }; |
32 | 32 |
33 enum class BindingSetDispatchMode { | 33 enum class BindingSetDispatchMode { |
34 WITHOUT_CONTEXT, | 34 WITHOUT_CONTEXT, |
35 WITH_CONTEXT, | 35 WITH_CONTEXT, |
36 }; | 36 }; |
37 | 37 |
38 using BindingId = size_t; | |
39 | |
40 // Use this class to manage a set of bindings, which are automatically destroyed | 38 // Use this class to manage a set of bindings, which are automatically destroyed |
41 // and removed from the set when the pipe they are bound to is disconnected. | 39 // and removed from the set when the pipe they are bound to is disconnected. |
42 template <typename Interface, typename BindingType = Binding<Interface>> | 40 template <typename Interface, typename BindingType = Binding<Interface>> |
43 class BindingSet { | 41 class BindingSet { |
44 public: | 42 public: |
45 using PreDispatchCallback = base::Callback<void(void*)>; | |
46 using Traits = BindingSetTraits<BindingType>; | 43 using Traits = BindingSetTraits<BindingType>; |
47 using ProxyType = typename Traits::ProxyType; | 44 using ProxyType = typename Traits::ProxyType; |
48 using RequestType = typename Traits::RequestType; | 45 using RequestType = typename Traits::RequestType; |
49 | 46 |
50 BindingSet() : BindingSet(BindingSetDispatchMode::WITHOUT_CONTEXT) {} | 47 BindingSet() : BindingSet(BindingSetDispatchMode::WITHOUT_CONTEXT) {} |
51 | 48 |
52 // Constructs a new BindingSet operating in |dispatch_mode|. If |WITH_CONTEXT| | 49 // Constructs a new BindingSet operating in |dispatch_mode|. If |WITH_CONTEXT| |
53 // is used, AddBinding() supports a |context| argument, and dispatch_context() | 50 // is used, AddBinding() supports a |context| argument, and dispatch_context() |
54 // may be called during message or error dispatch to identify which specific | 51 // may be called during message or error dispatch to identify which specific |
55 // binding received the message or error. | 52 // binding received the message or error. |
56 explicit BindingSet(BindingSetDispatchMode dispatch_mode) | 53 explicit BindingSet(BindingSetDispatchMode dispatch_mode) |
57 : dispatch_mode_(dispatch_mode) {} | 54 : dispatch_mode_(dispatch_mode) {} |
58 | 55 |
59 void set_connection_error_handler(const base::Closure& error_handler) { | 56 void set_connection_error_handler(const base::Closure& error_handler) { |
60 error_handler_ = error_handler; | 57 error_handler_ = error_handler; |
61 } | 58 } |
62 | 59 |
63 // Sets a callback to be invoked immediately before dispatching any message or | |
64 // error received by any of the bindings in the set. This may only be used | |
65 // if the set was constructed with |BindingSetDispatchMode::WITH_CONTEXT|. | |
66 // |handler| is passed the context associated with the binding which received | |
67 // the message or event about to be dispatched. | |
68 void set_pre_dispatch_handler(const PreDispatchCallback& handler) { | |
69 DCHECK(SupportsContext()); | |
70 pre_dispatch_handler_ = handler; | |
71 } | |
72 | |
73 // Adds a new binding to the set which binds |request| to |impl|. If |context| | 60 // Adds a new binding to the set which binds |request| to |impl|. If |context| |
74 // is non-null, dispatch_context() will reflect this value during the extent | 61 // is non-null, dispatch_context() will reflect this value during the extent |
75 // of any message or error dispatch targeting this specific binding. Note that | 62 // of any message or error dispatch targeting this specific binding. Note that |
76 // |context| may only be non-null if the BindingSet was constructed with | 63 // |context| may only be non-null if the BindingSet was constructed with |
77 // |BindingSetDispatchMode::WITH_CONTEXT|. | 64 // |BindingSetDispatchMode::WITH_CONTEXT|. |
78 BindingId AddBinding(Interface* impl, | 65 void AddBinding(Interface* impl, |
79 RequestType request, | 66 RequestType request, |
80 void* context = nullptr) { | 67 void* context = nullptr) { |
81 DCHECK(!context || SupportsContext()); | 68 DCHECK(!context || SupportsContext()); |
82 BindingId id = next_binding_id_++; | |
83 DCHECK_GE(next_binding_id_, 0u); | |
84 std::unique_ptr<Entry> entry = | 69 std::unique_ptr<Entry> entry = |
85 base::MakeUnique<Entry>(impl, std::move(request), this, id, context); | 70 base::MakeUnique<Entry>(impl, std::move(request), this, context); |
86 bindings_.insert(std::make_pair(id, std::move(entry))); | 71 bindings_.insert(std::make_pair(entry.get(), std::move(entry))); |
87 return id; | |
88 } | |
89 | |
90 // Removes a binding from the set. Note that this is safe to call even if the | |
91 // binding corresponding to |id| has already been removed. | |
92 // | |
93 // Returns |true| if the binding was removed and |false| if it didn't exist. | |
94 bool RemoveBinding(BindingId id) { | |
95 auto it = bindings_.find(id); | |
96 if (it == bindings_.end()) | |
97 return false; | |
98 bindings_.erase(it); | |
99 return true; | |
100 } | 72 } |
101 | 73 |
102 // Returns a proxy bound to one end of a pipe whose other end is bound to | 74 // Returns a proxy bound to one end of a pipe whose other end is bound to |
103 // |this|. If |id_storage| is not null, |*id_storage| will be set to the ID | 75 // |this|. |
104 // of the added binding. | 76 ProxyType CreateInterfacePtrAndBind(Interface* impl) { |
105 ProxyType CreateInterfacePtrAndBind(Interface* impl, | |
106 BindingId* id_storage = nullptr) { | |
107 ProxyType proxy; | 77 ProxyType proxy; |
108 BindingId id = AddBinding(impl, Traits::GetProxy(&proxy)); | 78 AddBinding(impl, Traits::GetProxy(&proxy)); |
109 if (id_storage) | |
110 *id_storage = id; | |
111 return proxy; | 79 return proxy; |
112 } | 80 } |
113 | 81 |
114 void CloseAllBindings() { bindings_.clear(); } | 82 void CloseAllBindings() { bindings_.clear(); } |
115 | 83 |
116 bool empty() const { return bindings_.empty(); } | 84 bool empty() const { return bindings_.empty(); } |
117 | 85 |
118 // Implementations may call this when processing a dispatched message or | 86 // Implementations may call this when processing a dispatched message or |
119 // error. During the extent of message or error dispatch, this will return the | 87 // error. During the extent of message or error dispatch, this will return the |
120 // context associated with the specific binding which received the message or | 88 // context associated with the specific binding which received the message or |
(...skipping 13 matching lines...) Expand all Loading... |
134 } | 102 } |
135 | 103 |
136 private: | 104 private: |
137 friend class Entry; | 105 friend class Entry; |
138 | 106 |
139 class Entry { | 107 class Entry { |
140 public: | 108 public: |
141 Entry(Interface* impl, | 109 Entry(Interface* impl, |
142 RequestType request, | 110 RequestType request, |
143 BindingSet* binding_set, | 111 BindingSet* binding_set, |
144 BindingId binding_id, | |
145 void* context) | 112 void* context) |
146 : binding_(impl, std::move(request)), | 113 : binding_(impl, std::move(request)), |
147 binding_set_(binding_set), | 114 binding_set_(binding_set), |
148 binding_id_(binding_id), | |
149 context_(context) { | 115 context_(context) { |
150 if (binding_set->SupportsContext()) | 116 if (binding_set->SupportsContext()) |
151 binding_.AddFilter(base::MakeUnique<DispatchFilter>(this)); | 117 binding_.AddFilter(base::MakeUnique<DispatchFilter>(this)); |
152 binding_.set_connection_error_handler(base::Bind( | 118 binding_.set_connection_error_handler(base::Bind( |
153 &Entry::OnConnectionError, base::Unretained(this))); | 119 &Entry::OnConnectionError, base::Unretained(this))); |
154 } | 120 } |
155 | 121 |
156 void FlushForTesting() { binding_.FlushForTesting(); } | 122 void FlushForTesting() { binding_.FlushForTesting(); } |
157 | 123 |
158 private: | 124 private: |
(...skipping 15 matching lines...) Expand all Loading... |
174 }; | 140 }; |
175 | 141 |
176 void WillDispatch() { | 142 void WillDispatch() { |
177 DCHECK(binding_set_->SupportsContext()); | 143 DCHECK(binding_set_->SupportsContext()); |
178 binding_set_->SetDispatchContext(context_); | 144 binding_set_->SetDispatchContext(context_); |
179 } | 145 } |
180 | 146 |
181 void OnConnectionError() { | 147 void OnConnectionError() { |
182 if (binding_set_->SupportsContext()) | 148 if (binding_set_->SupportsContext()) |
183 WillDispatch(); | 149 WillDispatch(); |
184 binding_set_->OnConnectionError(binding_id_); | 150 binding_set_->OnConnectionError(this); |
185 } | 151 } |
186 | 152 |
187 BindingType binding_; | 153 BindingType binding_; |
188 BindingSet* const binding_set_; | 154 BindingSet* const binding_set_; |
189 const BindingId binding_id_; | |
190 void* const context_; | 155 void* const context_; |
191 | 156 |
192 DISALLOW_COPY_AND_ASSIGN(Entry); | 157 DISALLOW_COPY_AND_ASSIGN(Entry); |
193 }; | 158 }; |
194 | 159 |
195 void SetDispatchContext(void* context) { | 160 void SetDispatchContext(void* context) { |
196 DCHECK(SupportsContext()); | 161 DCHECK(SupportsContext()); |
197 dispatch_context_ = context; | 162 dispatch_context_ = context; |
198 if (!pre_dispatch_handler_.is_null()) | |
199 pre_dispatch_handler_.Run(context); | |
200 } | 163 } |
201 | 164 |
202 bool SupportsContext() const { | 165 bool SupportsContext() const { |
203 return dispatch_mode_ == BindingSetDispatchMode::WITH_CONTEXT; | 166 return dispatch_mode_ == BindingSetDispatchMode::WITH_CONTEXT; |
204 } | 167 } |
205 | 168 |
206 void OnConnectionError(BindingId id) { | 169 void OnConnectionError(Entry* entry) { |
207 auto it = bindings_.find(id); | 170 auto it = bindings_.find(entry); |
208 DCHECK(it != bindings_.end()); | 171 DCHECK(it != bindings_.end()); |
209 bindings_.erase(it); | 172 bindings_.erase(it); |
210 | 173 |
211 if (!error_handler_.is_null()) | 174 if (!error_handler_.is_null()) |
212 error_handler_.Run(); | 175 error_handler_.Run(); |
213 } | 176 } |
214 | 177 |
215 BindingSetDispatchMode dispatch_mode_; | 178 BindingSetDispatchMode dispatch_mode_; |
216 base::Closure error_handler_; | 179 base::Closure error_handler_; |
217 PreDispatchCallback pre_dispatch_handler_; | 180 std::map<Entry*, std::unique_ptr<Entry>> bindings_; |
218 BindingId next_binding_id_ = 0; | |
219 std::map<BindingId, std::unique_ptr<Entry>> bindings_; | |
220 void* dispatch_context_ = nullptr; | 181 void* dispatch_context_ = nullptr; |
221 | 182 |
222 DISALLOW_COPY_AND_ASSIGN(BindingSet); | 183 DISALLOW_COPY_AND_ASSIGN(BindingSet); |
223 }; | 184 }; |
224 | 185 |
225 } // namespace mojo | 186 } // namespace mojo |
226 | 187 |
227 #endif // MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ | 188 #endif // MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ |
OLD | NEW |