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

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

Issue 2668153003: Mojo C++ Bindings: Eliminate unbound ThreadSafeInterfacePtr (Closed)
Patch Set: . Created 3 years, 10 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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_THREAD_SAFE_INTERFACE_PTR_H_ 5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
7 7
8 #include <memory> 8 #include <memory>
9 9
10 #include "base/macros.h" 10 #include "base/macros.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/memory/ref_counted.h" 12 #include "base/memory/ref_counted.h"
13 #include "base/task_runner.h" 13 #include "base/task_runner.h"
14 #include "base/threading/thread_task_runner_handle.h" 14 #include "base/threading/thread_task_runner_handle.h"
15 #include "mojo/public/cpp/bindings/associated_interface_ptr.h" 15 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
16 #include "mojo/public/cpp/bindings/interface_ptr.h" 16 #include "mojo/public/cpp/bindings/interface_ptr.h"
17 #include "mojo/public/cpp/bindings/message.h" 17 #include "mojo/public/cpp/bindings/message.h"
18 18
19 namespace mojo { 19 namespace mojo {
20 20
21 struct ThreadSafeInterfacePtrDeleter; 21 // Instances of this class may be used used from any thread to serialize
yzshen1 2017/02/07 00:06:27 nit: remove one redundant "used" please.
Ken Rockot(use gerrit already) 2017/02/07 01:25:32 Done
22 22 // |Interface| messages and forward them elsewhere. In general you should use
23 // ThreadSafeInterfacePtr and ThreadSafeAssociatedInterfacePtr are versions of 23 // one of the ThreadSafeInterfacePtrBase helper aliases defined below, but this
24 // InterfacePtr and AssociatedInterfacePtr that let callers invoke 24 // type may be useful if you need/want to manually manage the lifetime of the
25 // interface methods from any threads. Callbacks are received on the thread that 25 // underlying proxy object which will be used to ultimately send messages.
26 // performed the interface call. 26 template <typename Interface>
27 // 27 class ThreadSafeForwarder : public MessageReceiverWithResponder {
28 // To create a ThreadSafeInterfacePtr/ThreadSafeAssociatedInterfacePtr, first
29 // create a regular InterfacePtr/AssociatedInterfacePtr that
30 // you then provide to ThreadSafeInterfacePtr/AssociatedInterfacePtr::Create.
31 // You can then call methods on the
32 // ThreadSafeInterfacePtr/AssociatedInterfacePtr instance from any thread.
33 //
34 // Ex for ThreadSafeInterfacePtr:
35 // frob::FrobinatorPtr frobinator;
36 // frob::FrobinatorImpl impl(MakeRequest(&frobinator));
37 // scoped_refptr<frob::ThreadSafeFrobinatorPtr> thread_safe_frobinator =
38 // frob::ThreadSafeFrobinatorPtr::Create(std::move(frobinator));
39 // (*thread_safe_frobinator)->FrobinateToTheMax();
40 //
41 // An alternate way is to create the ThreadSafeInterfacePtr unbound (not
42 // associated with an InterfacePtr) and call Bind() at a later time when the
43 // InterfacePtr becomes available. Note that you shouldn't call any interface
44 // methods on the ThreadSafeInterfacePtr before it is bound.
45
46 template <typename Interface, template <typename> class InterfacePtrType>
47 class ThreadSafeInterfacePtrBase
48 : public MessageReceiverWithResponder,
49 public base::RefCountedThreadSafe<
50 ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>,
51 ThreadSafeInterfacePtrDeleter> {
52 public: 28 public:
53 using ProxyType = typename Interface::Proxy_; 29 using ProxyType = typename Interface::Proxy_;
30 using ForwardMessageCallback = base::Callback<void(Message)>;
31 using ForwardMessageWithResponderCallback =
32 base::Callback<void(Message, std::unique_ptr<MessageReceiver>)>;
54 33
55 static scoped_refptr<ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>> 34 // Constructs a ThreadSafeForwarder through which Messages are forwarded to
56 Create(InterfacePtrType<Interface> interface_ptr) { 35 // |forward| or |forward_with_responder| by posting to |task_runner|.
57 scoped_refptr<ThreadSafeInterfacePtrBase> ptr( 36 //
58 new ThreadSafeInterfacePtrBase()); 37 // Any message sent through this forwarding interface will dispatch its reply,
59 return ptr->Bind(std::move(interface_ptr)) ? ptr : nullptr; 38 // if any, back to the thread which called the corresponding interface method.
60 } 39 ThreadSafeForwarder(
yzshen1 2017/02/07 00:06:27 (I could do this in my CL. Just to mention it to g
Ken Rockot(use gerrit already) 2017/02/07 01:25:32 OK - Seems reasonable to me. Almost makes me want
40 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
41 const ForwardMessageCallback& forward,
42 const ForwardMessageWithResponderCallback& forward_with_responder)
43 : proxy_(this), task_runner_(task_runner), forward_(forward),
44 forward_with_responder_(forward_with_responder) {}
61 45
62 // Creates a ThreadSafeInterfacePtrBase with no associated InterfacePtr. 46 ~ThreadSafeForwarder() override {}
63 // Call Bind() with the InterfacePtr once available, which must be called on
64 // the |bind_task_runner|.
65 // Providing the TaskRunner here allows you to post a task to
66 // |bind_task_runner| to do the bind and then immediately start calling
67 // methods on the returned interface.
68 static scoped_refptr<ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>>
69 CreateUnbound(
70 const scoped_refptr<base::SingleThreadTaskRunner>& bind_task_runner) {
71 scoped_refptr<ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>> ptr =
72 new ThreadSafeInterfacePtrBase();
73 ptr->interface_ptr_task_runner_ = bind_task_runner;
74 return ptr;
75 }
76 47
77 // Binds a ThreadSafeInterfacePtrBase previously created with CreateUnbound(). 48 ProxyType& proxy() { return proxy_; }
78 // This must be called on the thread that |interface_ptr| should be used.
79 // If created with CreateUnbound() that thread should be the same as the one
80 // provided at creation time.
81 bool Bind(InterfacePtrType<Interface> interface_ptr) {
82 DCHECK(!interface_ptr_task_runner_ ||
83 interface_ptr_task_runner_ == base::ThreadTaskRunnerHandle::Get());
84 if (!interface_ptr.is_bound()) {
85 LOG(ERROR) << "Attempting to bind a ThreadSafe[Associated]InterfacePtr "
86 "from an unbound InterfacePtr.";
87 return false;
88 }
89 interface_ptr_ = std::move(interface_ptr);
90 interface_ptr_task_runner_ = base::ThreadTaskRunnerHandle::Get();
91 return true;
92 }
93
94 ~ThreadSafeInterfacePtrBase() override {}
95
96 Interface* get() { return &proxy_; }
97 Interface* operator->() { return get(); }
98 Interface& operator*() { return *get(); }
99 49
100 private: 50 private:
101 friend class base::RefCountedThreadSafe<
102 ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>>;
103 friend struct ThreadSafeInterfacePtrDeleter;
104
105 ThreadSafeInterfacePtrBase() : proxy_(this), weak_ptr_factory_(this) {}
106
107 void DeleteOnCorrectThread() const {
108 if (interface_ptr_task_runner_ &&
109 !interface_ptr_task_runner_->BelongsToCurrentThread() &&
110 interface_ptr_task_runner_->DeleteSoon(FROM_HERE, this)) {
111 return;
112 }
113 delete this;
114 }
115
116 // MessageReceiverWithResponder implementation: 51 // MessageReceiverWithResponder implementation:
117 bool Accept(Message* message) override { 52 bool Accept(Message* message) override {
118 interface_ptr_task_runner_->PostTask( 53 task_runner_->PostTask(
119 FROM_HERE, 54 FROM_HERE, base::Bind(forward_, base::Passed(message)));
120 base::Bind(&ThreadSafeInterfacePtrBase::AcceptOnInterfacePtrThread,
121 weak_ptr_factory_.GetWeakPtr(),
122 base::Passed(std::move(*message))));
123 return true; 55 return true;
124 } 56 }
125 57
126 bool AcceptWithResponder(Message* message, 58 bool AcceptWithResponder(Message* message,
127 MessageReceiver* responder) override { 59 MessageReceiver* response_receiver) override {
128 auto forward_responder = base::MakeUnique<ForwardToCallingThread>( 60 auto responder = base::MakeUnique<ForwardToCallingThread>(
129 base::WrapUnique(responder)); 61 base::WrapUnique(response_receiver));
130 interface_ptr_task_runner_->PostTask( 62 task_runner_->PostTask(
131 FROM_HERE, base::Bind(&ThreadSafeInterfacePtrBase:: 63 FROM_HERE,
132 AcceptWithResponderOnInterfacePtrThread, 64 base::Bind(forward_with_responder_, base::Passed(message),
133 weak_ptr_factory_.GetWeakPtr(), 65 base::Passed(&responder)));
134 base::Passed(std::move(*message)),
135 base::Passed(std::move(forward_responder))));
136 return true; 66 return true;
137 } 67 }
138 68
139 void AcceptOnInterfacePtrThread(Message message) {
140 interface_ptr_.internal_state()->ForwardMessage(std::move(message));
141 }
142 void AcceptWithResponderOnInterfacePtrThread(
143 Message message,
144 std::unique_ptr<MessageReceiver> responder) {
145 interface_ptr_.internal_state()->ForwardMessageWithResponder(
146 std::move(message), std::move(responder));
147 }
148
149 class ForwardToCallingThread : public MessageReceiver { 69 class ForwardToCallingThread : public MessageReceiver {
150 public: 70 public:
151 explicit ForwardToCallingThread(std::unique_ptr<MessageReceiver> responder) 71 explicit ForwardToCallingThread(std::unique_ptr<MessageReceiver> responder)
152 : responder_(std::move(responder)), 72 : responder_(std::move(responder)),
153 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()) { 73 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
154 } 74 }
155 75
156 private: 76 private:
157 bool Accept(Message* message) { 77 bool Accept(Message* message) {
158 // The current instance will be deleted when this method returns, so we 78 // The current instance will be deleted when this method returns, so we
159 // have to relinquish the responder's ownership so it does not get 79 // have to relinquish the responder's ownership so it does not get
160 // deleted. 80 // deleted.
161 caller_task_runner_->PostTask(FROM_HERE, 81 caller_task_runner_->PostTask(FROM_HERE,
162 base::Bind(&ForwardToCallingThread::CallAcceptAndDeleteResponder, 82 base::Bind(&ForwardToCallingThread::CallAcceptAndDeleteResponder,
163 base::Passed(std::move(responder_)), 83 base::Passed(std::move(responder_)),
164 base::Passed(std::move(*message)))); 84 base::Passed(std::move(*message))));
165 return true; 85 return true;
166 } 86 }
167 87
168 static void CallAcceptAndDeleteResponder( 88 static void CallAcceptAndDeleteResponder(
169 std::unique_ptr<MessageReceiver> responder, 89 std::unique_ptr<MessageReceiver> responder,
170 Message message) { 90 Message message) {
171 ignore_result(responder->Accept(&message)); 91 ignore_result(responder->Accept(&message));
172 } 92 }
173 93
174 std::unique_ptr<MessageReceiver> responder_; 94 std::unique_ptr<MessageReceiver> responder_;
175 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; 95 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
176 }; 96 };
177 97
178 scoped_refptr<base::SingleThreadTaskRunner> interface_ptr_task_runner_;
179 ProxyType proxy_; 98 ProxyType proxy_;
180 InterfacePtrType<Interface> interface_ptr_; 99 const scoped_refptr<base::SequencedTaskRunner> task_runner_;
181 base::WeakPtrFactory<ThreadSafeInterfacePtrBase> weak_ptr_factory_; 100 const ForwardMessageCallback forward_;
101 const ForwardMessageWithResponderCallback forward_with_responder_;
102
103 DISALLOW_COPY_AND_ASSIGN(ThreadSafeForwarder);
182 }; 104 };
183 105
184 struct ThreadSafeInterfacePtrDeleter { 106 template <typename InterfacePtrType>
185 template <typename Interface, template <typename> class InterfacePtrType> 107 class ThreadSafeInterfacePtrBase :
186 static void Destruct( 108 public base::RefCountedThreadSafe<
187 const ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>* 109 ThreadSafeInterfacePtrBase<InterfacePtrType>> {
188 interface_ptr) { 110 public:
189 interface_ptr->DeleteOnCorrectThread(); 111 using InterfaceType = typename InterfacePtrType::InterfaceType;
112 using PtrInfoType = typename InterfacePtrType::PtrInfoType;
113
114 explicit ThreadSafeInterfacePtrBase(
115 std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder)
116 : forwarder_(std::move(forwarder)) {}
117
118 // Creates a ThreadSafeInterfacePtrBase wrapping an underlying non-thread-safe
119 // InterfacePtrType which is bound to the calling thread. All messages sent
120 // via this thread-safe proxy will internally be sent by first posting to this
121 // (the calling) thread's TaskRunner.
122 static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
123 InterfacePtrType interface_ptr) {
124 scoped_refptr<PtrWrapper> wrapper =
125 new PtrWrapper(std::move(interface_ptr));
126 return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder());
190 } 127 }
128
129 // Creates a ThreadSafeInterfacePtrBase which binds the underlying
130 // non-thread-safe InterfacePtrType on the specified TaskRunner. All messages
131 // sent via this thread-safe proxy will internally be sent by first posting to
132 // that TaskRunner.
133 static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
134 PtrInfoType ptr_info,
135 const scoped_refptr<base::SingleThreadTaskRunner>& bind_task_runner) {
136 scoped_refptr<PtrWrapper> wrapper =
137 new PtrWrapper(std::move(ptr_info), bind_task_runner);
138 return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder());
139 }
140
141 InterfaceType* get() { return &forwarder_->proxy(); }
142 InterfaceType* operator->() { return get(); }
143 InterfaceType& operator*() { return *get(); }
144
145 private:
146 friend class base::RefCountedThreadSafe<
147 ThreadSafeInterfacePtrBase<InterfacePtrType>>;
148
149 struct PtrWrapperDeleter;
150
151 // Helper class which owns an |InterfacePtrType| instance on an appropriate
152 // thread. This is kept alive as long its bound within some
153 // ThreadSafeForwarder's callbacks.
154 class PtrWrapper
155 : public base::RefCountedThreadSafe<PtrWrapper, PtrWrapperDeleter> {
156 public:
157 explicit PtrWrapper(InterfacePtrType ptr)
158 : PtrWrapper(base::ThreadTaskRunnerHandle::Get()) {
159 Bind(ptr.PassInterface());
yzshen1 2017/02/07 00:06:27 How about "ptr_ = std::move(ptr)"? This is more ef
Ken Rockot(use gerrit already) 2017/02/07 01:25:32 Done
160 }
161
162 PtrWrapper(PtrInfoType ptr_info,
163 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
164 : PtrWrapper(task_runner) {
165 task_runner_->PostTask(
166 FROM_HERE,
167 base::Bind(&PtrWrapper::Bind, this, base::Passed(&ptr_info)));
168 }
169
170 std::unique_ptr<ThreadSafeForwarder<InterfaceType>> CreateForwarder() {
171 return base::MakeUnique<ThreadSafeForwarder<InterfaceType>>(
172 task_runner_,
173 base::Bind(&PtrWrapper::Accept, this),
174 base::Bind(&PtrWrapper::AcceptWithResponder, this));
175 }
176
177 private:
178 friend class base::RefCountedThreadSafe<PtrWrapper>;
179 friend struct PtrWrapperDeleter;
180
181 PtrWrapper(const scoped_refptr<base::SequencedTaskRunner>& task_runner)
yzshen1 2017/02/07 00:06:27 explicit, please.
Ken Rockot(use gerrit already) 2017/02/07 01:25:32 Done
182 : task_runner_(task_runner) {}
183
184 ~PtrWrapper() {}
185
186 void Bind(PtrInfoType ptr_info) {
187 DCHECK(task_runner_->RunsTasksOnCurrentThread());
188 ptr_.Bind(std::move(ptr_info));
189 }
190
191 void Accept(Message message) {
192 ptr_.internal_state()->ForwardMessage(std::move(message));
193 }
194
195 void AcceptWithResponder(Message message,
196 std::unique_ptr<MessageReceiver> responder) {
197 ptr_.internal_state()->ForwardMessageWithResponder(
198 std::move(message), std::move(responder));
199 }
200
201 void DeleteOnCorrectThread() const {
202 if (!task_runner_->RunsTasksOnCurrentThread()) {
203 task_runner_->PostTask(
204 FROM_HERE,
205 base::Bind(&PtrWrapper::DeleteOnCorrectThread,
206 base::Unretained(this)));
yzshen1 2017/02/07 00:06:27 I think we could use "Unretained" here because no
Ken Rockot(use gerrit already) 2017/02/07 01:25:32 Yep, done
207 } else {
208 delete this;
209 }
210 }
211
212 InterfacePtrType ptr_;
213 const scoped_refptr<base::SequencedTaskRunner> task_runner_;
214
215 DISALLOW_COPY_AND_ASSIGN(PtrWrapper);
216 };
217
218 struct PtrWrapperDeleter {
219 static void Destruct(const PtrWrapper* interface_ptr) {
220 interface_ptr->DeleteOnCorrectThread();
221 }
222 };
223
224 ~ThreadSafeInterfacePtrBase() {}
225
226 const std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder_;
227
228 DISALLOW_COPY_AND_ASSIGN(ThreadSafeInterfacePtrBase);
191 }; 229 };
192 230
193 template <typename Interface> 231 template <typename Interface>
194 using ThreadSafeAssociatedInterfacePtr = 232 using ThreadSafeAssociatedInterfacePtr =
195 ThreadSafeInterfacePtrBase<Interface, AssociatedInterfacePtr>; 233 ThreadSafeInterfacePtrBase<AssociatedInterfacePtr<Interface>>;
196 234
197 template <typename Interface> 235 template <typename Interface>
198 using ThreadSafeInterfacePtr = 236 using ThreadSafeInterfacePtr =
199 ThreadSafeInterfacePtrBase<Interface, InterfacePtr>; 237 ThreadSafeInterfacePtrBase<InterfacePtr<Interface>>;
200 238
201 } // namespace mojo 239 } // namespace mojo
202 240
203 #endif // MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_ 241 #endif // MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698