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

Side by Side Diff: mojo/public/cpp/bindings/binding_set.h

Issue 2283543002: Add support for dispatch contexts on BindingSet (Closed)
Patch Set: . Created 4 years, 3 months 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
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 <algorithm>
9 #include <utility> 8 #include <utility>
10 #include <vector>
11 9
12 #include "base/bind.h" 10 #include "base/bind.h"
13 #include "base/callback.h" 11 #include "base/callback.h"
14 #include "base/macros.h" 12 #include "base/macros.h"
15 #include "base/memory/weak_ptr.h"
16 #include "mojo/public/cpp/bindings/binding.h" 13 #include "mojo/public/cpp/bindings/binding.h"
14 #include "mojo/public/cpp/bindings/interface_ptr.h"
15 #include "mojo/public/cpp/bindings/interface_request.h"
16 #include "mojo/public/cpp/bindings/message.h"
17 17
18 namespace mojo { 18 namespace mojo {
19 19
20 template <typename BindingType>
21 struct BindingSetTraits;
22
23 template <typename Interface>
24 struct BindingSetTraits<Binding<Interface>> {
25 using ProxyType = InterfacePtr<Interface>;
26 using RequestType = InterfaceRequest<Interface>;
27
28 static RequestType GetProxy(ProxyType* proxy) {
29 return mojo::GetProxy(proxy);
30 }
31 };
32
33 enum class BindingSetDispatchMode {
34 WITHOUT_CONTEXT,
35 WITH_CONTEXT,
36 };
37
20 // 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
21 // 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.
22 template <typename Interface> 40 template <typename Interface, typename BindingType = Binding<Interface>>
23 class BindingSet { 41 class BindingSet {
24 public: 42 public:
25 BindingSet() {} 43 using Traits = BindingSetTraits<BindingType>;
26 ~BindingSet() { CloseAllBindings(); } 44 using ProxyType = typename Traits::ProxyType;
45 using RequestType = typename Traits::RequestType;
46
47 BindingSet() : BindingSet(BindingSetDispatchMode::WITHOUT_CONTEXT) {}
48
49 // Constructs a new BindingSet operating in |dispatch_mode|. If |WITH_CONTEXT|
50 // is used, AddBinding() supports a |context| argument, and dispatch_context()
51 // may be called during message or error dispatch to identify which specific
52 // binding received the message or error.
53 explicit BindingSet(BindingSetDispatchMode dispatch_mode)
54 : dispatch_mode_(dispatch_mode) {}
27 55
28 void set_connection_error_handler(const base::Closure& error_handler) { 56 void set_connection_error_handler(const base::Closure& error_handler) {
29 error_handler_ = error_handler; 57 error_handler_ = error_handler;
30 } 58 }
31 59
32 void AddBinding(Interface* impl, InterfaceRequest<Interface> request) { 60 // Adds a new binding to the set which binds |request| to |impl|. If |context|
33 auto binding = new Element(impl, std::move(request)); 61 // is non-null, dispatch_context() will reflect this value during the extent
34 binding->set_connection_error_handler( 62 // of any message or error dispatch targeting this specific binding. Note that
35 base::Bind(&BindingSet::OnConnectionError, base::Unretained(this))); 63 // |context| may only be non-null if the BindingSet was constructed with
36 bindings_.push_back(binding->GetWeakPtr()); 64 // |BindingSetDispatchMode::WITH_CONTEXT|.
65 void AddBinding(Interface* impl,
66 RequestType request,
67 void* context = nullptr) {
68 DCHECK(!context || SupportsContext());
69 std::unique_ptr<Entry> entry =
70 base::MakeUnique<Entry>(impl, std::move(request), this, context);
71 bindings_.insert(std::make_pair(entry.get(), std::move(entry)));
37 } 72 }
38 73
39 // Returns an InterfacePtr bound to one end of a pipe whose other end is 74 // Returns a proxy bound to one end of a pipe whose other end is bound to
40 // bound to |this|. 75 // |this|.
41 InterfacePtr<Interface> CreateInterfacePtrAndBind(Interface* impl) { 76 ProxyType CreateInterfacePtrAndBind(Interface* impl) {
42 InterfacePtr<Interface> interface_ptr; 77 ProxyType proxy;
43 AddBinding(impl, GetProxy(&interface_ptr)); 78 AddBinding(impl, Traits::GetProxy(&proxy));
44 return interface_ptr; 79 return proxy;
45 } 80 }
46 81
47 void CloseAllBindings() { 82 void CloseAllBindings() { bindings_.clear(); }
48 for (const auto& it : bindings_) {
49 if (it) {
50 it->Close();
51 delete it.get();
52 }
53 }
54 bindings_.clear();
55 }
56 83
57 bool empty() const { return bindings_.empty(); } 84 bool empty() const { return bindings_.empty(); }
58 85
86 // Implementations may call this when processing a dispatched message or
87 // error. During the extent of message or error dispatch, this will return the
88 // context associated with the specific binding which received the message or
89 // error. Use AddBinding() to associated a context with a specific binding.
90 //
91 // Note that this may ONLY be called if the BindingSet was constructed with
92 // |BindingSetDispatchMode::WITH_CONTEXT|.
93 void* dispatch_context() const {
94 DCHECK(SupportsContext());
95 return dispatch_context_;
96 }
97
59 private: 98 private:
60 class Element { 99 friend class Entry;
100
101 class Entry {
61 public: 102 public:
62 Element(Interface* impl, InterfaceRequest<Interface> request) 103 Entry(Interface* impl,
63 : binding_(impl, std::move(request)), weak_ptr_factory_(this) { 104 RequestType request,
64 binding_.set_connection_error_handler( 105 BindingSet* binding_set,
65 base::Bind(&Element::OnConnectionError, base::Unretained(this))); 106 void* context)
66 } 107 : binding_(impl, std::move(request)),
67 108 binding_set_(binding_set),
68 ~Element() {} 109 context_(context) {
69 110 if (binding_set->SupportsContext())
70 void set_connection_error_handler(const base::Closure& error_handler) { 111 binding_.AddFilter(base::MakeUnique<DispatchFilter>(this));
71 error_handler_ = error_handler; 112 binding_.set_connection_error_handler(base::Bind(
72 } 113 &Entry::OnConnectionError, base::Unretained(this)));
73
74 base::WeakPtr<Element> GetWeakPtr() {
75 return weak_ptr_factory_.GetWeakPtr();
76 }
77
78 void Close() { binding_.Close(); }
79
80 void OnConnectionError() {
81 base::Closure error_handler = error_handler_;
82 delete this;
83 if (!error_handler.is_null())
84 error_handler.Run();
85 } 114 }
86 115
87 private: 116 private:
88 Binding<Interface> binding_; 117 class DispatchFilter : public MessageReceiver {
89 base::Closure error_handler_; 118 public:
90 base::WeakPtrFactory<Element> weak_ptr_factory_; 119 explicit DispatchFilter(Entry* entry) : entry_(entry) {}
120 ~DispatchFilter() override {}
91 121
92 DISALLOW_COPY_AND_ASSIGN(Element); 122 private:
123 // MessageReceiver:
124 bool Accept(Message* message) override {
125 entry_->WillDispatch();
126 return true;
127 }
128
129 Entry* entry_;
130
131 DISALLOW_COPY_AND_ASSIGN(DispatchFilter);
132 };
133
134 void WillDispatch() {
135 if (binding_set_->SupportsContext())
yzshen1 2016/08/26 18:11:28 nit: we could move this check out of WillDispatch(
Ken Rockot(use gerrit already) 2016/08/26 20:15:01 Done
136 binding_set_->SetDispatchContext(context_);
137 }
138
139 void OnConnectionError() {
140 WillDispatch();
141 binding_set_->OnConnectionError(this);
142 }
143
144 BindingType binding_;
145 BindingSet* const binding_set_;
146 void* const context_;
147
148 DISALLOW_COPY_AND_ASSIGN(Entry);
93 }; 149 };
94 150
95 void OnConnectionError() { 151 void SetDispatchContext(void* context) {
96 // Clear any deleted bindings. 152 DCHECK(SupportsContext());
97 bindings_.erase(std::remove_if(bindings_.begin(), bindings_.end(), 153 dispatch_context_ = context;
98 [](const base::WeakPtr<Element>& p) { 154 }
99 return p.get() == nullptr; 155
100 }), 156 bool SupportsContext() const {
101 bindings_.end()); 157 return dispatch_mode_ == BindingSetDispatchMode::WITH_CONTEXT;
158 }
159
160 void OnConnectionError(Entry* entry) {
161 auto it = bindings_.find(entry);
162 DCHECK(it != bindings_.end());
163 bindings_.erase(it);
102 164
103 if (!error_handler_.is_null()) 165 if (!error_handler_.is_null())
104 error_handler_.Run(); 166 error_handler_.Run();
105 } 167 }
106 168
169 BindingSetDispatchMode dispatch_mode_;
107 base::Closure error_handler_; 170 base::Closure error_handler_;
108 std::vector<base::WeakPtr<Element>> bindings_; 171 std::map<Entry*, std::unique_ptr<Entry>> bindings_;
172 void* dispatch_context_ = nullptr;
109 173
110 DISALLOW_COPY_AND_ASSIGN(BindingSet); 174 DISALLOW_COPY_AND_ASSIGN(BindingSet);
111 }; 175 };
112 176
113 } // namespace mojo 177 } // namespace mojo
114 178
115 #endif // MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_ 179 #endif // MOJO_PUBLIC_CPP_BINDINGS_BINDING_SET_H_
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/associated_binding_set.h ('k') | mojo/public/cpp/bindings/lib/binding_state.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698