blob: 2100b61d0421faa59c42808ba3ba8ae45aad78a7 [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,
87 base::RunLoop* run_loop)
88 : sync_msg_queue_(context->received_sync_msgs()),
89 outer_state_(sync_msg_queue_->top_send_done_event_watcher_),
90 event_(context->GetSendDoneEvent()),
91 callback_(
tzik130cfd0c2017-04-18 03:49:0592 base::BindOnce(&SyncChannel::SyncContext::OnSendDoneEventSignaled,
93 context,
94 run_loop)) {
rockotb62e2e32017-03-24 18:36:4495 sync_msg_queue_->top_send_done_event_watcher_ = this;
96 if (outer_state_)
97 outer_state_->StopWatching();
98 StartWatching();
99 }
100
101 ~NestedSendDoneWatcher() {
102 sync_msg_queue_->top_send_done_event_watcher_ = outer_state_;
103 if (outer_state_)
104 outer_state_->StartWatching();
105 }
106
107 private:
tzik130cfd0c2017-04-18 03:49:05108 void Run(WaitableEvent* event) {
109 DCHECK(callback_);
110 std::move(callback_).Run(event);
111 }
112
113 void StartWatching() {
114 watcher_.StartWatching(event_, base::BindOnce(&NestedSendDoneWatcher::Run,
115 base::Unretained(this)));
116 }
117
rockotb62e2e32017-03-24 18:36:44118 void StopWatching() { watcher_.StopWatching(); }
119
120 ReceivedSyncMsgQueue* const sync_msg_queue_;
121 NestedSendDoneWatcher* const outer_state_;
122
123 base::WaitableEvent* const event_;
tzik130cfd0c2017-04-18 03:49:05124 base::WaitableEventWatcher::EventCallback callback_;
rockotb62e2e32017-03-24 18:36:44125 base::WaitableEventWatcher watcher_;
126
127 DISALLOW_COPY_AND_ASSIGN(NestedSendDoneWatcher);
128 };
129
[email protected]3cdb7af812008-10-24 19:21:13130 // Returns the ReceivedSyncMsgQueue instance for this thread, creating one
[email protected]d3ae7a072008-12-05 20:27:20131 // if necessary. Call RemoveContext on the same thread when done.
132 static ReceivedSyncMsgQueue* AddContext() {
[email protected]3cdb7af812008-10-24 19:21:13133 // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple
134 // SyncChannel objects can block the same thread).
135 ReceivedSyncMsgQueue* rv = lazy_tls_ptr_.Pointer()->Get();
136 if (!rv) {
137 rv = new ReceivedSyncMsgQueue();
138 ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Set(rv);
139 }
140 rv->listener_count_++;
141 return rv;
initial.commit09911bf2008-07-26 23:55:29142 }
143
rockot9abe09b2016-08-02 20:57:34144 // Prevents messages from being dispatched immediately when the dispatch event
145 // is signaled. Instead, |*dispatch_flag| will be set.
146 void BlockDispatch(bool* dispatch_flag) { dispatch_flag_ = dispatch_flag; }
147
148 // Allows messages to be dispatched immediately when the dispatch event is
149 // signaled.
150 void UnblockDispatch() { dispatch_flag_ = nullptr; }
151
initial.commit09911bf2008-07-26 23:55:29152 // Called on IPC thread when a synchronous message or reply arrives.
[email protected]d3ae7a072008-12-05 20:27:20153 void QueueMessage(const Message& msg, SyncChannel::SyncContext* context) {
initial.commit09911bf2008-07-26 23:55:29154 bool was_task_pending;
155 {
[email protected]20305ec2011-01-21 04:55:52156 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29157
158 was_task_pending = task_pending_;
159 task_pending_ = true;
160
161 // We set the event in case the listener thread is blocked (or is about
162 // to). In case it's not, the PostTask dispatches the messages.
[email protected]d3ae7a072008-12-05 20:27:20163 message_queue_.push_back(QueuedMessage(new Message(msg), context));
[email protected]522cc10d2012-01-11 22:39:54164 message_queue_version_++;
initial.commit09911bf2008-07-26 23:55:29165 }
166
[email protected]1c4947f2009-01-15 22:25:11167 dispatch_event_.Signal();
initial.commit09911bf2008-07-26 23:55:29168 if (!was_task_pending) {
[email protected]b2432302012-07-02 21:15:52169 listener_task_runner_->PostTask(
[email protected]72b6f8e22011-11-12 21:16:41170 FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchMessagesTask,
vmpstra34d11322016-03-21 20:28:47171 this, base::RetainedRef(context)));
initial.commit09911bf2008-07-26 23:55:29172 }
173 }
174
175 void QueueReply(const Message &msg, SyncChannel::SyncContext* context) {
[email protected]d3ae7a072008-12-05 20:27:20176 received_replies_.push_back(QueuedMessage(new Message(msg), context));
initial.commit09911bf2008-07-26 23:55:29177 }
178
[email protected]d3ae7a072008-12-05 20:27:20179 // Called on the listener's thread to process any queues synchronous
initial.commit09911bf2008-07-26 23:55:29180 // messages.
[email protected]54af05f2011-04-08 03:38:21181 void DispatchMessagesTask(SyncContext* context) {
initial.commit09911bf2008-07-26 23:55:29182 {
[email protected]20305ec2011-01-21 04:55:52183 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29184 task_pending_ = false;
185 }
[email protected]54af05f2011-04-08 03:38:21186 context->DispatchMessages();
initial.commit09911bf2008-07-26 23:55:29187 }
188
rockot9abe09b2016-08-02 20:57:34189 // Dispatches any queued incoming sync messages. If |dispatching_context| is
190 // not null, messages which target a restricted dispatch channel will only be
191 // dispatched if |dispatching_context| belongs to the same restricted dispatch
192 // group as that channel. If |dispatching_context| is null, all queued
193 // messages are dispatched.
[email protected]54af05f2011-04-08 03:38:21194 void DispatchMessages(SyncContext* dispatching_context) {
[email protected]522cc10d2012-01-11 22:39:54195 bool first_time = true;
tfarina10a5c062015-09-04 18:47:57196 uint32_t expected_version = 0;
[email protected]522cc10d2012-01-11 22:39:54197 SyncMessageQueue::iterator it;
initial.commit09911bf2008-07-26 23:55:29198 while (true) {
rockot9abe09b2016-08-02 20:57:34199 Message* message = nullptr;
[email protected]d3ae7a072008-12-05 20:27:20200 scoped_refptr<SyncChannel::SyncContext> context;
initial.commit09911bf2008-07-26 23:55:29201 {
[email protected]20305ec2011-01-21 04:55:52202 base::AutoLock auto_lock(message_lock_);
[email protected]522cc10d2012-01-11 22:39:54203 if (first_time || message_queue_version_ != expected_version) {
204 it = message_queue_.begin();
205 first_time = false;
[email protected]54af05f2011-04-08 03:38:21206 }
[email protected]522cc10d2012-01-11 22:39:54207 for (; it != message_queue_.end(); it++) {
[email protected]298ee7d2012-03-30 21:29:30208 int message_group = it->context->restrict_dispatch_group();
rockot9abe09b2016-08-02 20:57:34209 if (!dispatching_context ||
210 message_group == kRestrictDispatchGroup_None ||
[email protected]298ee7d2012-03-30 21:29:30211 message_group == dispatching_context->restrict_dispatch_group()) {
[email protected]522cc10d2012-01-11 22:39:54212 message = it->message;
213 context = it->context;
214 it = message_queue_.erase(it);
215 message_queue_version_++;
216 expected_version = message_queue_version_;
217 break;
218 }
219 }
220 }
initial.commit09911bf2008-07-26 23:55:29221
rockot9abe09b2016-08-02 20:57:34222 if (message == nullptr)
[email protected]522cc10d2012-01-11 22:39:54223 break;
224 context->OnDispatchMessage(*message);
225 delete message;
initial.commit09911bf2008-07-26 23:55:29226 }
227 }
228
initial.commit09911bf2008-07-26 23:55:29229 // SyncChannel calls this in its destructor.
[email protected]d3ae7a072008-12-05 20:27:20230 void RemoveContext(SyncContext* context) {
[email protected]20305ec2011-01-21 04:55:52231 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29232
[email protected]d3ae7a072008-12-05 20:27:20233 SyncMessageQueue::iterator iter = message_queue_.begin();
234 while (iter != message_queue_.end()) {
[email protected]17571642013-06-01 04:11:27235 if (iter->context.get() == context) {
[email protected]d3ae7a072008-12-05 20:27:20236 delete iter->message;
237 iter = message_queue_.erase(iter);
[email protected]522cc10d2012-01-11 22:39:54238 message_queue_version_++;
initial.commit09911bf2008-07-26 23:55:29239 } else {
[email protected]d3ae7a072008-12-05 20:27:20240 iter++;
initial.commit09911bf2008-07-26 23:55:29241 }
initial.commit09911bf2008-07-26 23:55:29242 }
[email protected]3cdb7af812008-10-24 19:21:13243
244 if (--listener_count_ == 0) {
245 DCHECK(lazy_tls_ptr_.Pointer()->Get());
rockot9abe09b2016-08-02 20:57:34246 lazy_tls_ptr_.Pointer()->Set(nullptr);
247 sync_dispatch_watcher_.reset();
[email protected]3cdb7af812008-10-24 19:21:13248 }
initial.commit09911bf2008-07-26 23:55:29249 }
250
rockotb62e2e32017-03-24 18:36:44251 base::WaitableEvent* dispatch_event() { return &dispatch_event_; }
[email protected]b2432302012-07-02 21:15:52252 base::SingleThreadTaskRunner* listener_task_runner() {
[email protected]17571642013-06-01 04:11:27253 return listener_task_runner_.get();
[email protected]92bf9062011-05-02 18:00:49254 }
initial.commit09911bf2008-07-26 23:55:29255
[email protected]f886b7bf2008-09-10 10:54:06256 // Holds a pointer to the per-thread ReceivedSyncMsgQueue object.
scottmg5e65e3a2017-03-08 08:48:46257 static base::LazyInstance<base::ThreadLocalPointer<ReceivedSyncMsgQueue>>::
258 DestructorAtExit lazy_tls_ptr_;
[email protected]f886b7bf2008-09-10 10:54:06259
initial.commit09911bf2008-07-26 23:55:29260 // Called on the ipc thread to check if we can unblock any current Send()
261 // calls based on a queued reply.
262 void DispatchReplies() {
initial.commit09911bf2008-07-26 23:55:29263 for (size_t i = 0; i < received_replies_.size(); ++i) {
264 Message* message = received_replies_[i].message;
[email protected]3cdb7af812008-10-24 19:21:13265 if (received_replies_[i].context->TryToUnblockListener(message)) {
initial.commit09911bf2008-07-26 23:55:29266 delete message;
267 received_replies_.erase(received_replies_.begin() + i);
268 return;
269 }
270 }
271 }
272
[email protected]63a7bb82008-10-25 00:46:00273 private:
[email protected]877d55d2009-11-05 21:53:08274 friend class base::RefCountedThreadSafe<ReceivedSyncMsgQueue>;
275
[email protected]4df10d612008-11-12 00:38:26276 // See the comment in SyncChannel::SyncChannel for why this event is created
277 // as manual reset.
gab90c2c5c2016-06-01 20:34:06278 ReceivedSyncMsgQueue()
279 : message_queue_version_(0),
rockotb62e2e32017-03-24 18:36:44280 dispatch_event_(base::WaitableEvent::ResetPolicy::MANUAL,
281 base::WaitableEvent::InitialState::NOT_SIGNALED),
gab90c2c5c2016-06-01 20:34:06282 listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
Jeremy Roman160eb922017-08-29 17:43:43283 sync_dispatch_watcher_(std::make_unique<mojo::SyncEventWatcher>(
rockotb62e2e32017-03-24 18:36:44284 &dispatch_event_,
285 base::Bind(&ReceivedSyncMsgQueue::OnDispatchEventReady,
286 base::Unretained(this)))) {
rockot9abe09b2016-08-02 20:57:34287 sync_dispatch_watcher_->AllowWokenUpBySyncWatchOnSameThread();
288 }
[email protected]63a7bb82008-10-25 00:46:00289
[email protected]877d55d2009-11-05 21:53:08290 ~ReceivedSyncMsgQueue() {}
291
rockotb62e2e32017-03-24 18:36:44292 void OnDispatchEventReady() {
rockot9abe09b2016-08-02 20:57:34293 if (dispatch_flag_) {
294 *dispatch_flag_ = true;
295 return;
296 }
297
298 // We were woken up during a sync wait, but no specific SyncChannel is
299 // currently waiting. i.e., some other Mojo interface on this thread is
300 // waiting for a response. Since we don't support anything analogous to
301 // restricted dispatch on Mojo interfaces, in this case it's safe to
302 // dispatch sync messages for any context.
303 DispatchMessages(nullptr);
304 }
305
[email protected]d3ae7a072008-12-05 20:27:20306 // Holds information about a queued synchronous message or reply.
307 struct QueuedMessage {
308 QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { }
initial.commit09911bf2008-07-26 23:55:29309 Message* message;
310 scoped_refptr<SyncChannel::SyncContext> context;
311 };
312
[email protected]522cc10d2012-01-11 22:39:54313 typedef std::list<QueuedMessage> SyncMessageQueue;
[email protected]1c4947f2009-01-15 22:25:11314 SyncMessageQueue message_queue_;
rockotb62e2e32017-03-24 18:36:44315
316 // Used to signal DispatchMessages to rescan
317 uint32_t message_queue_version_ = 0;
[email protected]d3ae7a072008-12-05 20:27:20318
319 std::vector<QueuedMessage> received_replies_;
[email protected]3cdb7af812008-10-24 19:21:13320
rockot3c236292016-07-07 20:26:02321 // Signaled when we get a synchronous message that we must respond to, as the
[email protected]3cdb7af812008-10-24 19:21:13322 // sender needs its reply before it can reply to our original synchronous
323 // message.
rockotb62e2e32017-03-24 18:36:44324 base::WaitableEvent dispatch_event_;
[email protected]b2432302012-07-02 21:15:52325 scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
[email protected]20305ec2011-01-21 04:55:52326 base::Lock message_lock_;
rockotb62e2e32017-03-24 18:36:44327 bool task_pending_ = false;
328 int listener_count_ = 0;
[email protected]ac0efda2009-10-14 16:22:02329
rockotb62e2e32017-03-24 18:36:44330 // The current NestedSendDoneWatcher for this thread, if we're currently
331 // in a SyncChannel::WaitForReplyWithNestedMessageLoop. See
332 // NestedSendDoneWatcher comments for more details.
333 NestedSendDoneWatcher* top_send_done_event_watcher_ = nullptr;
rockot9abe09b2016-08-02 20:57:34334
335 // If not null, the address of a flag to set when the dispatch event signals,
336 // in lieu of actually dispatching messages. This is used by
337 // SyncChannel::WaitForReply to restrict the scope of queued messages we're
338 // allowed to process while it's waiting.
339 bool* dispatch_flag_ = nullptr;
340
341 // Watches |dispatch_event_| during all sync handle watches on this thread.
rockotb62e2e32017-03-24 18:36:44342 std::unique_ptr<mojo::SyncEventWatcher> sync_dispatch_watcher_;
initial.commit09911bf2008-07-26 23:55:29343};
344
scottmg5e65e3a2017-03-08 08:48:46345base::LazyInstance<base::ThreadLocalPointer<
346 SyncChannel::ReceivedSyncMsgQueue>>::DestructorAtExit
[email protected]6de0fd1d2011-11-15 13:31:49347 SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_ =
348 LAZY_INSTANCE_INITIALIZER;
initial.commit09911bf2008-07-26 23:55:29349
350SyncChannel::SyncContext::SyncContext(
[email protected]b7f59e822012-06-29 22:05:26351 Listener* listener,
dchengfd033702014-08-28 16:59:29352 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09353 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]1c4947f2009-01-15 22:25:11354 WaitableEvent* shutdown_event)
Hajime Hoshiff15e972017-11-09 06:37:09355 : ChannelProxy::Context(listener, ipc_task_runner, listener_task_runner),
[email protected]1c4947f2009-01-15 22:25:11356 received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()),
[email protected]54af05f2011-04-08 03:38:21357 shutdown_event_(shutdown_event),
Hajime Hoshiff15e972017-11-09 06:37:09358 restrict_dispatch_group_(kRestrictDispatchGroup_None) {}
initial.commit09911bf2008-07-26 23:55:29359
rockotb62e2e32017-03-24 18:36:44360void SyncChannel::SyncContext::OnSendDoneEventSignaled(
361 base::RunLoop* nested_loop,
362 base::WaitableEvent* event) {
363 DCHECK_EQ(GetSendDoneEvent(), event);
364 nested_loop->Quit();
365}
366
initial.commit09911bf2008-07-26 23:55:29367SyncChannel::SyncContext::~SyncContext() {
368 while (!deserializers_.empty())
[email protected]3cdb7af812008-10-24 19:21:13369 Pop();
initial.commit09911bf2008-07-26 23:55:29370}
371
372// Adds information about an outgoing sync message to the context so that
rockot3c236292016-07-07 20:26:02373// we know how to deserialize the reply. Returns |true| if the message was added
374// to the context or |false| if it was rejected (e.g. due to shutdown.)
375bool SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
[email protected]4a180a52011-04-15 19:07:43376 // Create the tracking information for this message. This object is stored
377 // by value since all members are pointers that are cheap to copy. These
378 // pointers are cleaned up in the Pop() function.
379 //
[email protected]1c4947f2009-01-15 22:25:11380 // The event is created as manual reset because in between Signal and
[email protected]4df10d612008-11-12 00:38:26381 // OnObjectSignalled, another Send can happen which would stop the watcher
382 // from being called. The event would get watched later, when the nested
383 // Send completes, so the event will need to remain set.
rockot3c236292016-07-07 20:26:02384 base::AutoLock auto_lock(deserializers_lock_);
385 if (reject_new_deserializers_)
386 return false;
gab90c2c5c2016-06-01 20:34:06387 PendingSyncMsg pending(
388 SyncMessage::GetMessageId(*sync_msg), sync_msg->GetReplyDeserializer(),
rockotb62e2e32017-03-24 18:36:44389 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
390 base::WaitableEvent::InitialState::NOT_SIGNALED));
[email protected]3cdb7af812008-10-24 19:21:13391 deserializers_.push_back(pending);
rockot3c236292016-07-07 20:26:02392 return true;
initial.commit09911bf2008-07-26 23:55:29393}
394
[email protected]3cdb7af812008-10-24 19:21:13395bool SyncChannel::SyncContext::Pop() {
[email protected]63a7bb82008-10-25 00:46:00396 bool result;
397 {
[email protected]20305ec2011-01-21 04:55:52398 base::AutoLock auto_lock(deserializers_lock_);
[email protected]63a7bb82008-10-25 00:46:00399 PendingSyncMsg msg = deserializers_.back();
400 delete msg.deserializer;
[email protected]1c4947f2009-01-15 22:25:11401 delete msg.done_event;
rockot3c236292016-07-07 20:26:02402 msg.done_event = nullptr;
[email protected]63a7bb82008-10-25 00:46:00403 deserializers_.pop_back();
404 result = msg.send_result;
405 }
406
407 // We got a reply to a synchronous Send() call that's blocking the listener
408 // thread. However, further down the call stack there could be another
409 // blocking Send() call, whose reply we received after we made this last
410 // Send() call. So check if we have any queued replies available that
411 // can now unblock the listener thread.
[email protected]b2432302012-07-02 21:15:52412 ipc_task_runner()->PostTask(
[email protected]72b6f8e22011-11-12 21:16:41413 FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchReplies,
tzik07cace42016-09-01 04:21:25414 received_sync_msgs_));
[email protected]63a7bb82008-10-25 00:46:00415
416 return result;
[email protected]3cdb7af812008-10-24 19:21:13417}
418
rockotb62e2e32017-03-24 18:36:44419base::WaitableEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
[email protected]20305ec2011-01-21 04:55:52420 base::AutoLock auto_lock(deserializers_lock_);
[email protected]3cdb7af812008-10-24 19:21:13421 return deserializers_.back().done_event;
422}
423
rockotb62e2e32017-03-24 18:36:44424base::WaitableEvent* SyncChannel::SyncContext::GetDispatchEvent() {
[email protected]3cdb7af812008-10-24 19:21:13425 return received_sync_msgs_->dispatch_event();
initial.commit09911bf2008-07-26 23:55:29426}
427
428void SyncChannel::SyncContext::DispatchMessages() {
[email protected]54af05f2011-04-08 03:38:21429 received_sync_msgs_->DispatchMessages(this);
initial.commit09911bf2008-07-26 23:55:29430}
431
[email protected]3cdb7af812008-10-24 19:21:13432bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) {
[email protected]20305ec2011-01-21 04:55:52433 base::AutoLock auto_lock(deserializers_lock_);
[email protected]63a7bb82008-10-25 00:46:00434 if (deserializers_.empty() ||
435 !SyncMessage::IsMessageReplyTo(*msg, deserializers_.back().id)) {
436 return false;
[email protected]3cdb7af812008-10-24 19:21:13437 }
initial.commit09911bf2008-07-26 23:55:29438
[email protected]63a7bb82008-10-25 00:46:00439 if (!msg->is_reply_error()) {
[email protected]211142cd2012-08-13 09:41:19440 bool send_result = deserializers_.back().deserializer->
[email protected]63a7bb82008-10-25 00:46:00441 SerializeOutputParameters(*msg);
[email protected]211142cd2012-08-13 09:41:19442 deserializers_.back().send_result = send_result;
bauerb3e9be732015-11-03 18:17:47443 DVLOG_IF(1, !send_result) << "Couldn't deserialize reply message";
[email protected]211142cd2012-08-13 09:41:19444 } else {
bauerb3e9be732015-11-03 18:17:47445 DVLOG(1) << "Received error reply";
[email protected]63a7bb82008-10-25 00:46:00446 }
tzika08b2fd2016-03-30 02:32:59447
rockotb62e2e32017-03-24 18:36:44448 base::WaitableEvent* done_event = deserializers_.back().done_event;
tzika08b2fd2016-03-30 02:32:59449 TRACE_EVENT_FLOW_BEGIN0(
450 TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
451 "SyncChannel::SyncContext::TryToUnblockListener", done_event);
452
453 done_event->Signal();
initial.commit09911bf2008-07-26 23:55:29454
[email protected]3cdb7af812008-10-24 19:21:13455 return true;
initial.commit09911bf2008-07-26 23:55:29456}
457
[email protected]3cdb7af812008-10-24 19:21:13458void SyncChannel::SyncContext::Clear() {
459 CancelPendingSends();
[email protected]d3ae7a072008-12-05 20:27:20460 received_sync_msgs_->RemoveContext(this);
[email protected]3cdb7af812008-10-24 19:21:13461 Context::Clear();
462}
463
[email protected]a95986a82010-12-24 06:19:28464bool SyncChannel::SyncContext::OnMessageReceived(const Message& msg) {
[email protected]d65cab7a2008-08-12 01:25:41465 // Give the filters a chance at processing this message.
466 if (TryFilters(msg))
[email protected]a95986a82010-12-24 06:19:28467 return true;
[email protected]d65cab7a2008-08-12 01:25:41468
[email protected]3cdb7af812008-10-24 19:21:13469 if (TryToUnblockListener(&msg))
[email protected]a95986a82010-12-24 06:19:28470 return true;
initial.commit09911bf2008-07-26 23:55:29471
[email protected]9134cce6d2012-04-10 20:07:53472 if (msg.is_reply()) {
473 received_sync_msgs_->QueueReply(msg, this);
[email protected]a95986a82010-12-24 06:19:28474 return true;
initial.commit09911bf2008-07-26 23:55:29475 }
476
[email protected]9134cce6d2012-04-10 20:07:53477 if (msg.should_unblock()) {
478 received_sync_msgs_->QueueMessage(msg, this);
[email protected]a95986a82010-12-24 06:19:28479 return true;
initial.commit09911bf2008-07-26 23:55:29480 }
481
[email protected]3cdb7af812008-10-24 19:21:13482 return Context::OnMessageReceivedNoFilter(msg);
initial.commit09911bf2008-07-26 23:55:29483}
484
initial.commit09911bf2008-07-26 23:55:29485void SyncChannel::SyncContext::OnChannelError() {
[email protected]3cdb7af812008-10-24 19:21:13486 CancelPendingSends();
[email protected]a4f822702009-02-06 00:44:53487 shutdown_watcher_.StopWatching();
initial.commit09911bf2008-07-26 23:55:29488 Context::OnChannelError();
489}
490
rockot10188752016-09-08 18:24:56491void SyncChannel::SyncContext::OnChannelOpened() {
[email protected]329be052013-02-04 18:14:28492 shutdown_watcher_.StartWatching(
493 shutdown_event_,
rockot3c236292016-07-07 20:26:02494 base::Bind(&SyncChannel::SyncContext::OnShutdownEventSignaled,
[email protected]329be052013-02-04 18:14:28495 base::Unretained(this)));
rockot10188752016-09-08 18:24:56496 Context::OnChannelOpened();
initial.commit09911bf2008-07-26 23:55:29497}
498
[email protected]3cdb7af812008-10-24 19:21:13499void SyncChannel::SyncContext::OnChannelClosed() {
[email protected]87339f02010-09-02 21:45:50500 CancelPendingSends();
[email protected]3cdb7af812008-10-24 19:21:13501 shutdown_watcher_.StopWatching();
502 Context::OnChannelClosed();
503}
504
[email protected]3cdb7af812008-10-24 19:21:13505void SyncChannel::SyncContext::CancelPendingSends() {
[email protected]20305ec2011-01-21 04:55:52506 base::AutoLock auto_lock(deserializers_lock_);
rockot3c236292016-07-07 20:26:02507 reject_new_deserializers_ = true;
[email protected]3cdb7af812008-10-24 19:21:13508 PendingSyncMessageQueue::iterator iter;
bauerb3e9be732015-11-03 18:17:47509 DVLOG(1) << "Canceling pending sends";
tzika08b2fd2016-03-30 02:32:59510 for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
511 TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
512 "SyncChannel::SyncContext::CancelPendingSends",
513 iter->done_event);
[email protected]1c4947f2009-01-15 22:25:11514 iter->done_event->Signal();
tzika08b2fd2016-03-30 02:32:59515 }
[email protected]3cdb7af812008-10-24 19:21:13516}
517
rockot3c236292016-07-07 20:26:02518void SyncChannel::SyncContext::OnShutdownEventSignaled(WaitableEvent* event) {
519 DCHECK_EQ(event, shutdown_event_);
[email protected]3cdb7af812008-10-24 19:21:13520
rockot3c236292016-07-07 20:26:02521 // Process shut down before we can get a reply to a synchronous message.
522 // Cancel pending Send calls, which will end up setting the send done event.
523 CancelPendingSends();
[email protected]329be052013-02-04 18:14:28524}
[email protected]3cdb7af812008-10-24 19:21:13525
[email protected]fca876a12014-06-05 16:15:38526// static
danakj03de39b22016-04-23 04:21:09527std::unique_ptr<SyncChannel> SyncChannel::Create(
[email protected]42ce94e2010-12-08 19:28:09528 const IPC::ChannelHandle& channel_handle,
[email protected]3b0e4662014-06-02 20:29:30529 Channel::Mode mode,
[email protected]b7f59e822012-06-29 22:05:26530 Listener* listener,
dchengfd033702014-08-28 16:59:29531 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09532 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]4b580bf2010-12-02 19:16:07533 bool create_pipe_now,
erikchen30dc2812015-09-24 03:26:38534 base::WaitableEvent* shutdown_event) {
danakj03de39b22016-04-23 04:21:09535 std::unique_ptr<SyncChannel> channel =
Hajime Hoshiff15e972017-11-09 06:37:09536 Create(listener, ipc_task_runner, listener_task_runner, shutdown_event);
erikchen30dc2812015-09-24 03:26:38537 channel->Init(channel_handle, mode, create_pipe_now);
dchenge48600452015-12-28 02:24:50538 return channel;
[email protected]fca876a12014-06-05 16:15:38539}
540
541// static
danakj03de39b22016-04-23 04:21:09542std::unique_ptr<SyncChannel> SyncChannel::Create(
543 std::unique_ptr<ChannelFactory> factory,
[email protected]64860882014-08-04 23:44:17544 Listener* listener,
dchengfd033702014-08-28 16:59:29545 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09546 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]64860882014-08-04 23:44:17547 bool create_pipe_now,
548 base::WaitableEvent* shutdown_event) {
danakj03de39b22016-04-23 04:21:09549 std::unique_ptr<SyncChannel> channel =
Hajime Hoshiff15e972017-11-09 06:37:09550 Create(listener, ipc_task_runner, listener_task_runner, shutdown_event);
dchenge48600452015-12-28 02:24:50551 channel->Init(std::move(factory), create_pipe_now);
552 return channel;
[email protected]64860882014-08-04 23:44:17553}
554
555// static
danakj03de39b22016-04-23 04:21:09556std::unique_ptr<SyncChannel> SyncChannel::Create(
[email protected]fca876a12014-06-05 16:15:38557 Listener* listener,
dchengfd033702014-08-28 16:59:29558 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09559 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]fca876a12014-06-05 16:15:38560 WaitableEvent* shutdown_event) {
Hajime Hoshiff15e972017-11-09 06:37:09561 return base::WrapUnique(new SyncChannel(
562 listener, ipc_task_runner, listener_task_runner, shutdown_event));
[email protected]952394af2011-11-16 01:06:46563}
564
565SyncChannel::SyncChannel(
[email protected]b7f59e822012-06-29 22:05:26566 Listener* listener,
dchengfd033702014-08-28 16:59:29567 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
Hajime Hoshiff15e972017-11-09 06:37:09568 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner,
[email protected]952394af2011-11-16 01:06:46569 WaitableEvent* shutdown_event)
Hajime Hoshiff15e972017-11-09 06:37:09570 : ChannelProxy(new SyncContext(listener,
571 ipc_task_runner,
572 listener_task_runner,
573 shutdown_event)),
rockotb62e2e32017-03-24 18:36:44574 sync_handle_registry_(mojo::SyncHandleRegistry::current()) {
[email protected]1f9cf472014-04-17 05:07:18575 // The current (listener) thread must be distinct from the IPC thread, or else
576 // sending synchronous messages will deadlock.
dchengff04843f2014-09-03 18:01:16577 DCHECK_NE(ipc_task_runner.get(), base::ThreadTaskRunnerHandle::Get().get());
[email protected]952394af2011-11-16 01:06:46578 StartWatching();
initial.commit09911bf2008-07-26 23:55:29579}
580
581SyncChannel::~SyncChannel() {
initial.commit09911bf2008-07-26 23:55:29582}
583
[email protected]298ee7d2012-03-30 21:29:30584void SyncChannel::SetRestrictDispatchChannelGroup(int group) {
585 sync_context()->set_restrict_dispatch_group(group);
[email protected]54af05f2011-04-08 03:38:21586}
587
rockotac64ae92f2015-08-06 00:32:29588scoped_refptr<SyncMessageFilter> SyncChannel::CreateSyncMessageFilter() {
589 scoped_refptr<SyncMessageFilter> filter = new SyncMessageFilter(
rockotb97e3d32016-09-16 17:39:03590 sync_context()->shutdown_event());
rockotac64ae92f2015-08-06 00:32:29591 AddFilter(filter.get());
rockot29ade1b2015-08-07 06:23:59592 if (!did_init())
593 pre_init_sync_message_filters_.push_back(filter);
rockotac64ae92f2015-08-06 00:32:29594 return filter;
595}
596
[email protected]3cdb7af812008-10-24 19:21:13597bool SyncChannel::Send(Message* message) {
davidsz041528a2017-05-12 09:19:23598#if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
[email protected]60b2c61f2012-08-22 22:39:57599 std::string name;
rockot9abe09b2016-08-02 20:57:34600 Logging::GetInstance()->GetMessageText(
601 message->type(), &name, message, nullptr);
[email protected]d6cbf052014-05-02 21:29:24602 TRACE_EVENT1("ipc", "SyncChannel::Send", "name", name);
[email protected]60b2c61f2012-08-22 22:39:57603#else
[email protected]d6cbf052014-05-02 21:29:24604 TRACE_EVENT2("ipc", "SyncChannel::Send",
[email protected]60b2c61f2012-08-22 22:39:57605 "class", IPC_MESSAGE_ID_CLASS(message->type()),
606 "line", IPC_MESSAGE_ID_LINE(message->type()));
607#endif
[email protected]3cdb7af812008-10-24 19:21:13608 if (!message->is_sync()) {
John Abd-El-Malekd1d6f6a2017-07-18 20:01:00609 ChannelProxy::SendInternal(message);
[email protected]3cdb7af812008-10-24 19:21:13610 return true;
initial.commit09911bf2008-07-26 23:55:29611 }
612
rockot3c236292016-07-07 20:26:02613 SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
614 bool pump_messages = sync_msg->ShouldPumpMessages();
615
[email protected]3cdb7af812008-10-24 19:21:13616 // *this* might get deleted in WaitForReply.
617 scoped_refptr<SyncContext> context(sync_context());
rockot3c236292016-07-07 20:26:02618 if (!context->Push(sync_msg)) {
619 DVLOG(1) << "Channel is shutting down. Dropping sync message.";
[email protected]3cdb7af812008-10-24 19:21:13620 delete message;
621 return false;
622 }
623
John Abd-El-Malekd1d6f6a2017-07-18 20:01:00624 ChannelProxy::SendInternal(message);
initial.commit09911bf2008-07-26 23:55:29625
[email protected]3cdb7af812008-10-24 19:21:13626 // Wait for reply, or for any other incoming synchronous messages.
rockot9abe09b2016-08-02 20:57:34627 // |this| might get deleted, so only call static functions at this point.
rockot3c236292016-07-07 20:26:02628 scoped_refptr<mojo::SyncHandleRegistry> registry = sync_handle_registry_;
629 WaitForReply(registry.get(), context.get(), pump_messages);
initial.commit09911bf2008-07-26 23:55:29630
tzika08b2fd2016-03-30 02:32:59631 TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
632 "SyncChannel::Send", context->GetSendDoneEvent());
633
[email protected]3cdb7af812008-10-24 19:21:13634 return context->Pop();
initial.commit09911bf2008-07-26 23:55:29635}
636
rockot3c236292016-07-07 20:26:02637void SyncChannel::WaitForReply(mojo::SyncHandleRegistry* registry,
638 SyncContext* context,
639 bool pump_messages) {
[email protected]54af05f2011-04-08 03:38:21640 context->DispatchMessages();
rockot64e65de2016-06-21 20:17:49641
rockotb62e2e32017-03-24 18:36:44642 base::WaitableEvent* pump_messages_event = nullptr;
643 if (pump_messages) {
644 if (!g_pump_messages_event.Get()) {
Jeremy Roman160eb922017-08-29 17:43:43645 g_pump_messages_event.Get() = std::make_unique<base::WaitableEvent>(
rockotb62e2e32017-03-24 18:36:44646 base::WaitableEvent::ResetPolicy::MANUAL,
647 base::WaitableEvent::InitialState::SIGNALED);
648 }
649 pump_messages_event = g_pump_messages_event.Get().get();
650 }
rockot3c236292016-07-07 20:26:02651
652 while (true) {
653 bool dispatch = false;
654 bool send_done = false;
655 bool should_pump_messages = false;
Ken Rockot267df5a2017-08-30 23:31:45656 base::Closure on_send_done_callback = base::Bind(&OnEventReady, &send_done);
657 registry->RegisterEvent(context->GetSendDoneEvent(), on_send_done_callback);
rockotb62e2e32017-03-24 18:36:44658
Ken Rockot267df5a2017-08-30 23:31:45659 base::Closure on_pump_messages_callback;
rockot3c236292016-07-07 20:26:02660 if (pump_messages_event) {
Ken Rockot267df5a2017-08-30 23:31:45661 on_pump_messages_callback =
662 base::Bind(&OnEventReady, &should_pump_messages);
663 registry->RegisterEvent(pump_messages_event, on_pump_messages_callback);
rockot3c236292016-07-07 20:26:02664 }
665
666 const bool* stop_flags[] = { &dispatch, &send_done, &should_pump_messages };
rockot9abe09b2016-08-02 20:57:34667 context->received_sync_msgs()->BlockDispatch(&dispatch);
rockotb62e2e32017-03-24 18:36:44668 registry->Wait(stop_flags, 3);
rockot9abe09b2016-08-02 20:57:34669 context->received_sync_msgs()->UnblockDispatch();
rockot3c236292016-07-07 20:26:02670
Ken Rockot267df5a2017-08-30 23:31:45671 registry->UnregisterEvent(context->GetSendDoneEvent(),
672 on_send_done_callback);
rockot3c236292016-07-07 20:26:02673 if (pump_messages_event)
Ken Rockot267df5a2017-08-30 23:31:45674 registry->UnregisterEvent(pump_messages_event, on_pump_messages_callback);
rockot3c236292016-07-07 20:26:02675
676 if (dispatch) {
rockot9abe09b2016-08-02 20:57:34677 // We're waiting for a reply, but we received a blocking synchronous call.
678 // We must process it to avoid potential deadlocks.
[email protected]9eec2252009-12-01 02:34:18679 context->GetDispatchEvent()->Reset();
680 context->DispatchMessages();
[email protected]3cdb7af812008-10-24 19:21:13681 continue;
682 }
683
rockot3c236292016-07-07 20:26:02684 if (should_pump_messages)
gab2998ee72017-05-05 16:23:50685 WaitForReplyWithNestedMessageLoop(context); // Run a nested run loop.
[email protected]3cdb7af812008-10-24 19:21:13686
687 break;
688 }
689}
690
[email protected]9eec2252009-12-01 02:34:18691void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) {
Gabriel Charette43b8bf32017-11-08 20:24:43692 base::RunLoop nested_loop(base::RunLoop::Type::kNestableTasksAllowed);
rockotb62e2e32017-03-24 18:36:44693 ReceivedSyncMsgQueue::NestedSendDoneWatcher watcher(context, &nested_loop);
694 nested_loop.Run();
[email protected]3cdb7af812008-10-24 19:21:13695}
696
rockotb62e2e32017-03-24 18:36:44697void SyncChannel::OnDispatchEventSignaled(base::WaitableEvent* event) {
698 DCHECK_EQ(sync_context()->GetDispatchEvent(), event);
yzshen1bd23702016-11-30 21:54:51699 sync_context()->GetDispatchEvent()->Reset();
rockotb62e2e32017-03-24 18:36:44700
701 StartWatching();
702
703 // NOTE: May delete |this|.
yzshen1bd23702016-11-30 21:54:51704 sync_context()->DispatchMessages();
initial.commit09911bf2008-07-26 23:55:29705}
706
[email protected]952394af2011-11-16 01:06:46707void SyncChannel::StartWatching() {
rockot9abe09b2016-08-02 20:57:34708 // |dispatch_watcher_| watches the event asynchronously, only dispatching
709 // messages once the listener thread is unblocked and pumping its task queue.
710 // The ReceivedSyncMsgQueue also watches this event and may dispatch
711 // immediately if woken up by a message which it's allowed to dispatch.
rockotb62e2e32017-03-24 18:36:44712 dispatch_watcher_.StartWatching(
713 sync_context()->GetDispatchEvent(),
714 base::Bind(&SyncChannel::OnDispatchEventSignaled,
715 base::Unretained(this)));
[email protected]952394af2011-11-16 01:06:46716}
717
rockot29ade1b2015-08-07 06:23:59718void SyncChannel::OnChannelInit() {
rockot29ade1b2015-08-07 06:23:59719 pre_init_sync_message_filters_.clear();
720}
721
initial.commit09911bf2008-07-26 23:55:29722} // namespace IPC