blob: c4f14dce5cff5eec87691a5fdf16ce5b3b22abaa [file] [log] [blame]
[email protected]522cc10d2012-01-11 22:39:541// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]946d1b22009-07-22 23:57:215#include "ipc/ipc_sync_channel.h"
initial.commit09911bf2008-07-26 23:55:296
avi246998d82015-12-22 02:39:047#include <stddef.h>
8#include <stdint.h>
danakj03de39b22016-04-23 04:21:099
dchenge48600452015-12-28 02:24:5010#include <utility>
avi246998d82015-12-22 02:39:0411
[email protected]72b6f8e22011-11-12 21:16:4112#include "base/bind.h"
[email protected]f886b7bf2008-09-10 10:54:0613#include "base/lazy_instance.h"
[email protected]c62dd9d2011-09-21 18:05:4114#include "base/location.h"
initial.commit09911bf2008-07-26 23:55:2915#include "base/logging.h"
rockot3c236292016-07-07 20:26:0216#include "base/macros.h"
danakj03de39b22016-04-23 04:21:0917#include "base/memory/ptr_util.h"
gabf64a25e2017-05-12 19:42:5618#include "base/message_loop/message_loop.h"
fdoray6d056ff2016-07-04 21:56:4219#include "base/run_loop.h"
[email protected]44f9c952011-01-02 06:05:3920#include "base/synchronization/waitable_event.h"
[email protected]b2432302012-07-02 21:15:5221#include "base/threading/thread_local.h"
gabf08ccc02016-05-11 18:51:1122#include "base/threading/thread_task_runner_handle.h"
primiano7182d7b2015-01-30 18:02:0323#include "base/trace_event/trace_event.h"
[email protected]64860882014-08-04 23:44:1724#include "ipc/ipc_channel_factory.h"
[email protected]60b2c61f2012-08-22 22:39:5725#include "ipc/ipc_logging.h"
26#include "ipc/ipc_message_macros.h"
[email protected]946d1b22009-07-22 23:57:2127#include "ipc/ipc_sync_message.h"
rockotb62e2e32017-03-24 18:36:4428#include "mojo/public/cpp/bindings/sync_event_watcher.h"
initial.commit09911bf2008-07-26 23:55:2929
[email protected]1c4947f2009-01-15 22:25:1130using base::WaitableEvent;
initial.commit09911bf2008-07-26 23:55:2931
32namespace IPC {
rockot3c236292016-07-07 20:26:0233
34namespace {
35
36// A generic callback used when watching handles synchronously. Sets |*signal|
rockotb62e2e32017-03-24 18:36:4437// to true.
38void OnEventReady(bool* signal) {
rockot3c236292016-07-07 20:26:0239 *signal = true;
rockot3c236292016-07-07 20:26:0240}
41
rockotb62e2e32017-03-24 18:36:4442base::LazyInstance<std::unique_ptr<base::WaitableEvent>>::Leaky
43 g_pump_messages_event = LAZY_INSTANCE_INITIALIZER;
rockot3c236292016-07-07 20:26:0244
45} // namespace
46
initial.commit09911bf2008-07-26 23:55:2947// When we're blocked in a Send(), we need to process incoming synchronous
48// messages right away because it could be blocking our reply (either
49// directly from the same object we're calling, or indirectly through one or
50// more other channels). That means that in SyncContext's OnMessageReceived,
51// we need to process sync message right away if we're blocked. However a
52// simple check isn't sufficient, because the listener thread can be in the
53// process of calling Send.
54// To work around this, when SyncChannel filters a sync message, it sets
55// an event that the listener thread waits on during its Send() call. This
56// allows us to dispatch incoming sync messages when blocked. The race
57// condition is handled because if Send is in the process of being called, it
58// will check the event. In case the listener thread isn't sending a message,
59// we queue a task on the listener thread to dispatch the received messages.
60// The messages are stored in this queue object that's shared among all
61// SyncChannel objects on the same thread (since one object can receive a
62// sync message while another one is blocked).
63
initial.commit09911bf2008-07-26 23:55:2964class SyncChannel::ReceivedSyncMsgQueue :
65 public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> {
66 public:
rockotb62e2e32017-03-24 18:36:4467 // SyncChannel::WaitForReplyWithNestedMessageLoop may be re-entered, i.e. we
68 // may nest waiting message loops arbitrarily deep on the SyncChannel's
69 // thread. Every such operation has a corresponding WaitableEvent to be
70 // watched which, when signalled for IPC completion, breaks out of the loop.
71 // A reference to the innermost (i.e. topmost) watcher is held in
72 // |ReceivedSyncMsgQueue::top_send_done_event_watcher_|.
73 //
74 // NestedSendDoneWatcher provides a simple scoper which is used by
75 // WaitForReplyWithNestedMessageLoop to begin watching a new local "send done"
76 // event, preserving the previous topmost state on the local stack until the
77 // new inner loop is broken. If yet another subsequent nested loop is started
78 // therein the process is repeated again in the new inner stack frame, and so
79 // on.
80 //
81 // When this object is destroyed on stack unwind, the previous topmost state
82 // is swapped back into |ReceivedSyncMsgQueue::top_send_done_event_watcher_|,
83 // and its watch is resumed immediately.
84 class NestedSendDoneWatcher {
85 public:
86 NestedSendDoneWatcher(SyncChannel::SyncContext* context,
Hajime Hoshi138652c92018-01-12 15:11:4487 base::RunLoop* run_loop,
88 scoped_refptr<base::SequencedTaskRunner> task_runner)
rockotb62e2e32017-03-24 18:36:4489 : sync_msg_queue_(context->received_sync_msgs()),
90 outer_state_(sync_msg_queue_->top_send_done_event_watcher_),
91 event_(context->GetSendDoneEvent()),
92 callback_(
tzik130cfd0c2017-04-18 03:49:0593 base::BindOnce(&SyncChannel::SyncContext::OnSendDoneEventSignaled,
94 context,
Hajime Hoshi138652c92018-01-12 15:11:4495 run_loop)),
96 task_runner_(std::move(task_runner)) {
rockotb62e2e32017-03-24 18:36:4497 sync_msg_queue_->top_send_done_event_watcher_ = this;
98 if (outer_state_)
99 outer_state_->StopWatching();
100 StartWatching();
101 }
102
103 ~NestedSendDoneWatcher() {
104 sync_msg_queue_->top_send_done_event_watcher_ = outer_state_;
105 if (outer_state_)
106 outer_state_->StartWatching();
107 }
108
109 private:
tzik130cfd0c2017-04-18 03:49:05110 void Run(WaitableEvent* event) {
111 DCHECK(callback_);
112 std::move(callback_).Run(event);
113 }
114
115 void StartWatching() {
Hajime Hoshi138652c92018-01-12 15:11:44116 watcher_.StartWatching(
117 event_,
118 base::BindOnce(&NestedSendDoneWatcher::Run, base::Unretained(this)),
119 task_runner_);
tzik130cfd0c2017-04-18 03:49:05120 }
121
rockotb62e2e32017-03-24 18:36:44122 void StopWatching() { watcher_.StopWatching(); }
123
124 ReceivedSyncMsgQueue* const sync_msg_queue_;
125 NestedSendDoneWatcher* const outer_state_;
126
127 base::WaitableEvent* const event_;
tzik130cfd0c2017-04-18 03:49:05128 base::WaitableEventWatcher::EventCallback callback_;
rockotb62e2e32017-03-24 18:36:44129 base::WaitableEventWatcher watcher_;
Hajime Hoshi138652c92018-01-12 15:11:44130 scoped_refptr<base::SequencedTaskRunner> task_runner_;
rockotb62e2e32017-03-24 18:36:44131
132 DISALLOW_COPY_AND_ASSIGN(NestedSendDoneWatcher);
133 };
134
[email protected]3cdb7af812008-10-24 19:21:13135 // Returns the ReceivedSyncMsgQueue instance for this thread, creating one
[email protected]d3ae7a072008-12-05 20:27:20136 // if necessary. Call RemoveContext on the same thread when done.
137 static ReceivedSyncMsgQueue* AddContext() {
[email protected]3cdb7af812008-10-24 19:21:13138 // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple
139 // SyncChannel objects can block the same thread).
140 ReceivedSyncMsgQueue* rv = lazy_tls_ptr_.Pointer()->Get();
141 if (!rv) {
142 rv = new ReceivedSyncMsgQueue();
143 ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Set(rv);
144 }
145 rv->listener_count_++;
146 return rv;
initial.commit09911bf2008-07-26 23:55:29147 }
148
rockot9abe09b2016-08-02 20:57:34149 // Prevents messages from being dispatched immediately when the dispatch event
150 // is signaled. Instead, |*dispatch_flag| will be set.
151 void BlockDispatch(bool* dispatch_flag) { dispatch_flag_ = dispatch_flag; }
152
153 // Allows messages to be dispatched immediately when the dispatch event is
154 // signaled.
155 void UnblockDispatch() { dispatch_flag_ = nullptr; }
156
initial.commit09911bf2008-07-26 23:55:29157 // Called on IPC thread when a synchronous message or reply arrives.
[email protected]d3ae7a072008-12-05 20:27:20158 void QueueMessage(const Message& msg, SyncChannel::SyncContext* context) {
initial.commit09911bf2008-07-26 23:55:29159 bool was_task_pending;
160 {
[email protected]20305ec2011-01-21 04:55:52161 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29162
163 was_task_pending = task_pending_;
164 task_pending_ = true;
165
166 // We set the event in case the listener thread is blocked (or is about
167 // to). In case it's not, the PostTask dispatches the messages.
[email protected]d3ae7a072008-12-05 20:27:20168 message_queue_.push_back(QueuedMessage(new Message(msg), context));
[email protected]522cc10d2012-01-11 22:39:54169 message_queue_version_++;
initial.commit09911bf2008-07-26 23:55:29170 }
171
[email protected]1c4947f2009-01-15 22:25:11172 dispatch_event_.Signal();
initial.commit09911bf2008-07-26 23:55:29173 if (!was_task_pending) {
[email protected]b2432302012-07-02 21:15:52174 listener_task_runner_->PostTask(
[email protected]72b6f8e22011-11-12 21:16:41175 FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchMessagesTask,
vmpstra34d11322016-03-21 20:28:47176 this, base::RetainedRef(context)));
initial.commit09911bf2008-07-26 23:55:29177 }
178 }
179
180 void QueueReply(const Message &msg, SyncChannel::SyncContext* context) {
[email protected]d3ae7a072008-12-05 20:27:20181 received_replies_.push_back(QueuedMessage(new Message(msg), context));
initial.commit09911bf2008-07-26 23:55:29182 }
183
[email protected]d3ae7a072008-12-05 20:27:20184 // Called on the listener's thread to process any queues synchronous
initial.commit09911bf2008-07-26 23:55:29185 // messages.
[email protected]54af05f2011-04-08 03:38:21186 void DispatchMessagesTask(SyncContext* context) {
initial.commit09911bf2008-07-26 23:55:29187 {
[email protected]20305ec2011-01-21 04:55:52188 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29189 task_pending_ = false;
190 }
[email protected]54af05f2011-04-08 03:38:21191 context->DispatchMessages();
initial.commit09911bf2008-07-26 23:55:29192 }
193
rockot9abe09b2016-08-02 20:57:34194 // Dispatches any queued incoming sync messages. If |dispatching_context| is
195 // not null, messages which target a restricted dispatch channel will only be
196 // dispatched if |dispatching_context| belongs to the same restricted dispatch
197 // group as that channel. If |dispatching_context| is null, all queued
198 // messages are dispatched.
[email protected]54af05f2011-04-08 03:38:21199 void DispatchMessages(SyncContext* dispatching_context) {
[email protected]522cc10d2012-01-11 22:39:54200 bool first_time = true;
tfarina10a5c062015-09-04 18:47:57201 uint32_t expected_version = 0;
[email protected]522cc10d2012-01-11 22:39:54202 SyncMessageQueue::iterator it;
initial.commit09911bf2008-07-26 23:55:29203 while (true) {
rockot9abe09b2016-08-02 20:57:34204 Message* message = nullptr;
[email protected]d3ae7a072008-12-05 20:27:20205 scoped_refptr<SyncChannel::SyncContext> context;
initial.commit09911bf2008-07-26 23:55:29206 {
[email protected]20305ec2011-01-21 04:55:52207 base::AutoLock auto_lock(message_lock_);
[email protected]522cc10d2012-01-11 22:39:54208 if (first_time || message_queue_version_ != expected_version) {
209 it = message_queue_.begin();
210 first_time = false;
[email protected]54af05f2011-04-08 03:38:21211 }
[email protected]522cc10d2012-01-11 22:39:54212 for (; it != message_queue_.end(); it++) {
[email protected]298ee7d2012-03-30 21:29:30213 int message_group = it->context->restrict_dispatch_group();
Sam McNallyae42d322018-01-09 00:47:55214 if (message_group == kRestrictDispatchGroup_None ||
215 (dispatching_context &&
216 message_group ==
217 dispatching_context->restrict_dispatch_group())) {
[email protected]522cc10d2012-01-11 22:39:54218 message = it->message;
219 context = it->context;
220 it = message_queue_.erase(it);
221 message_queue_version_++;
222 expected_version = message_queue_version_;
223 break;
224 }
225 }
226 }
initial.commit09911bf2008-07-26 23:55:29227
rockot9abe09b2016-08-02 20:57:34228 if (message == nullptr)
[email protected]522cc10d2012-01-11 22:39:54229 break;
230 context->OnDispatchMessage(*message);
231 delete message;
initial.commit09911bf2008-07-26 23:55:29232 }
233 }
234
initial.commit09911bf2008-07-26 23:55:29235 // SyncChannel calls this in its destructor.
[email protected]d3ae7a072008-12-05 20:27:20236 void RemoveContext(SyncContext* context) {
[email protected]20305ec2011-01-21 04:55:52237 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29238
[email protected]d3ae7a072008-12-05 20:27:20239 SyncMessageQueue::iterator iter = message_queue_.begin();
240 while (iter != message_queue_.end()) {
[email protected]17571642013-06-01 04:11:27241 if (iter->context.get() == context) {
[email protected]d3ae7a072008-12-05 20:27:20242 delete iter->message;
243 iter = message_queue_.erase(iter);
[email protected]522cc10d2012-01-11 22:39:54244 message_queue_version_++;
initial.commit09911bf2008-07-26 23:55:29245 } else {
[email protected]d3ae7a072008-12-05 20:27:20246 iter++;
initial.commit09911bf2008-07-26 23:55:29247 }
initial.commit09911bf2008-07-26 23:55:29248 }
[email protected]3cdb7af812008-10-24 19:21:13249
250 if (--listener_count_ == 0) {
251 DCHECK(lazy_tls_ptr_.Pointer()->Get());
rockot9abe09b2016-08-02 20:57:34252 lazy_tls_ptr_.Pointer()->Set(nullptr);
253 sync_dispatch_watcher_.reset();
[email protected]3cdb7af812008-10-24 19:21:13254 }
initial.commit09911bf2008-07-26 23:55:29255 }
256
rockotb62e2e32017-03-24 18:36:44257 base::WaitableEvent* dispatch_event() { return &dispatch_event_; }
[email protected]b2432302012-07-02 21:15:52258 base::SingleThreadTaskRunner* listener_task_runner() {
[email protected]17571642013-06-01 04:11:27259 return listener_task_runner_.get();
[email protected]92bf9062011-05-02 18:00:49260 }
initial.commit09911bf2008-07-26 23:55:29261
[email protected]f886b7bf2008-09-10 10:54:06262 // Holds a pointer to the per-thread ReceivedSyncMsgQueue object.
scottmg5e65e3a2017-03-08 08:48:46263 static base::LazyInstance<base::ThreadLocalPointer<ReceivedSyncMsgQueue>>::
264 DestructorAtExit lazy_tls_ptr_;
[email protected]f886b7bf2008-09-10 10:54:06265
initial.commit09911bf2008-07-26 23:55:29266 // Called on the ipc thread to check if we can unblock any current Send()
267 // calls based on a queued reply.
268 void DispatchReplies() {
initial.commit09911bf2008-07-26 23:55:29269 for (size_t i = 0; i < received_replies_.size(); ++i) {
270 Message* message = received_replies_[i].message;
[email protected]3cdb7af812008-10-24 19:21:13271 if (received_replies_[i].context->TryToUnblockListener(message)) {
initial.commit09911bf2008-07-26 23:55:29272 delete message;
273 received_replies_.erase(received_replies_.begin() + i);
274 return;
275 }
276 }
277 }
278
[email protected]63a7bb82008-10-25 00:46:00279 private:
[email protected]877d55d2009-11-05 21:53:08280 friend class base::RefCountedThreadSafe<ReceivedSyncMsgQueue>;
281
[email protected]4df10d612008-11-12 00:38:26282 // See the comment in SyncChannel::SyncChannel for why this event is created
283 // as manual reset.
gab90c2c5c2016-06-01 20:34:06284 ReceivedSyncMsgQueue()
285 : message_queue_version_(0),
rockotb62e2e32017-03-24 18:36:44286 dispatch_event_(base::WaitableEvent::ResetPolicy::MANUAL,
287 base::WaitableEvent::InitialState::NOT_SIGNALED),
gab90c2c5c2016-06-01 20:34:06288 listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
Jeremy Roman160eb922017-08-29 17:43:43289 sync_dispatch_watcher_(std::make_unique<mojo::SyncEventWatcher>(
rockotb62e2e32017-03-24 18:36:44290 &dispatch_event_,
291 base::Bind(&ReceivedSyncMsgQueue::OnDispatchEventReady,
292 base::Unretained(this)))) {
rockot9abe09b2016-08-02 20:57:34293 sync_dispatch_watcher_->AllowWokenUpBySyncWatchOnSameThread();
294 }
[email protected]63a7bb82008-10-25 00:46:00295
Chris Watkins2d879af2017-11-30 02:11:59296 ~ReceivedSyncMsgQueue() = default;
[email protected]877d55d2009-11-05 21:53:08297
rockotb62e2e32017-03-24 18:36:44298 void OnDispatchEventReady() {
rockot9abe09b2016-08-02 20:57:34299 if (dispatch_flag_) {
300 *dispatch_flag_ = true;
301 return;
302 }
303
304 // We were woken up during a sync wait, but no specific SyncChannel is
305 // currently waiting. i.e., some other Mojo interface on this thread is
306 // waiting for a response. Since we don't support anything analogous to
307 // restricted dispatch on Mojo interfaces, in this case it's safe to
308 // dispatch sync messages for any context.
309 DispatchMessages(nullptr);
310 }
311
[email protected]d3ae7a072008-12-05 20:27:20312 // Holds information about a queued synchronous message or reply.
313 struct QueuedMessage {
314 QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { }
initial.commit09911bf2008-07-26 23:55:29315 Message* message;
316 scoped_refptr<SyncChannel::SyncContext> context;
317 };
318
[email protected]522cc10d2012-01-11 22:39:54319 typedef std::list<QueuedMessage> SyncMessageQueue;
[email protected]1c4947f2009-01-15 22:25:11320 SyncMessageQueue message_queue_;
rockotb62e2e32017-03-24 18:36:44321
322 // Used to signal DispatchMessages to rescan
323 uint32_t message_queue_version_ = 0;
[email protected]d3ae7a072008-12-05 20:27:20324
325 std::vector<QueuedMessage> received_replies_;
[email protected]3cdb7af812008-10-24 19:21:13326
rockot3c236292016-07-07 20:26:02327 // Signaled when we get a synchronous message that we must respond to, as the
[email protected]3cdb7af812008-10-24 19:21:13328 // sender needs its reply before it can reply to our original synchronous
329 // message.
rockotb62e2e32017-03-24 18:36:44330 base::WaitableEvent dispatch_event_;
[email protected]b2432302012-07-02 21:15:52331 scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
[email protected]20305ec2011-01-21 04:55:52332 base::Lock message_lock_;
rockotb62e2e32017-03-24 18:36:44333 bool task_pending_ = false;
334 int listener_count_ = 0;
[email protected]ac0efda2009-10-14 16:22:02335
rockotb62e2e32017-03-24 18:36:44336 // The current NestedSendDoneWatcher for this thread, if we're currently
337 // in a SyncChannel::WaitForReplyWithNestedMessageLoop. See
338 // NestedSendDoneWatcher comments for more details.
339 NestedSendDoneWatcher* top_send_done_event_watcher_ = nullptr;
rockot9abe09b2016-08-02 20:57:34340
341 // If not null, the address of a flag to set when the dispatch event signals,
342 // in lieu of actually dispatching messages. This is used by
343 // SyncChannel::WaitForReply to restrict the scope of queued messages we're
344 // allowed to process while it's waiting.
345 bool* dispatch_flag_ = nullptr;
346
347 // Watches |dispatch_event_| during all sync handle watches on this thread.
rockotb62e2e32017-03-24 18:36:44348 std::unique_ptr<mojo::SyncEventWatcher> sync_dispatch_watcher_;
initial.commit09911bf2008-07-26 23:55:29349};
350
scottmg5e65e3a2017-03-08 08:48:46351base::LazyInstance<base::ThreadLocalPointer<
352 SyncChannel::ReceivedSyncMsgQueue>>::DestructorAtExit
[email protected]6de0fd1d2011-11-15 13:31:49353 SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_ =
354 LAZY_INSTANCE_INITIALIZER;
initial.commit09911bf2008-07-26 23:55:29355
356SyncChannel::SyncContext::SyncContext(
[email protected]b7f59e822012-06-29 22:05:26357 Listener* listener,
dchengfd033702014-08-28 16:59:29358 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09359 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]1c4947f2009-01-15 22:25:11360 WaitableEvent* shutdown_event)
Hajime Hoshiff15e972017-11-09 06:37:09361 : ChannelProxy::Context(listener, ipc_task_runner, listener_task_runner),
[email protected]1c4947f2009-01-15 22:25:11362 received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()),
[email protected]54af05f2011-04-08 03:38:21363 shutdown_event_(shutdown_event),
Hajime Hoshiff15e972017-11-09 06:37:09364 restrict_dispatch_group_(kRestrictDispatchGroup_None) {}
initial.commit09911bf2008-07-26 23:55:29365
rockotb62e2e32017-03-24 18:36:44366void SyncChannel::SyncContext::OnSendDoneEventSignaled(
367 base::RunLoop* nested_loop,
368 base::WaitableEvent* event) {
369 DCHECK_EQ(GetSendDoneEvent(), event);
370 nested_loop->Quit();
371}
372
initial.commit09911bf2008-07-26 23:55:29373SyncChannel::SyncContext::~SyncContext() {
374 while (!deserializers_.empty())
[email protected]3cdb7af812008-10-24 19:21:13375 Pop();
initial.commit09911bf2008-07-26 23:55:29376}
377
378// Adds information about an outgoing sync message to the context so that
rockot3c236292016-07-07 20:26:02379// we know how to deserialize the reply. Returns |true| if the message was added
380// to the context or |false| if it was rejected (e.g. due to shutdown.)
381bool SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
[email protected]4a180a52011-04-15 19:07:43382 // Create the tracking information for this message. This object is stored
383 // by value since all members are pointers that are cheap to copy. These
384 // pointers are cleaned up in the Pop() function.
385 //
[email protected]1c4947f2009-01-15 22:25:11386 // The event is created as manual reset because in between Signal and
[email protected]4df10d612008-11-12 00:38:26387 // OnObjectSignalled, another Send can happen which would stop the watcher
388 // from being called. The event would get watched later, when the nested
389 // Send completes, so the event will need to remain set.
rockot3c236292016-07-07 20:26:02390 base::AutoLock auto_lock(deserializers_lock_);
391 if (reject_new_deserializers_)
392 return false;
gab90c2c5c2016-06-01 20:34:06393 PendingSyncMsg pending(
394 SyncMessage::GetMessageId(*sync_msg), sync_msg->GetReplyDeserializer(),
rockotb62e2e32017-03-24 18:36:44395 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
396 base::WaitableEvent::InitialState::NOT_SIGNALED));
[email protected]3cdb7af812008-10-24 19:21:13397 deserializers_.push_back(pending);
rockot3c236292016-07-07 20:26:02398 return true;
initial.commit09911bf2008-07-26 23:55:29399}
400
[email protected]3cdb7af812008-10-24 19:21:13401bool SyncChannel::SyncContext::Pop() {
[email protected]63a7bb82008-10-25 00:46:00402 bool result;
403 {
[email protected]20305ec2011-01-21 04:55:52404 base::AutoLock auto_lock(deserializers_lock_);
[email protected]63a7bb82008-10-25 00:46:00405 PendingSyncMsg msg = deserializers_.back();
406 delete msg.deserializer;
[email protected]1c4947f2009-01-15 22:25:11407 delete msg.done_event;
rockot3c236292016-07-07 20:26:02408 msg.done_event = nullptr;
[email protected]63a7bb82008-10-25 00:46:00409 deserializers_.pop_back();
410 result = msg.send_result;
411 }
412
413 // We got a reply to a synchronous Send() call that's blocking the listener
414 // thread. However, further down the call stack there could be another
415 // blocking Send() call, whose reply we received after we made this last
416 // Send() call. So check if we have any queued replies available that
417 // can now unblock the listener thread.
[email protected]b2432302012-07-02 21:15:52418 ipc_task_runner()->PostTask(
[email protected]72b6f8e22011-11-12 21:16:41419 FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchReplies,
tzik07cace42016-09-01 04:21:25420 received_sync_msgs_));
[email protected]63a7bb82008-10-25 00:46:00421
422 return result;
[email protected]3cdb7af812008-10-24 19:21:13423}
424
rockotb62e2e32017-03-24 18:36:44425base::WaitableEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
[email protected]20305ec2011-01-21 04:55:52426 base::AutoLock auto_lock(deserializers_lock_);
[email protected]3cdb7af812008-10-24 19:21:13427 return deserializers_.back().done_event;
428}
429
rockotb62e2e32017-03-24 18:36:44430base::WaitableEvent* SyncChannel::SyncContext::GetDispatchEvent() {
[email protected]3cdb7af812008-10-24 19:21:13431 return received_sync_msgs_->dispatch_event();
initial.commit09911bf2008-07-26 23:55:29432}
433
434void SyncChannel::SyncContext::DispatchMessages() {
[email protected]54af05f2011-04-08 03:38:21435 received_sync_msgs_->DispatchMessages(this);
initial.commit09911bf2008-07-26 23:55:29436}
437
[email protected]3cdb7af812008-10-24 19:21:13438bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) {
[email protected]20305ec2011-01-21 04:55:52439 base::AutoLock auto_lock(deserializers_lock_);
[email protected]63a7bb82008-10-25 00:46:00440 if (deserializers_.empty() ||
441 !SyncMessage::IsMessageReplyTo(*msg, deserializers_.back().id)) {
442 return false;
[email protected]3cdb7af812008-10-24 19:21:13443 }
initial.commit09911bf2008-07-26 23:55:29444
[email protected]63a7bb82008-10-25 00:46:00445 if (!msg->is_reply_error()) {
[email protected]211142cd2012-08-13 09:41:19446 bool send_result = deserializers_.back().deserializer->
[email protected]63a7bb82008-10-25 00:46:00447 SerializeOutputParameters(*msg);
[email protected]211142cd2012-08-13 09:41:19448 deserializers_.back().send_result = send_result;
bauerb3e9be732015-11-03 18:17:47449 DVLOG_IF(1, !send_result) << "Couldn't deserialize reply message";
[email protected]211142cd2012-08-13 09:41:19450 } else {
bauerb3e9be732015-11-03 18:17:47451 DVLOG(1) << "Received error reply";
[email protected]63a7bb82008-10-25 00:46:00452 }
tzika08b2fd2016-03-30 02:32:59453
rockotb62e2e32017-03-24 18:36:44454 base::WaitableEvent* done_event = deserializers_.back().done_event;
tzika08b2fd2016-03-30 02:32:59455 TRACE_EVENT_FLOW_BEGIN0(
456 TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
457 "SyncChannel::SyncContext::TryToUnblockListener", done_event);
458
459 done_event->Signal();
initial.commit09911bf2008-07-26 23:55:29460
[email protected]3cdb7af812008-10-24 19:21:13461 return true;
initial.commit09911bf2008-07-26 23:55:29462}
463
[email protected]3cdb7af812008-10-24 19:21:13464void SyncChannel::SyncContext::Clear() {
465 CancelPendingSends();
[email protected]d3ae7a072008-12-05 20:27:20466 received_sync_msgs_->RemoveContext(this);
[email protected]3cdb7af812008-10-24 19:21:13467 Context::Clear();
468}
469
[email protected]a95986a82010-12-24 06:19:28470bool SyncChannel::SyncContext::OnMessageReceived(const Message& msg) {
[email protected]d65cab7a2008-08-12 01:25:41471 // Give the filters a chance at processing this message.
472 if (TryFilters(msg))
[email protected]a95986a82010-12-24 06:19:28473 return true;
[email protected]d65cab7a2008-08-12 01:25:41474
[email protected]3cdb7af812008-10-24 19:21:13475 if (TryToUnblockListener(&msg))
[email protected]a95986a82010-12-24 06:19:28476 return true;
initial.commit09911bf2008-07-26 23:55:29477
[email protected]9134cce6d2012-04-10 20:07:53478 if (msg.is_reply()) {
479 received_sync_msgs_->QueueReply(msg, this);
[email protected]a95986a82010-12-24 06:19:28480 return true;
initial.commit09911bf2008-07-26 23:55:29481 }
482
[email protected]9134cce6d2012-04-10 20:07:53483 if (msg.should_unblock()) {
484 received_sync_msgs_->QueueMessage(msg, this);
[email protected]a95986a82010-12-24 06:19:28485 return true;
initial.commit09911bf2008-07-26 23:55:29486 }
487
[email protected]3cdb7af812008-10-24 19:21:13488 return Context::OnMessageReceivedNoFilter(msg);
initial.commit09911bf2008-07-26 23:55:29489}
490
initial.commit09911bf2008-07-26 23:55:29491void SyncChannel::SyncContext::OnChannelError() {
[email protected]3cdb7af812008-10-24 19:21:13492 CancelPendingSends();
[email protected]a4f822702009-02-06 00:44:53493 shutdown_watcher_.StopWatching();
initial.commit09911bf2008-07-26 23:55:29494 Context::OnChannelError();
495}
496
rockot10188752016-09-08 18:24:56497void SyncChannel::SyncContext::OnChannelOpened() {
[email protected]329be052013-02-04 18:14:28498 shutdown_watcher_.StartWatching(
499 shutdown_event_,
rockot3c236292016-07-07 20:26:02500 base::Bind(&SyncChannel::SyncContext::OnShutdownEventSignaled,
Hajime Hoshi138652c92018-01-12 15:11:44501 base::Unretained(this)),
502 ipc_task_runner());
rockot10188752016-09-08 18:24:56503 Context::OnChannelOpened();
initial.commit09911bf2008-07-26 23:55:29504}
505
[email protected]3cdb7af812008-10-24 19:21:13506void SyncChannel::SyncContext::OnChannelClosed() {
[email protected]87339f02010-09-02 21:45:50507 CancelPendingSends();
[email protected]3cdb7af812008-10-24 19:21:13508 shutdown_watcher_.StopWatching();
509 Context::OnChannelClosed();
510}
511
[email protected]3cdb7af812008-10-24 19:21:13512void SyncChannel::SyncContext::CancelPendingSends() {
[email protected]20305ec2011-01-21 04:55:52513 base::AutoLock auto_lock(deserializers_lock_);
rockot3c236292016-07-07 20:26:02514 reject_new_deserializers_ = true;
[email protected]3cdb7af812008-10-24 19:21:13515 PendingSyncMessageQueue::iterator iter;
bauerb3e9be732015-11-03 18:17:47516 DVLOG(1) << "Canceling pending sends";
tzika08b2fd2016-03-30 02:32:59517 for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
518 TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
519 "SyncChannel::SyncContext::CancelPendingSends",
520 iter->done_event);
[email protected]1c4947f2009-01-15 22:25:11521 iter->done_event->Signal();
tzika08b2fd2016-03-30 02:32:59522 }
[email protected]3cdb7af812008-10-24 19:21:13523}
524
rockot3c236292016-07-07 20:26:02525void SyncChannel::SyncContext::OnShutdownEventSignaled(WaitableEvent* event) {
526 DCHECK_EQ(event, shutdown_event_);
[email protected]3cdb7af812008-10-24 19:21:13527
rockot3c236292016-07-07 20:26:02528 // Process shut down before we can get a reply to a synchronous message.
529 // Cancel pending Send calls, which will end up setting the send done event.
530 CancelPendingSends();
[email protected]329be052013-02-04 18:14:28531}
[email protected]3cdb7af812008-10-24 19:21:13532
[email protected]fca876a12014-06-05 16:15:38533// static
danakj03de39b22016-04-23 04:21:09534std::unique_ptr<SyncChannel> SyncChannel::Create(
[email protected]42ce94e2010-12-08 19:28:09535 const IPC::ChannelHandle& channel_handle,
[email protected]3b0e4662014-06-02 20:29:30536 Channel::Mode mode,
[email protected]b7f59e822012-06-29 22:05:26537 Listener* listener,
dchengfd033702014-08-28 16:59:29538 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09539 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]4b580bf2010-12-02 19:16:07540 bool create_pipe_now,
erikchen30dc2812015-09-24 03:26:38541 base::WaitableEvent* shutdown_event) {
danakj03de39b22016-04-23 04:21:09542 std::unique_ptr<SyncChannel> channel =
Hajime Hoshiff15e972017-11-09 06:37:09543 Create(listener, ipc_task_runner, listener_task_runner, shutdown_event);
erikchen30dc2812015-09-24 03:26:38544 channel->Init(channel_handle, mode, create_pipe_now);
dchenge48600452015-12-28 02:24:50545 return channel;
[email protected]fca876a12014-06-05 16:15:38546}
547
548// static
danakj03de39b22016-04-23 04:21:09549std::unique_ptr<SyncChannel> SyncChannel::Create(
550 std::unique_ptr<ChannelFactory> factory,
[email protected]64860882014-08-04 23:44:17551 Listener* listener,
dchengfd033702014-08-28 16:59:29552 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09553 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]64860882014-08-04 23:44:17554 bool create_pipe_now,
555 base::WaitableEvent* shutdown_event) {
danakj03de39b22016-04-23 04:21:09556 std::unique_ptr<SyncChannel> channel =
Hajime Hoshiff15e972017-11-09 06:37:09557 Create(listener, ipc_task_runner, listener_task_runner, shutdown_event);
dchenge48600452015-12-28 02:24:50558 channel->Init(std::move(factory), create_pipe_now);
559 return channel;
[email protected]64860882014-08-04 23:44:17560}
561
562// static
danakj03de39b22016-04-23 04:21:09563std::unique_ptr<SyncChannel> SyncChannel::Create(
[email protected]fca876a12014-06-05 16:15:38564 Listener* listener,
dchengfd033702014-08-28 16:59:29565 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09566 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]fca876a12014-06-05 16:15:38567 WaitableEvent* shutdown_event) {
Hajime Hoshiff15e972017-11-09 06:37:09568 return base::WrapUnique(new SyncChannel(
569 listener, ipc_task_runner, listener_task_runner, shutdown_event));
[email protected]952394af2011-11-16 01:06:46570}
571
572SyncChannel::SyncChannel(
[email protected]b7f59e822012-06-29 22:05:26573 Listener* listener,
dchengfd033702014-08-28 16:59:29574 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09575 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]952394af2011-11-16 01:06:46576 WaitableEvent* shutdown_event)
Hajime Hoshiff15e972017-11-09 06:37:09577 : ChannelProxy(new SyncContext(listener,
578 ipc_task_runner,
579 listener_task_runner,
580 shutdown_event)),
rockotb62e2e32017-03-24 18:36:44581 sync_handle_registry_(mojo::SyncHandleRegistry::current()) {
[email protected]1f9cf472014-04-17 05:07:18582 // The current (listener) thread must be distinct from the IPC thread, or else
583 // sending synchronous messages will deadlock.
dchengff04843f2014-09-03 18:01:16584 DCHECK_NE(ipc_task_runner.get(), base::ThreadTaskRunnerHandle::Get().get());
[email protected]952394af2011-11-16 01:06:46585 StartWatching();
initial.commit09911bf2008-07-26 23:55:29586}
587
Chris Watkins2d879af2017-11-30 02:11:59588SyncChannel::~SyncChannel() = default;
initial.commit09911bf2008-07-26 23:55:29589
[email protected]298ee7d2012-03-30 21:29:30590void SyncChannel::SetRestrictDispatchChannelGroup(int group) {
591 sync_context()->set_restrict_dispatch_group(group);
[email protected]54af05f2011-04-08 03:38:21592}
593
rockotac64ae92f2015-08-06 00:32:29594scoped_refptr<SyncMessageFilter> SyncChannel::CreateSyncMessageFilter() {
595 scoped_refptr<SyncMessageFilter> filter = new SyncMessageFilter(
rockotb97e3d32016-09-16 17:39:03596 sync_context()->shutdown_event());
rockotac64ae92f2015-08-06 00:32:29597 AddFilter(filter.get());
rockot29ade1b2015-08-07 06:23:59598 if (!did_init())
599 pre_init_sync_message_filters_.push_back(filter);
rockotac64ae92f2015-08-06 00:32:29600 return filter;
601}
602
[email protected]3cdb7af812008-10-24 19:21:13603bool SyncChannel::Send(Message* message) {
davidsz041528a2017-05-12 09:19:23604#if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
[email protected]60b2c61f2012-08-22 22:39:57605 std::string name;
rockot9abe09b2016-08-02 20:57:34606 Logging::GetInstance()->GetMessageText(
607 message->type(), &name, message, nullptr);
[email protected]d6cbf052014-05-02 21:29:24608 TRACE_EVENT1("ipc", "SyncChannel::Send", "name", name);
[email protected]60b2c61f2012-08-22 22:39:57609#else
[email protected]d6cbf052014-05-02 21:29:24610 TRACE_EVENT2("ipc", "SyncChannel::Send",
[email protected]60b2c61f2012-08-22 22:39:57611 "class", IPC_MESSAGE_ID_CLASS(message->type()),
612 "line", IPC_MESSAGE_ID_LINE(message->type()));
613#endif
[email protected]3cdb7af812008-10-24 19:21:13614 if (!message->is_sync()) {
John Abd-El-Malekd1d6f6a2017-07-18 20:01:00615 ChannelProxy::SendInternal(message);
[email protected]3cdb7af812008-10-24 19:21:13616 return true;
initial.commit09911bf2008-07-26 23:55:29617 }
618
rockot3c236292016-07-07 20:26:02619 SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
620 bool pump_messages = sync_msg->ShouldPumpMessages();
621
[email protected]3cdb7af812008-10-24 19:21:13622 // *this* might get deleted in WaitForReply.
623 scoped_refptr<SyncContext> context(sync_context());
rockot3c236292016-07-07 20:26:02624 if (!context->Push(sync_msg)) {
625 DVLOG(1) << "Channel is shutting down. Dropping sync message.";
[email protected]3cdb7af812008-10-24 19:21:13626 delete message;
627 return false;
628 }
629
John Abd-El-Malekd1d6f6a2017-07-18 20:01:00630 ChannelProxy::SendInternal(message);
initial.commit09911bf2008-07-26 23:55:29631
[email protected]3cdb7af812008-10-24 19:21:13632 // Wait for reply, or for any other incoming synchronous messages.
rockot9abe09b2016-08-02 20:57:34633 // |this| might get deleted, so only call static functions at this point.
rockot3c236292016-07-07 20:26:02634 scoped_refptr<mojo::SyncHandleRegistry> registry = sync_handle_registry_;
635 WaitForReply(registry.get(), context.get(), pump_messages);
initial.commit09911bf2008-07-26 23:55:29636
tzika08b2fd2016-03-30 02:32:59637 TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
638 "SyncChannel::Send", context->GetSendDoneEvent());
639
[email protected]3cdb7af812008-10-24 19:21:13640 return context->Pop();
initial.commit09911bf2008-07-26 23:55:29641}
642
rockot3c236292016-07-07 20:26:02643void SyncChannel::WaitForReply(mojo::SyncHandleRegistry* registry,
644 SyncContext* context,
645 bool pump_messages) {
[email protected]54af05f2011-04-08 03:38:21646 context->DispatchMessages();
rockot64e65de2016-06-21 20:17:49647
rockotb62e2e32017-03-24 18:36:44648 base::WaitableEvent* pump_messages_event = nullptr;
649 if (pump_messages) {
650 if (!g_pump_messages_event.Get()) {
Jeremy Roman160eb922017-08-29 17:43:43651 g_pump_messages_event.Get() = std::make_unique<base::WaitableEvent>(
rockotb62e2e32017-03-24 18:36:44652 base::WaitableEvent::ResetPolicy::MANUAL,
653 base::WaitableEvent::InitialState::SIGNALED);
654 }
655 pump_messages_event = g_pump_messages_event.Get().get();
656 }
rockot3c236292016-07-07 20:26:02657
658 while (true) {
659 bool dispatch = false;
660 bool send_done = false;
661 bool should_pump_messages = false;
Ken Rockot267df5a2017-08-30 23:31:45662 base::Closure on_send_done_callback = base::Bind(&OnEventReady, &send_done);
663 registry->RegisterEvent(context->GetSendDoneEvent(), on_send_done_callback);
rockotb62e2e32017-03-24 18:36:44664
Ken Rockot267df5a2017-08-30 23:31:45665 base::Closure on_pump_messages_callback;
rockot3c236292016-07-07 20:26:02666 if (pump_messages_event) {
Ken Rockot267df5a2017-08-30 23:31:45667 on_pump_messages_callback =
668 base::Bind(&OnEventReady, &should_pump_messages);
669 registry->RegisterEvent(pump_messages_event, on_pump_messages_callback);
rockot3c236292016-07-07 20:26:02670 }
671
672 const bool* stop_flags[] = { &dispatch, &send_done, &should_pump_messages };
rockot9abe09b2016-08-02 20:57:34673 context->received_sync_msgs()->BlockDispatch(&dispatch);
rockotb62e2e32017-03-24 18:36:44674 registry->Wait(stop_flags, 3);
rockot9abe09b2016-08-02 20:57:34675 context->received_sync_msgs()->UnblockDispatch();
rockot3c236292016-07-07 20:26:02676
Ken Rockot267df5a2017-08-30 23:31:45677 registry->UnregisterEvent(context->GetSendDoneEvent(),
678 on_send_done_callback);
rockot3c236292016-07-07 20:26:02679 if (pump_messages_event)
Ken Rockot267df5a2017-08-30 23:31:45680 registry->UnregisterEvent(pump_messages_event, on_pump_messages_callback);
rockot3c236292016-07-07 20:26:02681
682 if (dispatch) {
rockot9abe09b2016-08-02 20:57:34683 // We're waiting for a reply, but we received a blocking synchronous call.
684 // We must process it to avoid potential deadlocks.
[email protected]9eec2252009-12-01 02:34:18685 context->GetDispatchEvent()->Reset();
686 context->DispatchMessages();
[email protected]3cdb7af812008-10-24 19:21:13687 continue;
688 }
689
rockot3c236292016-07-07 20:26:02690 if (should_pump_messages)
gab2998ee72017-05-05 16:23:50691 WaitForReplyWithNestedMessageLoop(context); // Run a nested run loop.
[email protected]3cdb7af812008-10-24 19:21:13692
693 break;
694 }
695}
696
[email protected]9eec2252009-12-01 02:34:18697void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) {
Gabriel Charette43b8bf32017-11-08 20:24:43698 base::RunLoop nested_loop(base::RunLoop::Type::kNestableTasksAllowed);
Hajime Hoshi138652c92018-01-12 15:11:44699 ReceivedSyncMsgQueue::NestedSendDoneWatcher watcher(
700 context, &nested_loop, context->listener_task_runner());
rockotb62e2e32017-03-24 18:36:44701 nested_loop.Run();
[email protected]3cdb7af812008-10-24 19:21:13702}
703
rockotb62e2e32017-03-24 18:36:44704void SyncChannel::OnDispatchEventSignaled(base::WaitableEvent* event) {
705 DCHECK_EQ(sync_context()->GetDispatchEvent(), event);
yzshen1bd23702016-11-30 21:54:51706 sync_context()->GetDispatchEvent()->Reset();
rockotb62e2e32017-03-24 18:36:44707
708 StartWatching();
709
710 // NOTE: May delete |this|.
yzshen1bd23702016-11-30 21:54:51711 sync_context()->DispatchMessages();
initial.commit09911bf2008-07-26 23:55:29712}
713
[email protected]952394af2011-11-16 01:06:46714void SyncChannel::StartWatching() {
rockot9abe09b2016-08-02 20:57:34715 // |dispatch_watcher_| watches the event asynchronously, only dispatching
716 // messages once the listener thread is unblocked and pumping its task queue.
717 // The ReceivedSyncMsgQueue also watches this event and may dispatch
718 // immediately if woken up by a message which it's allowed to dispatch.
rockotb62e2e32017-03-24 18:36:44719 dispatch_watcher_.StartWatching(
720 sync_context()->GetDispatchEvent(),
Hajime Hoshi138652c92018-01-12 15:11:44721 base::BindOnce(&SyncChannel::OnDispatchEventSignaled,
722 base::Unretained(this)),
723 sync_context()->listener_task_runner());
[email protected]952394af2011-11-16 01:06:46724}
725
rockot29ade1b2015-08-07 06:23:59726void SyncChannel::OnChannelInit() {
rockot29ade1b2015-08-07 06:23:59727 pre_init_sync_message_filters_.clear();
728}
729
initial.commit09911bf2008-07-26 23:55:29730} // namespace IPC