| 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 from any thread to serialize |Interface| |
| 22 | 22 // messages and forward them elsewhere. In general you should use one of the |
| 23 // ThreadSafeInterfacePtr and ThreadSafeAssociatedInterfacePtr are versions of | 23 // ThreadSafeInterfacePtrBase helper aliases defined below, but this type may be |
| 24 // InterfacePtr and AssociatedInterfacePtr that let callers invoke | 24 // useful if you need/want to manually manage the lifetime of the underlying |
| 25 // interface methods from any threads. Callbacks are received on the thread that | 25 // 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( |
| 40 const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| 41 const ForwardMessageCallback& forward, |
| 42 const ForwardMessageWithResponderCallback& forward_with_responder) |
| 43 : proxy_(this), |
| 44 task_runner_(task_runner), |
| 45 forward_(forward), |
| 46 forward_with_responder_(forward_with_responder) {} |
| 61 | 47 |
| 62 // Creates a ThreadSafeInterfacePtrBase with no associated InterfacePtr. | 48 ~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 | 49 |
| 77 // Binds a ThreadSafeInterfacePtrBase previously created with CreateUnbound(). | 50 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 | 51 |
| 100 private: | 52 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: | 53 // MessageReceiverWithResponder implementation: |
| 117 bool Accept(Message* message) override { | 54 bool Accept(Message* message) override { |
| 118 interface_ptr_task_runner_->PostTask( | 55 task_runner_->PostTask(FROM_HERE, |
| 119 FROM_HERE, | 56 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; | 57 return true; |
| 124 } | 58 } |
| 125 | 59 |
| 126 bool AcceptWithResponder(Message* message, | 60 bool AcceptWithResponder(Message* message, |
| 127 MessageReceiver* responder) override { | 61 MessageReceiver* response_receiver) override { |
| 128 auto forward_responder = base::MakeUnique<ForwardToCallingThread>( | 62 auto responder = base::MakeUnique<ForwardToCallingThread>( |
| 129 base::WrapUnique(responder)); | 63 base::WrapUnique(response_receiver)); |
| 130 interface_ptr_task_runner_->PostTask( | 64 task_runner_->PostTask( |
| 131 FROM_HERE, base::Bind(&ThreadSafeInterfacePtrBase:: | 65 FROM_HERE, base::Bind(forward_with_responder_, base::Passed(message), |
| 132 AcceptWithResponderOnInterfacePtrThread, | 66 base::Passed(&responder))); |
| 133 weak_ptr_factory_.GetWeakPtr(), | |
| 134 base::Passed(std::move(*message)), | |
| 135 base::Passed(std::move(forward_responder)))); | |
| 136 return true; | 67 return true; |
| 137 } | 68 } |
| 138 | 69 |
| 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 { | 70 class ForwardToCallingThread : public MessageReceiver { |
| 150 public: | 71 public: |
| 151 explicit ForwardToCallingThread(std::unique_ptr<MessageReceiver> responder) | 72 explicit ForwardToCallingThread(std::unique_ptr<MessageReceiver> responder) |
| 152 : responder_(std::move(responder)), | 73 : responder_(std::move(responder)), |
| 153 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()) { | 74 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()) { |
| 154 } | 75 } |
| 155 | 76 |
| 156 private: | 77 private: |
| 157 bool Accept(Message* message) { | 78 bool Accept(Message* message) { |
| 158 // The current instance will be deleted when this method returns, so we | 79 // 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 | 80 // have to relinquish the responder's ownership so it does not get |
| 160 // deleted. | 81 // deleted. |
| 161 caller_task_runner_->PostTask(FROM_HERE, | 82 caller_task_runner_->PostTask(FROM_HERE, |
| 162 base::Bind(&ForwardToCallingThread::CallAcceptAndDeleteResponder, | 83 base::Bind(&ForwardToCallingThread::CallAcceptAndDeleteResponder, |
| 163 base::Passed(std::move(responder_)), | 84 base::Passed(std::move(responder_)), |
| 164 base::Passed(std::move(*message)))); | 85 base::Passed(std::move(*message)))); |
| 165 return true; | 86 return true; |
| 166 } | 87 } |
| 167 | 88 |
| 168 static void CallAcceptAndDeleteResponder( | 89 static void CallAcceptAndDeleteResponder( |
| 169 std::unique_ptr<MessageReceiver> responder, | 90 std::unique_ptr<MessageReceiver> responder, |
| 170 Message message) { | 91 Message message) { |
| 171 ignore_result(responder->Accept(&message)); | 92 ignore_result(responder->Accept(&message)); |
| 172 } | 93 } |
| 173 | 94 |
| 174 std::unique_ptr<MessageReceiver> responder_; | 95 std::unique_ptr<MessageReceiver> responder_; |
| 175 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; | 96 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; |
| 176 }; | 97 }; |
| 177 | 98 |
| 178 scoped_refptr<base::SingleThreadTaskRunner> interface_ptr_task_runner_; | |
| 179 ProxyType proxy_; | 99 ProxyType proxy_; |
| 180 InterfacePtrType<Interface> interface_ptr_; | 100 const scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 181 base::WeakPtrFactory<ThreadSafeInterfacePtrBase> weak_ptr_factory_; | 101 const ForwardMessageCallback forward_; |
| 102 const ForwardMessageWithResponderCallback forward_with_responder_; |
| 103 |
| 104 DISALLOW_COPY_AND_ASSIGN(ThreadSafeForwarder); |
| 182 }; | 105 }; |
| 183 | 106 |
| 184 struct ThreadSafeInterfacePtrDeleter { | 107 template <typename InterfacePtrType> |
| 185 template <typename Interface, template <typename> class InterfacePtrType> | 108 class ThreadSafeInterfacePtrBase |
| 186 static void Destruct( | 109 : public base::RefCountedThreadSafe< |
| 187 const ThreadSafeInterfacePtrBase<Interface, InterfacePtrType>* | 110 ThreadSafeInterfacePtrBase<InterfacePtrType>> { |
| 188 interface_ptr) { | 111 public: |
| 189 interface_ptr->DeleteOnCorrectThread(); | 112 using InterfaceType = typename InterfacePtrType::InterfaceType; |
| 113 using PtrInfoType = typename InterfacePtrType::PtrInfoType; |
| 114 |
| 115 explicit ThreadSafeInterfacePtrBase( |
| 116 std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder) |
| 117 : forwarder_(std::move(forwarder)) {} |
| 118 |
| 119 // Creates a ThreadSafeInterfacePtrBase wrapping an underlying non-thread-safe |
| 120 // InterfacePtrType which is bound to the calling thread. All messages sent |
| 121 // via this thread-safe proxy will internally be sent by first posting to this |
| 122 // (the calling) thread's TaskRunner. |
| 123 static scoped_refptr<ThreadSafeInterfacePtrBase> Create( |
| 124 InterfacePtrType interface_ptr) { |
| 125 scoped_refptr<PtrWrapper> wrapper = |
| 126 new PtrWrapper(std::move(interface_ptr)); |
| 127 return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder()); |
| 190 } | 128 } |
| 129 |
| 130 // Creates a ThreadSafeInterfacePtrBase which binds the underlying |
| 131 // non-thread-safe InterfacePtrType on the specified TaskRunner. All messages |
| 132 // sent via this thread-safe proxy will internally be sent by first posting to |
| 133 // that TaskRunner. |
| 134 static scoped_refptr<ThreadSafeInterfacePtrBase> Create( |
| 135 PtrInfoType ptr_info, |
| 136 const scoped_refptr<base::SingleThreadTaskRunner>& bind_task_runner) { |
| 137 scoped_refptr<PtrWrapper> wrapper = new PtrWrapper(bind_task_runner); |
| 138 wrapper->BindOnTaskRunner(std::move(ptr_info)); |
| 139 return new ThreadSafeInterfacePtrBase(wrapper->CreateForwarder()); |
| 140 } |
| 141 |
| 142 InterfaceType* get() { return &forwarder_->proxy(); } |
| 143 InterfaceType* operator->() { return get(); } |
| 144 InterfaceType& operator*() { return *get(); } |
| 145 |
| 146 private: |
| 147 friend class base::RefCountedThreadSafe< |
| 148 ThreadSafeInterfacePtrBase<InterfacePtrType>>; |
| 149 |
| 150 struct PtrWrapperDeleter; |
| 151 |
| 152 // Helper class which owns an |InterfacePtrType| instance on an appropriate |
| 153 // thread. This is kept alive as long its bound within some |
| 154 // ThreadSafeForwarder's callbacks. |
| 155 class PtrWrapper |
| 156 : public base::RefCountedThreadSafe<PtrWrapper, PtrWrapperDeleter> { |
| 157 public: |
| 158 explicit PtrWrapper(InterfacePtrType ptr) |
| 159 : PtrWrapper(base::ThreadTaskRunnerHandle::Get()) { |
| 160 ptr_ = std::move(ptr); |
| 161 } |
| 162 |
| 163 explicit PtrWrapper( |
| 164 const scoped_refptr<base::SequencedTaskRunner>& task_runner) |
| 165 : task_runner_(task_runner) {} |
| 166 |
| 167 void BindOnTaskRunner(PtrInfoType ptr_info) { |
| 168 task_runner_->PostTask(FROM_HERE, base::Bind(&PtrWrapper::Bind, this, |
| 169 base::Passed(&ptr_info))); |
| 170 } |
| 171 |
| 172 std::unique_ptr<ThreadSafeForwarder<InterfaceType>> CreateForwarder() { |
| 173 return base::MakeUnique<ThreadSafeForwarder<InterfaceType>>( |
| 174 task_runner_, base::Bind(&PtrWrapper::Accept, this), |
| 175 base::Bind(&PtrWrapper::AcceptWithResponder, this)); |
| 176 } |
| 177 |
| 178 private: |
| 179 friend struct PtrWrapperDeleter; |
| 180 |
| 181 ~PtrWrapper() {} |
| 182 |
| 183 void Bind(PtrInfoType ptr_info) { |
| 184 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 185 ptr_.Bind(std::move(ptr_info)); |
| 186 } |
| 187 |
| 188 void Accept(Message message) { |
| 189 ptr_.internal_state()->ForwardMessage(std::move(message)); |
| 190 } |
| 191 |
| 192 void AcceptWithResponder(Message message, |
| 193 std::unique_ptr<MessageReceiver> responder) { |
| 194 ptr_.internal_state()->ForwardMessageWithResponder(std::move(message), |
| 195 std::move(responder)); |
| 196 } |
| 197 |
| 198 void DeleteOnCorrectThread() const { |
| 199 if (!task_runner_->RunsTasksOnCurrentThread()) { |
| 200 // NOTE: This is only called when there are no more references to |
| 201 // |this|, so binding it unretained is both safe and necessary. |
| 202 task_runner_->PostTask(FROM_HERE, |
| 203 base::Bind(&PtrWrapper::DeleteOnCorrectThread, |
| 204 base::Unretained(this))); |
| 205 } else { |
| 206 delete this; |
| 207 } |
| 208 } |
| 209 |
| 210 InterfacePtrType ptr_; |
| 211 const scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 212 |
| 213 DISALLOW_COPY_AND_ASSIGN(PtrWrapper); |
| 214 }; |
| 215 |
| 216 struct PtrWrapperDeleter { |
| 217 static void Destruct(const PtrWrapper* interface_ptr) { |
| 218 interface_ptr->DeleteOnCorrectThread(); |
| 219 } |
| 220 }; |
| 221 |
| 222 ~ThreadSafeInterfacePtrBase() {} |
| 223 |
| 224 const std::unique_ptr<ThreadSafeForwarder<InterfaceType>> forwarder_; |
| 225 |
| 226 DISALLOW_COPY_AND_ASSIGN(ThreadSafeInterfacePtrBase); |
| 191 }; | 227 }; |
| 192 | 228 |
| 193 template <typename Interface> | 229 template <typename Interface> |
| 194 using ThreadSafeAssociatedInterfacePtr = | 230 using ThreadSafeAssociatedInterfacePtr = |
| 195 ThreadSafeInterfacePtrBase<Interface, AssociatedInterfacePtr>; | 231 ThreadSafeInterfacePtrBase<AssociatedInterfacePtr<Interface>>; |
| 196 | 232 |
| 197 template <typename Interface> | 233 template <typename Interface> |
| 198 using ThreadSafeInterfacePtr = | 234 using ThreadSafeInterfacePtr = |
| 199 ThreadSafeInterfacePtrBase<Interface, InterfacePtr>; | 235 ThreadSafeInterfacePtrBase<InterfacePtr<Interface>>; |
| 200 | 236 |
| 201 } // namespace mojo | 237 } // namespace mojo |
| 202 | 238 |
| 203 #endif // MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_ | 239 #endif // MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_ |
| OLD | NEW |