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

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

Issue 2498743002: Mojo: introducing a thread safe interface pointer. (Closed)
Patch Set: Mojo: introducing a thread safe interface pointer. Created 4 years, 1 month 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
7
8 namespace mojo {
9
10 #include <memory>
11
12 #include "base/callback.h"
13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/task_runner.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "mojo/public/cpp/bindings/interface_ptr.h"
18 #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
19 #include "mojo/public/cpp/bindings/message.h"
20
21 struct ThreadSafeInterfacePtrDeleter;
22
23 // ThreadSafeInterfacePtr is a version of InterfacePtr that lets caller invoke
24 // interface methods from any threads. Callbacks are called on the thread that
25 // performed the interface call.
26 // To create a ThreadSafeInterfacePtr, create first a regular InterfacePtr that
27 // you then provide to ThreadSafeInterfacePtr::Create.
28 // You can then call methods on the ThreadSafeInterfacePtr from any thread.
29 //
30 // Ex:
31 // frob::FrobinatorPtr frobinator;
32 // frob::FrobinatorImpl impl(GetProxy(&frobinator));
33 // scoped_refptr<frob::ThreadSafeFrobinatorPtr> thread_safe_frobinator =
34 // frob::ThreadSafeFrobinatorPtr::Create(std::move(frobinator));
35 // (*thread_safe_frobinator)->FrobinateToTheMax();
36
37 template <typename Interface>
38 class ThreadSafeInterfacePtr : public MessageReceiverWithResponder,
39 public base::RefCountedThreadSafe<ThreadSafeInterfacePtr<Interface>,
40 ThreadSafeInterfacePtrDeleter> {
41 public:
42 using ProxyType = typename Interface::Proxy_;
43
44 using AcceptCallback = base::Callback<void(Message)>;
45 using AcceptWithResponderCallback =
46 base::Callback<void(Message, std::unique_ptr<MessageReceiver>)>;
47
48 Interface* get() { return &proxy_; }
49 Interface* operator->() { return get(); }
50 Interface& operator*() { return *get(); }
51
52 static scoped_refptr<ThreadSafeInterfacePtr<Interface>> Create(
53 InterfacePtr<Interface> interface_ptr) {
54 if (!interface_ptr.is_bound()) {
55 LOG(ERROR) << "Attempting to create a ThreadSafeInterfacePtr from an "
56 "unbound InterfacePtr.";
57 return nullptr;
58 }
59 return new ThreadSafeInterfacePtr(std::move(interface_ptr),
60 base::ThreadTaskRunnerHandle::Get());
61 }
62
63 private:
64 friend class base::RefCountedThreadSafe<ThreadSafeInterfacePtr<Interface>>;
65 friend struct ThreadSafeInterfacePtrDeleter;
66
67 ThreadSafeInterfacePtr(
68 InterfacePtr<Interface> interface_ptr,
69 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
70 : interface_ptr_task_runner_(task_runner),
71 proxy_(this),
72 interface_ptr_(std::move(interface_ptr)) {
73 // Note that it's important we do get the callback after interface_ptr_ has
74 // been set, as they would become invalid if interface_ptr_ is copied.
75 accept_callback_ = interface_ptr_.internal_state()->
76 GetThreadSafePtrAcceptCallback();
77 accept_with_responder_callback_ = interface_ptr_.internal_state()->
78 GetThreadSafePtrAcceptWithResponderCallback();
79 }
80
81 void DeleteOnCorrectThread() const {
82 if (!interface_ptr_task_runner_->BelongsToCurrentThread() &&
83 interface_ptr_task_runner_->DeleteSoon(FROM_HERE, this)) {
84 return;
85 }
86 delete this;
87 }
88
89 // MessageReceiverWithResponder implementation:
90 bool Accept(Message* message) override {
91 interface_ptr_task_runner_->PostTask(
92 FROM_HERE,
93 base::Bind(accept_callback_, base::Passed(std::move(*message))));
94 return true;
95 }
96
97 bool AcceptWithResponder(Message* message,
98 MessageReceiver* responder) override {
99 auto forward_responder = base::MakeUnique<ForwardToCallingThread>(
100 base::WrapUnique(responder));
101 interface_ptr_task_runner_->PostTask(
102 FROM_HERE,
103 base::Bind(accept_with_responder_callback_,
104 base::Passed(std::move(*message)),
105 base::Passed(std::move(forward_responder))));
106 return true;
107 }
108
109 class ForwardToCallingThread : public MessageReceiver {
110 public:
111 explicit ForwardToCallingThread(std::unique_ptr<MessageReceiver> responder)
112 : responder_(std::move(responder)),
113 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
114 }
115
116 private:
117 bool Accept(Message* message) {
118 // The current instance will be deleted when this method returns, so we
119 // have to relinquish the responder's ownership so it does not get
120 // deleted.
121 caller_task_runner_->PostTask(FROM_HERE,
122 base::Bind(&ForwardToCallingThread::CallAcceptAndDeleteResponder,
123 base::Passed(std::move(responder_)),
124 base::Passed(std::move(*message))));
125 return true;
126 }
127
128 static void CallAcceptAndDeleteResponder(
129 std::unique_ptr<MessageReceiver> responder,
130 Message message) {
131 ignore_result(responder->Accept(&message));
132 }
133
134 std::unique_ptr<MessageReceiver> responder_;
135 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
136 };
137
138 scoped_refptr<base::SingleThreadTaskRunner> interface_ptr_task_runner_;
139 ProxyType proxy_;
140 AcceptCallback accept_callback_;
141 AcceptWithResponderCallback accept_with_responder_callback_;
142 InterfacePtr<Interface> interface_ptr_;
143 };
144
145 struct ThreadSafeInterfacePtrDeleter {
146 template <typename Interface>
147 static void Destruct(const ThreadSafeInterfacePtr<Interface>* interface_ptr) {
148 interface_ptr->DeleteOnCorrectThread();
149 }
150 };
151
152 } // namespace mojo
153
154 #endif // MOJO_PUBLIC_CPP_BINDINGS_THREAD_SAFE_INTERFACE_PTR_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698