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

Side by Side Diff: mojo/public/cpp/bindings/lib/multiplex_router.cc

Issue 2754143005: Use WaitableEvents to wake up sync IPC waiting (Closed)
Patch Set: docs Created 3 years, 9 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 #include "mojo/public/cpp/bindings/lib/multiplex_router.h" 5 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
15 #include "base/single_thread_task_runner.h" 15 #include "base/single_thread_task_runner.h"
16 #include "base/stl_util.h" 16 #include "base/stl_util.h"
17 #include "base/synchronization/waitable_event.h"
17 #include "base/threading/thread_task_runner_handle.h" 18 #include "base/threading/thread_task_runner_handle.h"
18 #include "mojo/public/cpp/bindings/interface_endpoint_client.h" 19 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
19 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h" 20 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
20 #include "mojo/public/cpp/bindings/lib/may_auto_lock.h" 21 #include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
21 #include "mojo/public/cpp/bindings/sync_handle_watcher.h" 22 #include "mojo/public/cpp/bindings/sync_event_watcher.h"
22 23
23 namespace mojo { 24 namespace mojo {
24 namespace internal { 25 namespace internal {
25 26
26 // InterfaceEndpoint stores the information of an interface endpoint registered 27 // InterfaceEndpoint stores the information of an interface endpoint registered
27 // with the router. 28 // with the router.
28 // No one other than the router's |endpoints_| and |tasks_| should hold refs to 29 // No one other than the router's |endpoints_| and |tasks_| should hold refs to
29 // this object. 30 // this object.
30 class MultiplexRouter::InterfaceEndpoint 31 class MultiplexRouter::InterfaceEndpoint
31 : public base::RefCounted<InterfaceEndpoint>, 32 : public base::RefCounted<InterfaceEndpoint>,
32 public InterfaceEndpointController { 33 public InterfaceEndpointController {
33 public: 34 public:
34 InterfaceEndpoint(MultiplexRouter* router, InterfaceId id) 35 InterfaceEndpoint(MultiplexRouter* router, InterfaceId id)
35 : router_(router), 36 : router_(router),
36 id_(id), 37 id_(id),
37 closed_(false), 38 closed_(false),
38 peer_closed_(false), 39 peer_closed_(false),
39 handle_created_(false), 40 handle_created_(false),
40 client_(nullptr), 41 client_(nullptr) {}
41 event_signalled_(false) {}
42 42
43 // --------------------------------------------------------------------------- 43 // ---------------------------------------------------------------------------
44 // The following public methods are safe to call from any threads without 44 // The following public methods are safe to call from any threads without
45 // locking. 45 // locking.
46 46
47 InterfaceId id() const { return id_; } 47 InterfaceId id() const { return id_; }
48 48
49 // --------------------------------------------------------------------------- 49 // ---------------------------------------------------------------------------
50 // The following public methods are called under the router's lock. 50 // The following public methods are called under the router's lock.
51 51
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 DCHECK(task_runner_->BelongsToCurrentThread()); 101 DCHECK(task_runner_->BelongsToCurrentThread());
102 DCHECK(!closed_); 102 DCHECK(!closed_);
103 103
104 task_runner_ = nullptr; 104 task_runner_ = nullptr;
105 client_ = nullptr; 105 client_ = nullptr;
106 sync_watcher_.reset(); 106 sync_watcher_.reset();
107 } 107 }
108 108
109 void SignalSyncMessageEvent() { 109 void SignalSyncMessageEvent() {
110 router_->AssertLockAcquired(); 110 router_->AssertLockAcquired();
111 if (event_signalled_) 111 EnsureSyncMessageEventExists();
112 return; 112 sync_message_event_->Signal();
yzshen1 2017/03/23 20:15:50 Is it cheap enough to always create the event for
Ken Rockot(use gerrit already) 2017/03/23 22:04:20 Sure, probably. I guess the use of Optional can be
yzshen1 2017/03/23 22:42:10 Sorry I didn't make myself clear. Actually I was t
Ken Rockot(use gerrit already) 2017/03/24 04:59:54 Oops, I misunderstood. I was thinking we would cre
113
114 event_signalled_ = true;
115 if (!sync_message_event_sender_.is_valid())
116 return;
117
118 MojoResult result =
119 WriteMessageRaw(sync_message_event_sender_.get(), nullptr, 0, nullptr,
120 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
121 DCHECK_EQ(MOJO_RESULT_OK, result);
122 } 113 }
123 114
124 void ResetSyncMessageSignal() { 115 void ResetSyncMessageSignal() {
125 router_->AssertLockAcquired(); 116 router_->AssertLockAcquired();
126 117 if (!sync_message_event_.has_value())
127 if (!event_signalled_)
128 return; 118 return;
129 119 sync_message_event_->Reset();
130 event_signalled_ = false;
131 if (!sync_message_event_receiver_.is_valid())
132 return;
133
134 MojoResult result =
135 ReadMessageRaw(sync_message_event_receiver_.get(), nullptr, nullptr,
136 nullptr, nullptr, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
137 DCHECK_EQ(MOJO_RESULT_OK, result);
138 } 120 }
139 121
140 // --------------------------------------------------------------------------- 122 // ---------------------------------------------------------------------------
141 // The following public methods (i.e., InterfaceEndpointController 123 // The following public methods (i.e., InterfaceEndpointController
142 // implementation) are called by the client on the same thread as the 124 // implementation) are called by the client on the same thread as the
143 // AttachClient() call. They are called outside of the router's lock. 125 // AttachClient() call. They are called outside of the router's lock.
144 126
145 bool SendMessage(Message* message) override { 127 bool SendMessage(Message* message) override {
146 DCHECK(task_runner_->BelongsToCurrentThread()); 128 DCHECK(task_runner_->BelongsToCurrentThread());
147 message->set_interface_id(id_); 129 message->set_interface_id(id_);
(...skipping 19 matching lines...) Expand all
167 149
168 ~InterfaceEndpoint() override { 150 ~InterfaceEndpoint() override {
169 router_->AssertLockAcquired(); 151 router_->AssertLockAcquired();
170 152
171 DCHECK(!client_); 153 DCHECK(!client_);
172 DCHECK(closed_); 154 DCHECK(closed_);
173 DCHECK(peer_closed_); 155 DCHECK(peer_closed_);
174 DCHECK(!sync_watcher_); 156 DCHECK(!sync_watcher_);
175 } 157 }
176 158
177 void OnHandleReady(MojoResult result) { 159 void OnSyncEventSignaled() {
178 DCHECK(task_runner_->BelongsToCurrentThread()); 160 DCHECK(task_runner_->BelongsToCurrentThread());
179 scoped_refptr<MultiplexRouter> router_protector(router_); 161 scoped_refptr<MultiplexRouter> router_protector(router_);
180 162
181 // Because we never close |sync_message_event_{sender,receiver}_| before
182 // destruction or set a deadline, |result| should always be MOJO_RESULT_OK.
183 DCHECK_EQ(MOJO_RESULT_OK, result);
184
185 MayAutoLock locker(&router_->lock_); 163 MayAutoLock locker(&router_->lock_);
186 scoped_refptr<InterfaceEndpoint> self_protector(this); 164 scoped_refptr<InterfaceEndpoint> self_protector(this);
187 165
188 bool more_to_process = router_->ProcessFirstSyncMessageForEndpoint(id_); 166 bool more_to_process = router_->ProcessFirstSyncMessageForEndpoint(id_);
189 167
190 if (!more_to_process) 168 if (!more_to_process)
191 ResetSyncMessageSignal(); 169 ResetSyncMessageSignal();
192 170
193 // Currently there are no queued sync messages and the peer has closed so 171 // Currently there are no queued sync messages and the peer has closed so
194 // there won't be incoming sync messages in the future. 172 // there won't be incoming sync messages in the future.
195 if (!more_to_process && peer_closed_) { 173 if (!more_to_process && peer_closed_) {
196 // If a SyncWatch() call (or multiple ones) of this interface endpoint is 174 // If a SyncWatch() call (or multiple ones) of this interface endpoint is
197 // on the call stack, resetting the sync watcher will allow it to exit 175 // on the call stack, resetting the sync watcher will allow it to exit
198 // when the call stack unwinds to that frame. 176 // when the call stack unwinds to that frame.
199 sync_watcher_.reset(); 177 sync_watcher_.reset();
200 } 178 }
201 } 179 }
202 180
181 void EnsureSyncMessageEventExists() {
182 router_->AssertLockAcquired();
183 if (sync_message_event_.has_value())
184 return;
185 sync_message_event_.emplace(
186 base::WaitableEvent::ResetPolicy::MANUAL,
187 base::WaitableEvent::InitialState::NOT_SIGNALED);
188 }
189
203 void EnsureSyncWatcherExists() { 190 void EnsureSyncWatcherExists() {
204 DCHECK(task_runner_->BelongsToCurrentThread()); 191 DCHECK(task_runner_->BelongsToCurrentThread());
205 if (sync_watcher_) 192 if (sync_watcher_)
206 return; 193 return;
207 194
208 { 195 {
209 MayAutoLock locker(&router_->lock_); 196 MayAutoLock locker(&router_->lock_);
210 197 EnsureSyncMessageEventExists();
211 if (!sync_message_event_sender_.is_valid()) {
212 MojoResult result =
213 CreateMessagePipe(nullptr, &sync_message_event_sender_,
214 &sync_message_event_receiver_);
215 DCHECK_EQ(MOJO_RESULT_OK, result);
216
217 if (event_signalled_) {
218 // Reset the flag so that SignalSyncMessageEvent() will actually
219 // signal using the newly-created message pipe.
220 event_signalled_ = false;
221 SignalSyncMessageEvent();
222 }
223 }
224 } 198 }
225 199 sync_watcher_.reset(
226 sync_watcher_.reset(new SyncHandleWatcher( 200 new SyncEventWatcher(&sync_message_event_.value(),
227 sync_message_event_receiver_.get(), MOJO_HANDLE_SIGNAL_READABLE, 201 base::Bind(&InterfaceEndpoint::OnSyncEventSignaled,
228 base::Bind(&InterfaceEndpoint::OnHandleReady, base::Unretained(this)))); 202 base::Unretained(this))));
229 } 203 }
230 204
231 // --------------------------------------------------------------------------- 205 // ---------------------------------------------------------------------------
232 // The following members are safe to access from any threads. 206 // The following members are safe to access from any threads.
233 207
234 MultiplexRouter* const router_; 208 MultiplexRouter* const router_;
235 const InterfaceId id_; 209 const InterfaceId id_;
236 210
237 // --------------------------------------------------------------------------- 211 // ---------------------------------------------------------------------------
238 // The following members are accessed under the router's lock. 212 // The following members are accessed under the router's lock.
239 213
240 // Whether the endpoint has been closed. 214 // Whether the endpoint has been closed.
241 bool closed_; 215 bool closed_;
242 // Whether the peer endpoint has been closed. 216 // Whether the peer endpoint has been closed.
243 bool peer_closed_; 217 bool peer_closed_;
244 218
245 // Whether there is already a ScopedInterfaceEndpointHandle created for this 219 // Whether there is already a ScopedInterfaceEndpointHandle created for this
246 // endpoint. 220 // endpoint.
247 bool handle_created_; 221 bool handle_created_;
248 222
249 base::Optional<DisconnectReason> disconnect_reason_; 223 base::Optional<DisconnectReason> disconnect_reason_;
250 224
251 // The task runner on which |client_|'s methods can be called. 225 // The task runner on which |client_|'s methods can be called.
252 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 226 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
253 // Not owned. It is null if no client is attached to this endpoint. 227 // Not owned. It is null if no client is attached to this endpoint.
254 InterfaceEndpointClient* client_; 228 InterfaceEndpointClient* client_;
255 229
256 // A message pipe used as an event to signal that sync messages are available. 230 // An event used to signal that sync messages are available. The event is
257 // The message pipe handles are initialized under the router's lock and remain 231 // initialized under the router's lock and remains unchanged afterwards. It
258 // unchanged afterwards. They may be accessed outside of the router's lock 232 // may be accessed outside of the router's lock later.
259 // later. 233 base::Optional<base::WaitableEvent> sync_message_event_;
260 ScopedMessagePipeHandle sync_message_event_sender_;
261 ScopedMessagePipeHandle sync_message_event_receiver_;
262 bool event_signalled_;
263 234
264 // --------------------------------------------------------------------------- 235 // ---------------------------------------------------------------------------
265 // The following members are only valid while a client is attached. They are 236 // The following members are only valid while a client is attached. They are
266 // used exclusively on the client's thread. They may be accessed outside of 237 // used exclusively on the client's thread. They may be accessed outside of
267 // the router's lock. 238 // the router's lock.
268 239
269 std::unique_ptr<SyncHandleWatcher> sync_watcher_; 240 std::unique_ptr<SyncEventWatcher> sync_watcher_;
270 241
271 DISALLOW_COPY_AND_ASSIGN(InterfaceEndpoint); 242 DISALLOW_COPY_AND_ASSIGN(InterfaceEndpoint);
272 }; 243 };
273 244
274 // MessageWrapper objects are always destroyed under the router's lock. On 245 // MessageWrapper objects are always destroyed under the router's lock. On
275 // destruction, if the message it wrappers contains 246 // destruction, if the message it wrappers contains
276 // ScopedInterfaceEndpointHandles (which cannot be destructed under the 247 // ScopedInterfaceEndpointHandles (which cannot be destructed under the
277 // router's lock), the wrapper unlocks to clean them up. 248 // router's lock), the wrapper unlocks to clean them up.
278 class MultiplexRouter::MessageWrapper { 249 class MultiplexRouter::MessageWrapper {
279 public: 250 public:
(...skipping 697 matching lines...) Expand 10 before | Expand all | Expand 10 after
977 948
978 void MultiplexRouter::AssertLockAcquired() { 949 void MultiplexRouter::AssertLockAcquired() {
979 #if DCHECK_IS_ON() 950 #if DCHECK_IS_ON()
980 if (lock_) 951 if (lock_)
981 lock_->AssertAcquired(); 952 lock_->AssertAcquired();
982 #endif 953 #endif
983 } 954 }
984 955
985 } // namespace internal 956 } // namespace internal
986 } // namespace mojo 957 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698