OLD | NEW |
---|---|
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_ |
OLD | NEW |