Chromium Code Reviews| 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 |