blob: 570647bd5f58622e6555c51fb531b131bd4846dd [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"
rockot6d7be622016-06-15 18:25:1916#include "base/macros.h"
danakj03de39b22016-04-23 04:21:0917#include "base/memory/ptr_util.h"
rockot6d7be622016-06-15 18:25:1918#include "base/run_loop.h"
[email protected]44f9c952011-01-02 06:05:3919#include "base/synchronization/waitable_event.h"
[email protected]b2432302012-07-02 21:15:5220#include "base/threading/thread_local.h"
gabf08ccc02016-05-11 18:51:1121#include "base/threading/thread_task_runner_handle.h"
primiano7182d7b2015-01-30 18:02:0322#include "base/trace_event/trace_event.h"
[email protected]64860882014-08-04 23:44:1723#include "ipc/ipc_channel_factory.h"
[email protected]60b2c61f2012-08-22 22:39:5724#include "ipc/ipc_logging.h"
25#include "ipc/ipc_message_macros.h"
[email protected]946d1b22009-07-22 23:57:2126#include "ipc/ipc_sync_message.h"
rockot6d7be622016-06-15 18:25:1927#include "ipc/mojo_event.h"
28#include "mojo/public/cpp/bindings/sync_handle_registry.h"
initial.commit09911bf2008-07-26 23:55:2929
[email protected]e1acf6f2008-10-27 20:43:3330using base::TimeDelta;
31using base::TimeTicks;
[email protected]1c4947f2009-01-15 22:25:1132using base::WaitableEvent;
initial.commit09911bf2008-07-26 23:55:2933
34namespace IPC {
rockot6d7be622016-06-15 18:25:1935
36namespace {
37
38// A lazy thread-local Mojo Event which is always signaled. Used to wake up the
39// sync waiter when a SyncMessage requires the MessageLoop to be pumped while
40// waiting for a reply. This object is created lazily and ref-counted so it can
41// be cleaned up when no longer in use.
42class PumpMessagesEvent {
43 public:
44 // Acquires the event for this thread. Creates a new instance if necessary.
45 static PumpMessagesEvent* Acquire() {
46 PumpMessagesEvent* pump_messages_event = g_event_.Pointer()->Get();
47 if (!pump_messages_event) {
48 pump_messages_event = new PumpMessagesEvent;
49 pump_messages_event->event_.Signal();
50 g_event_.Pointer()->Set(pump_messages_event);
51 }
52 pump_messages_event->ref_count_++;
53 return pump_messages_event;
54 }
55
56 // Releases a handle to this event. There must be a 1:1 correspondence between
57 // calls to Acquire() and calls to Release().
58 static void Release() {
59 PumpMessagesEvent* pump_messages_event = g_event_.Pointer()->Get();
60 DCHECK(pump_messages_event);
61 DCHECK_GT(pump_messages_event->ref_count_, 0);
62 pump_messages_event->ref_count_--;
63 if (!pump_messages_event->ref_count_) {
64 g_event_.Pointer()->Set(nullptr);
65 delete pump_messages_event;
66 }
67 }
68
69 const mojo::Handle& GetHandle() const { return event_.GetHandle(); }
70
71 private:
72 PumpMessagesEvent() {}
73 ~PumpMessagesEvent() {}
74
75 int ref_count_ = 0;
76 MojoEvent event_;
77
78 static base::LazyInstance<base::ThreadLocalPointer<PumpMessagesEvent>>
79 g_event_;
80
81 DISALLOW_COPY_AND_ASSIGN(PumpMessagesEvent);
82};
83
84// A generic callback used when watching handles synchronously. Sets |*signal|
85// to true. Also sets |*error| to true in case of an error.
86void OnSyncHandleReady(bool* signal, bool* error, MojoResult result) {
87 *signal = true;
88 *error = result != MOJO_RESULT_OK;
89}
90
91// A ReadyCallback for use with mojo::Watcher. Ignores the result (DCHECKs, but
92// is only used in cases where failure should be impossible) and runs
93// |callback|.
94void RunOnHandleReady(const base::Closure& callback, MojoResult result) {
95 DCHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_ABORTED);
96 if (result == MOJO_RESULT_OK)
97 callback.Run();
98}
99
100} // namespace
101
102base::LazyInstance<base::ThreadLocalPointer<PumpMessagesEvent>>
103PumpMessagesEvent::g_event_ = LAZY_INSTANCE_INITIALIZER;
104
initial.commit09911bf2008-07-26 23:55:29105// When we're blocked in a Send(), we need to process incoming synchronous
106// messages right away because it could be blocking our reply (either
107// directly from the same object we're calling, or indirectly through one or
108// more other channels). That means that in SyncContext's OnMessageReceived,
109// we need to process sync message right away if we're blocked. However a
110// simple check isn't sufficient, because the listener thread can be in the
111// process of calling Send.
112// To work around this, when SyncChannel filters a sync message, it sets
113// an event that the listener thread waits on during its Send() call. This
114// allows us to dispatch incoming sync messages when blocked. The race
115// condition is handled because if Send is in the process of being called, it
116// will check the event. In case the listener thread isn't sending a message,
117// we queue a task on the listener thread to dispatch the received messages.
118// The messages are stored in this queue object that's shared among all
119// SyncChannel objects on the same thread (since one object can receive a
120// sync message while another one is blocked).
121
initial.commit09911bf2008-07-26 23:55:29122class SyncChannel::ReceivedSyncMsgQueue :
123 public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> {
124 public:
[email protected]3cdb7af812008-10-24 19:21:13125 // Returns the ReceivedSyncMsgQueue instance for this thread, creating one
[email protected]d3ae7a072008-12-05 20:27:20126 // if necessary. Call RemoveContext on the same thread when done.
127 static ReceivedSyncMsgQueue* AddContext() {
[email protected]3cdb7af812008-10-24 19:21:13128 // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple
129 // SyncChannel objects can block the same thread).
130 ReceivedSyncMsgQueue* rv = lazy_tls_ptr_.Pointer()->Get();
131 if (!rv) {
132 rv = new ReceivedSyncMsgQueue();
133 ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Set(rv);
134 }
135 rv->listener_count_++;
136 return rv;
initial.commit09911bf2008-07-26 23:55:29137 }
138
initial.commit09911bf2008-07-26 23:55:29139 // Called on IPC thread when a synchronous message or reply arrives.
[email protected]d3ae7a072008-12-05 20:27:20140 void QueueMessage(const Message& msg, SyncChannel::SyncContext* context) {
initial.commit09911bf2008-07-26 23:55:29141 bool was_task_pending;
142 {
[email protected]20305ec2011-01-21 04:55:52143 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29144
145 was_task_pending = task_pending_;
146 task_pending_ = true;
147
148 // We set the event in case the listener thread is blocked (or is about
149 // to). In case it's not, the PostTask dispatches the messages.
[email protected]d3ae7a072008-12-05 20:27:20150 message_queue_.push_back(QueuedMessage(new Message(msg), context));
[email protected]522cc10d2012-01-11 22:39:54151 message_queue_version_++;
initial.commit09911bf2008-07-26 23:55:29152 }
153
[email protected]1c4947f2009-01-15 22:25:11154 dispatch_event_.Signal();
initial.commit09911bf2008-07-26 23:55:29155 if (!was_task_pending) {
[email protected]b2432302012-07-02 21:15:52156 listener_task_runner_->PostTask(
[email protected]72b6f8e22011-11-12 21:16:41157 FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchMessagesTask,
vmpstra34d11322016-03-21 20:28:47158 this, base::RetainedRef(context)));
initial.commit09911bf2008-07-26 23:55:29159 }
160 }
161
162 void QueueReply(const Message &msg, SyncChannel::SyncContext* context) {
[email protected]d3ae7a072008-12-05 20:27:20163 received_replies_.push_back(QueuedMessage(new Message(msg), context));
initial.commit09911bf2008-07-26 23:55:29164 }
165
[email protected]d3ae7a072008-12-05 20:27:20166 // Called on the listener's thread to process any queues synchronous
initial.commit09911bf2008-07-26 23:55:29167 // messages.
[email protected]54af05f2011-04-08 03:38:21168 void DispatchMessagesTask(SyncContext* context) {
initial.commit09911bf2008-07-26 23:55:29169 {
[email protected]20305ec2011-01-21 04:55:52170 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29171 task_pending_ = false;
172 }
[email protected]54af05f2011-04-08 03:38:21173 context->DispatchMessages();
initial.commit09911bf2008-07-26 23:55:29174 }
175
[email protected]54af05f2011-04-08 03:38:21176 void DispatchMessages(SyncContext* dispatching_context) {
[email protected]522cc10d2012-01-11 22:39:54177 bool first_time = true;
tfarina10a5c062015-09-04 18:47:57178 uint32_t expected_version = 0;
[email protected]522cc10d2012-01-11 22:39:54179 SyncMessageQueue::iterator it;
initial.commit09911bf2008-07-26 23:55:29180 while (true) {
[email protected]522cc10d2012-01-11 22:39:54181 Message* message = NULL;
[email protected]d3ae7a072008-12-05 20:27:20182 scoped_refptr<SyncChannel::SyncContext> context;
initial.commit09911bf2008-07-26 23:55:29183 {
[email protected]20305ec2011-01-21 04:55:52184 base::AutoLock auto_lock(message_lock_);
[email protected]522cc10d2012-01-11 22:39:54185 if (first_time || message_queue_version_ != expected_version) {
186 it = message_queue_.begin();
187 first_time = false;
[email protected]54af05f2011-04-08 03:38:21188 }
[email protected]522cc10d2012-01-11 22:39:54189 for (; it != message_queue_.end(); it++) {
[email protected]298ee7d2012-03-30 21:29:30190 int message_group = it->context->restrict_dispatch_group();
191 if (message_group == kRestrictDispatchGroup_None ||
192 message_group == dispatching_context->restrict_dispatch_group()) {
[email protected]522cc10d2012-01-11 22:39:54193 message = it->message;
194 context = it->context;
195 it = message_queue_.erase(it);
196 message_queue_version_++;
197 expected_version = message_queue_version_;
198 break;
199 }
200 }
201 }
initial.commit09911bf2008-07-26 23:55:29202
[email protected]522cc10d2012-01-11 22:39:54203 if (message == NULL)
204 break;
205 context->OnDispatchMessage(*message);
206 delete message;
initial.commit09911bf2008-07-26 23:55:29207 }
208 }
209
initial.commit09911bf2008-07-26 23:55:29210 // SyncChannel calls this in its destructor.
[email protected]d3ae7a072008-12-05 20:27:20211 void RemoveContext(SyncContext* context) {
[email protected]20305ec2011-01-21 04:55:52212 base::AutoLock auto_lock(message_lock_);
initial.commit09911bf2008-07-26 23:55:29213
[email protected]d3ae7a072008-12-05 20:27:20214 SyncMessageQueue::iterator iter = message_queue_.begin();
215 while (iter != message_queue_.end()) {
[email protected]17571642013-06-01 04:11:27216 if (iter->context.get() == context) {
[email protected]d3ae7a072008-12-05 20:27:20217 delete iter->message;
218 iter = message_queue_.erase(iter);
[email protected]522cc10d2012-01-11 22:39:54219 message_queue_version_++;
initial.commit09911bf2008-07-26 23:55:29220 } else {
[email protected]d3ae7a072008-12-05 20:27:20221 iter++;
initial.commit09911bf2008-07-26 23:55:29222 }
initial.commit09911bf2008-07-26 23:55:29223 }
[email protected]3cdb7af812008-10-24 19:21:13224
225 if (--listener_count_ == 0) {
226 DCHECK(lazy_tls_ptr_.Pointer()->Get());
227 lazy_tls_ptr_.Pointer()->Set(NULL);
228 }
initial.commit09911bf2008-07-26 23:55:29229 }
230
rockot6d7be622016-06-15 18:25:19231 MojoEvent* dispatch_event() { return &dispatch_event_; }
[email protected]b2432302012-07-02 21:15:52232 base::SingleThreadTaskRunner* listener_task_runner() {
[email protected]17571642013-06-01 04:11:27233 return listener_task_runner_.get();
[email protected]92bf9062011-05-02 18:00:49234 }
initial.commit09911bf2008-07-26 23:55:29235
[email protected]f886b7bf2008-09-10 10:54:06236 // Holds a pointer to the per-thread ReceivedSyncMsgQueue object.
237 static base::LazyInstance<base::ThreadLocalPointer<ReceivedSyncMsgQueue> >
238 lazy_tls_ptr_;
239
initial.commit09911bf2008-07-26 23:55:29240 // Called on the ipc thread to check if we can unblock any current Send()
241 // calls based on a queued reply.
242 void DispatchReplies() {
initial.commit09911bf2008-07-26 23:55:29243 for (size_t i = 0; i < received_replies_.size(); ++i) {
244 Message* message = received_replies_[i].message;
[email protected]3cdb7af812008-10-24 19:21:13245 if (received_replies_[i].context->TryToUnblockListener(message)) {
initial.commit09911bf2008-07-26 23:55:29246 delete message;
247 received_replies_.erase(received_replies_.begin() + i);
248 return;
249 }
250 }
251 }
252
rockot6d7be622016-06-15 18:25:19253 mojo::Watcher* top_send_done_watcher() {
[email protected]ac0efda2009-10-14 16:22:02254 return top_send_done_watcher_;
255 }
256
rockot6d7be622016-06-15 18:25:19257 void set_top_send_done_watcher(mojo::Watcher* watcher) {
[email protected]ac0efda2009-10-14 16:22:02258 top_send_done_watcher_ = watcher;
259 }
260
[email protected]63a7bb82008-10-25 00:46:00261 private:
[email protected]877d55d2009-11-05 21:53:08262 friend class base::RefCountedThreadSafe<ReceivedSyncMsgQueue>;
263
[email protected]4df10d612008-11-12 00:38:26264 // See the comment in SyncChannel::SyncChannel for why this event is created
265 // as manual reset.
gab90c2c5c2016-06-01 20:34:06266 ReceivedSyncMsgQueue()
267 : message_queue_version_(0),
gab90c2c5c2016-06-01 20:34:06268 listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
269 task_pending_(false),
270 listener_count_(0),
271 top_send_done_watcher_(NULL) {}
[email protected]63a7bb82008-10-25 00:46:00272
[email protected]877d55d2009-11-05 21:53:08273 ~ReceivedSyncMsgQueue() {}
274
[email protected]d3ae7a072008-12-05 20:27:20275 // Holds information about a queued synchronous message or reply.
276 struct QueuedMessage {
277 QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { }
initial.commit09911bf2008-07-26 23:55:29278 Message* message;
279 scoped_refptr<SyncChannel::SyncContext> context;
280 };
281
[email protected]522cc10d2012-01-11 22:39:54282 typedef std::list<QueuedMessage> SyncMessageQueue;
[email protected]1c4947f2009-01-15 22:25:11283 SyncMessageQueue message_queue_;
tfarina10a5c062015-09-04 18:47:57284 uint32_t message_queue_version_; // Used to signal DispatchMessages to rescan
[email protected]d3ae7a072008-12-05 20:27:20285
286 std::vector<QueuedMessage> received_replies_;
[email protected]3cdb7af812008-10-24 19:21:13287
rockot6d7be622016-06-15 18:25:19288 // Signaled when we get a synchronous message that we must respond to, as the
[email protected]3cdb7af812008-10-24 19:21:13289 // sender needs its reply before it can reply to our original synchronous
290 // message.
rockot6d7be622016-06-15 18:25:19291 MojoEvent dispatch_event_;
[email protected]b2432302012-07-02 21:15:52292 scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
[email protected]20305ec2011-01-21 04:55:52293 base::Lock message_lock_;
[email protected]3cdb7af812008-10-24 19:21:13294 bool task_pending_;
295 int listener_count_;
[email protected]ac0efda2009-10-14 16:22:02296
rockot6d7be622016-06-15 18:25:19297 // The current send done handle watcher for this thread. Used to maintain
298 // a thread-local stack of send done watchers to ensure that nested sync
[email protected]ac0efda2009-10-14 16:22:02299 // message loops complete correctly.
rockot6d7be622016-06-15 18:25:19300 mojo::Watcher* top_send_done_watcher_;
initial.commit09911bf2008-07-26 23:55:29301};
302
[email protected]f886b7bf2008-09-10 10:54:06303base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> >
[email protected]6de0fd1d2011-11-15 13:31:49304 SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_ =
305 LAZY_INSTANCE_INITIALIZER;
initial.commit09911bf2008-07-26 23:55:29306
307SyncChannel::SyncContext::SyncContext(
[email protected]b7f59e822012-06-29 22:05:26308 Listener* listener,
dchengfd033702014-08-28 16:59:29309 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
[email protected]1c4947f2009-01-15 22:25:11310 WaitableEvent* shutdown_event)
[email protected]b2432302012-07-02 21:15:52311 : ChannelProxy::Context(listener, ipc_task_runner),
[email protected]1c4947f2009-01-15 22:25:11312 received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()),
[email protected]54af05f2011-04-08 03:38:21313 shutdown_event_(shutdown_event),
[email protected]298ee7d2012-03-30 21:29:30314 restrict_dispatch_group_(kRestrictDispatchGroup_None) {
initial.commit09911bf2008-07-26 23:55:29315}
316
317SyncChannel::SyncContext::~SyncContext() {
318 while (!deserializers_.empty())
[email protected]3cdb7af812008-10-24 19:21:13319 Pop();
initial.commit09911bf2008-07-26 23:55:29320}
321
322// Adds information about an outgoing sync message to the context so that
323// we know how to deserialize the reply. Returns a handle that's set when
324// the reply has arrived.
[email protected]3cdb7af812008-10-24 19:21:13325void SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
[email protected]4a180a52011-04-15 19:07:43326 // Create the tracking information for this message. This object is stored
327 // by value since all members are pointers that are cheap to copy. These
328 // pointers are cleaned up in the Pop() function.
329 //
[email protected]1c4947f2009-01-15 22:25:11330 // The event is created as manual reset because in between Signal and
[email protected]4df10d612008-11-12 00:38:26331 // OnObjectSignalled, another Send can happen which would stop the watcher
332 // from being called. The event would get watched later, when the nested
333 // Send completes, so the event will need to remain set.
gab90c2c5c2016-06-01 20:34:06334 PendingSyncMsg pending(
335 SyncMessage::GetMessageId(*sync_msg), sync_msg->GetReplyDeserializer(),
rockot6d7be622016-06-15 18:25:19336 new MojoEvent);
[email protected]20305ec2011-01-21 04:55:52337 base::AutoLock auto_lock(deserializers_lock_);
[email protected]3cdb7af812008-10-24 19:21:13338 deserializers_.push_back(pending);
initial.commit09911bf2008-07-26 23:55:29339}
340
[email protected]3cdb7af812008-10-24 19:21:13341bool SyncChannel::SyncContext::Pop() {
[email protected]63a7bb82008-10-25 00:46:00342 bool result;
343 {
[email protected]20305ec2011-01-21 04:55:52344 base::AutoLock auto_lock(deserializers_lock_);
[email protected]63a7bb82008-10-25 00:46:00345 PendingSyncMsg msg = deserializers_.back();
346 delete msg.deserializer;
[email protected]1c4947f2009-01-15 22:25:11347 delete msg.done_event;
rockot6d7be622016-06-15 18:25:19348 msg.done_event = nullptr;
[email protected]63a7bb82008-10-25 00:46:00349 deserializers_.pop_back();
350 result = msg.send_result;
351 }
352
353 // We got a reply to a synchronous Send() call that's blocking the listener
354 // thread. However, further down the call stack there could be another
355 // blocking Send() call, whose reply we received after we made this last
356 // Send() call. So check if we have any queued replies available that
357 // can now unblock the listener thread.
[email protected]b2432302012-07-02 21:15:52358 ipc_task_runner()->PostTask(
[email protected]72b6f8e22011-11-12 21:16:41359 FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchReplies,
360 received_sync_msgs_.get()));
[email protected]63a7bb82008-10-25 00:46:00361
362 return result;
[email protected]3cdb7af812008-10-24 19:21:13363}
364
rockot6d7be622016-06-15 18:25:19365MojoEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
[email protected]20305ec2011-01-21 04:55:52366 base::AutoLock auto_lock(deserializers_lock_);
[email protected]3cdb7af812008-10-24 19:21:13367 return deserializers_.back().done_event;
368}
369
rockot6d7be622016-06-15 18:25:19370MojoEvent* SyncChannel::SyncContext::GetDispatchEvent() {
[email protected]3cdb7af812008-10-24 19:21:13371 return received_sync_msgs_->dispatch_event();
initial.commit09911bf2008-07-26 23:55:29372}
373
374void SyncChannel::SyncContext::DispatchMessages() {
[email protected]54af05f2011-04-08 03:38:21375 received_sync_msgs_->DispatchMessages(this);
initial.commit09911bf2008-07-26 23:55:29376}
377
[email protected]3cdb7af812008-10-24 19:21:13378bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) {
[email protected]20305ec2011-01-21 04:55:52379 base::AutoLock auto_lock(deserializers_lock_);
[email protected]63a7bb82008-10-25 00:46:00380 if (deserializers_.empty() ||
381 !SyncMessage::IsMessageReplyTo(*msg, deserializers_.back().id)) {
382 return false;
[email protected]3cdb7af812008-10-24 19:21:13383 }
initial.commit09911bf2008-07-26 23:55:29384
[email protected]63a7bb82008-10-25 00:46:00385 if (!msg->is_reply_error()) {
[email protected]211142cd2012-08-13 09:41:19386 bool send_result = deserializers_.back().deserializer->
[email protected]63a7bb82008-10-25 00:46:00387 SerializeOutputParameters(*msg);
[email protected]211142cd2012-08-13 09:41:19388 deserializers_.back().send_result = send_result;
bauerb3e9be732015-11-03 18:17:47389 DVLOG_IF(1, !send_result) << "Couldn't deserialize reply message";
[email protected]211142cd2012-08-13 09:41:19390 } else {
bauerb3e9be732015-11-03 18:17:47391 DVLOG(1) << "Received error reply";
[email protected]63a7bb82008-10-25 00:46:00392 }
tzika08b2fd2016-03-30 02:32:59393
rockot6d7be622016-06-15 18:25:19394 MojoEvent* done_event = deserializers_.back().done_event;
tzika08b2fd2016-03-30 02:32:59395 TRACE_EVENT_FLOW_BEGIN0(
396 TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
397 "SyncChannel::SyncContext::TryToUnblockListener", done_event);
398
399 done_event->Signal();
initial.commit09911bf2008-07-26 23:55:29400
[email protected]3cdb7af812008-10-24 19:21:13401 return true;
initial.commit09911bf2008-07-26 23:55:29402}
403
[email protected]3cdb7af812008-10-24 19:21:13404void SyncChannel::SyncContext::Clear() {
405 CancelPendingSends();
[email protected]d3ae7a072008-12-05 20:27:20406 received_sync_msgs_->RemoveContext(this);
[email protected]3cdb7af812008-10-24 19:21:13407 Context::Clear();
408}
409
[email protected]a95986a82010-12-24 06:19:28410bool SyncChannel::SyncContext::OnMessageReceived(const Message& msg) {
[email protected]d65cab7a2008-08-12 01:25:41411 // Give the filters a chance at processing this message.
412 if (TryFilters(msg))
[email protected]a95986a82010-12-24 06:19:28413 return true;
[email protected]d65cab7a2008-08-12 01:25:41414
[email protected]3cdb7af812008-10-24 19:21:13415 if (TryToUnblockListener(&msg))
[email protected]a95986a82010-12-24 06:19:28416 return true;
initial.commit09911bf2008-07-26 23:55:29417
[email protected]9134cce6d2012-04-10 20:07:53418 if (msg.is_reply()) {
419 received_sync_msgs_->QueueReply(msg, this);
[email protected]a95986a82010-12-24 06:19:28420 return true;
initial.commit09911bf2008-07-26 23:55:29421 }
422
[email protected]9134cce6d2012-04-10 20:07:53423 if (msg.should_unblock()) {
424 received_sync_msgs_->QueueMessage(msg, this);
[email protected]a95986a82010-12-24 06:19:28425 return true;
initial.commit09911bf2008-07-26 23:55:29426 }
427
[email protected]3cdb7af812008-10-24 19:21:13428 return Context::OnMessageReceivedNoFilter(msg);
initial.commit09911bf2008-07-26 23:55:29429}
430
initial.commit09911bf2008-07-26 23:55:29431void SyncChannel::SyncContext::OnChannelError() {
[email protected]3cdb7af812008-10-24 19:21:13432 CancelPendingSends();
[email protected]a4f822702009-02-06 00:44:53433 shutdown_watcher_.StopWatching();
initial.commit09911bf2008-07-26 23:55:29434 Context::OnChannelError();
435}
436
[email protected]3cdb7af812008-10-24 19:21:13437void SyncChannel::SyncContext::OnChannelOpened() {
[email protected]329be052013-02-04 18:14:28438 shutdown_watcher_.StartWatching(
439 shutdown_event_,
rockot6d7be622016-06-15 18:25:19440 base::Bind(&SyncChannel::SyncContext::OnShutdownEventSignaled,
[email protected]329be052013-02-04 18:14:28441 base::Unretained(this)));
[email protected]3cdb7af812008-10-24 19:21:13442 Context::OnChannelOpened();
initial.commit09911bf2008-07-26 23:55:29443}
444
[email protected]3cdb7af812008-10-24 19:21:13445void SyncChannel::SyncContext::OnChannelClosed() {
[email protected]87339f02010-09-02 21:45:50446 CancelPendingSends();
[email protected]3cdb7af812008-10-24 19:21:13447 shutdown_watcher_.StopWatching();
448 Context::OnChannelClosed();
449}
450
[email protected]3cdb7af812008-10-24 19:21:13451void SyncChannel::SyncContext::CancelPendingSends() {
[email protected]20305ec2011-01-21 04:55:52452 base::AutoLock auto_lock(deserializers_lock_);
[email protected]3cdb7af812008-10-24 19:21:13453 PendingSyncMessageQueue::iterator iter;
bauerb3e9be732015-11-03 18:17:47454 DVLOG(1) << "Canceling pending sends";
tzika08b2fd2016-03-30 02:32:59455 for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
456 TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
457 "SyncChannel::SyncContext::CancelPendingSends",
458 iter->done_event);
[email protected]1c4947f2009-01-15 22:25:11459 iter->done_event->Signal();
tzika08b2fd2016-03-30 02:32:59460 }
[email protected]3cdb7af812008-10-24 19:21:13461}
462
rockot6d7be622016-06-15 18:25:19463void SyncChannel::SyncContext::OnShutdownEventSignaled(WaitableEvent* event) {
464 DCHECK_EQ(event, shutdown_event_);
[email protected]3cdb7af812008-10-24 19:21:13465
rockot6d7be622016-06-15 18:25:19466 // Process shut down before we can get a reply to a synchronous message.
467 // Cancel pending Send calls, which will end up setting the send done event.
468 CancelPendingSends();
[email protected]329be052013-02-04 18:14:28469}
[email protected]3cdb7af812008-10-24 19:21:13470
[email protected]fca876a12014-06-05 16:15:38471// static
danakj03de39b22016-04-23 04:21:09472std::unique_ptr<SyncChannel> SyncChannel::Create(
[email protected]42ce94e2010-12-08 19:28:09473 const IPC::ChannelHandle& channel_handle,
[email protected]3b0e4662014-06-02 20:29:30474 Channel::Mode mode,
[email protected]b7f59e822012-06-29 22:05:26475 Listener* listener,
dchengfd033702014-08-28 16:59:29476 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
[email protected]4b580bf2010-12-02 19:16:07477 bool create_pipe_now,
erikchen30dc2812015-09-24 03:26:38478 base::WaitableEvent* shutdown_event) {
danakj03de39b22016-04-23 04:21:09479 std::unique_ptr<SyncChannel> channel =
[email protected]fca876a12014-06-05 16:15:38480 Create(listener, ipc_task_runner, shutdown_event);
erikchen30dc2812015-09-24 03:26:38481 channel->Init(channel_handle, mode, create_pipe_now);
dchenge48600452015-12-28 02:24:50482 return channel;
[email protected]fca876a12014-06-05 16:15:38483}
484
485// static
danakj03de39b22016-04-23 04:21:09486std::unique_ptr<SyncChannel> SyncChannel::Create(
487 std::unique_ptr<ChannelFactory> factory,
[email protected]64860882014-08-04 23:44:17488 Listener* listener,
dchengfd033702014-08-28 16:59:29489 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
[email protected]64860882014-08-04 23:44:17490 bool create_pipe_now,
491 base::WaitableEvent* shutdown_event) {
danakj03de39b22016-04-23 04:21:09492 std::unique_ptr<SyncChannel> channel =
[email protected]64860882014-08-04 23:44:17493 Create(listener, ipc_task_runner, shutdown_event);
dchenge48600452015-12-28 02:24:50494 channel->Init(std::move(factory), create_pipe_now);
495 return channel;
[email protected]64860882014-08-04 23:44:17496}
497
498// static
danakj03de39b22016-04-23 04:21:09499std::unique_ptr<SyncChannel> SyncChannel::Create(
[email protected]fca876a12014-06-05 16:15:38500 Listener* listener,
dchengfd033702014-08-28 16:59:29501 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
[email protected]fca876a12014-06-05 16:15:38502 WaitableEvent* shutdown_event) {
danakj03de39b22016-04-23 04:21:09503 return base::WrapUnique(
[email protected]fca876a12014-06-05 16:15:38504 new SyncChannel(listener, ipc_task_runner, shutdown_event));
[email protected]952394af2011-11-16 01:06:46505}
506
507SyncChannel::SyncChannel(
[email protected]b7f59e822012-06-29 22:05:26508 Listener* listener,
dchengfd033702014-08-28 16:59:29509 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
[email protected]952394af2011-11-16 01:06:46510 WaitableEvent* shutdown_event)
[email protected]5855f1d2014-04-16 16:50:43511 : ChannelProxy(new SyncContext(listener, ipc_task_runner, shutdown_event)) {
rockot6d7be622016-06-15 18:25:19512 // Keep a thread-local PumpMessagesEvent alive at least as long as any
513 // SyncChannel exists. This is balanced in the SyncChannel destructor below.
514 PumpMessagesEvent::Acquire();
515
[email protected]1f9cf472014-04-17 05:07:18516 // The current (listener) thread must be distinct from the IPC thread, or else
517 // sending synchronous messages will deadlock.
dchengff04843f2014-09-03 18:01:16518 DCHECK_NE(ipc_task_runner.get(), base::ThreadTaskRunnerHandle::Get().get());
[email protected]952394af2011-11-16 01:06:46519 StartWatching();
initial.commit09911bf2008-07-26 23:55:29520}
521
522SyncChannel::~SyncChannel() {
rockot6d7be622016-06-15 18:25:19523 PumpMessagesEvent::Release();
initial.commit09911bf2008-07-26 23:55:29524}
525
[email protected]298ee7d2012-03-30 21:29:30526void SyncChannel::SetRestrictDispatchChannelGroup(int group) {
527 sync_context()->set_restrict_dispatch_group(group);
[email protected]54af05f2011-04-08 03:38:21528}
529
rockotac64ae92f2015-08-06 00:32:29530scoped_refptr<SyncMessageFilter> SyncChannel::CreateSyncMessageFilter() {
531 scoped_refptr<SyncMessageFilter> filter = new SyncMessageFilter(
532 sync_context()->shutdown_event(),
533 sync_context()->IsChannelSendThreadSafe());
534 AddFilter(filter.get());
rockot29ade1b2015-08-07 06:23:59535 if (!did_init())
536 pre_init_sync_message_filters_.push_back(filter);
rockotac64ae92f2015-08-06 00:32:29537 return filter;
538}
539
[email protected]3cdb7af812008-10-24 19:21:13540bool SyncChannel::Send(Message* message) {
[email protected]60b2c61f2012-08-22 22:39:57541#ifdef IPC_MESSAGE_LOG_ENABLED
[email protected]60b2c61f2012-08-22 22:39:57542 std::string name;
pkasting7bc277b2014-10-13 20:58:39543 Logging::GetInstance()->GetMessageText(message->type(), &name, message, NULL);
[email protected]d6cbf052014-05-02 21:29:24544 TRACE_EVENT1("ipc", "SyncChannel::Send", "name", name);
[email protected]60b2c61f2012-08-22 22:39:57545#else
[email protected]d6cbf052014-05-02 21:29:24546 TRACE_EVENT2("ipc", "SyncChannel::Send",
[email protected]60b2c61f2012-08-22 22:39:57547 "class", IPC_MESSAGE_ID_CLASS(message->type()),
548 "line", IPC_MESSAGE_ID_LINE(message->type()));
549#endif
[email protected]3cdb7af812008-10-24 19:21:13550 if (!message->is_sync()) {
551 ChannelProxy::Send(message);
552 return true;
initial.commit09911bf2008-07-26 23:55:29553 }
554
[email protected]3cdb7af812008-10-24 19:21:13555 // *this* might get deleted in WaitForReply.
556 scoped_refptr<SyncContext> context(sync_context());
[email protected]1c4947f2009-01-15 22:25:11557 if (context->shutdown_event()->IsSignaled()) {
bauerb3e9be732015-11-03 18:17:47558 DVLOG(1) << "shutdown event is signaled";
[email protected]3cdb7af812008-10-24 19:21:13559 delete message;
560 return false;
561 }
562
[email protected]3cdb7af812008-10-24 19:21:13563 SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
rockot6d7be622016-06-15 18:25:19564 bool pump_messages = sync_msg->ShouldPumpMessages();
[email protected]3cdb7af812008-10-24 19:21:13565 context->Push(sync_msg);
[email protected]3cdb7af812008-10-24 19:21:13566
initial.commit09911bf2008-07-26 23:55:29567 ChannelProxy::Send(message);
initial.commit09911bf2008-07-26 23:55:29568
[email protected]3cdb7af812008-10-24 19:21:13569 // Wait for reply, or for any other incoming synchronous messages.
[email protected]9eec2252009-12-01 02:34:18570 // *this* might get deleted, so only call static functions at this point.
rockot6d7be622016-06-15 18:25:19571 WaitForReply(context.get(), pump_messages);
initial.commit09911bf2008-07-26 23:55:29572
tzika08b2fd2016-03-30 02:32:59573 TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
574 "SyncChannel::Send", context->GetSendDoneEvent());
575
[email protected]3cdb7af812008-10-24 19:21:13576 return context->Pop();
initial.commit09911bf2008-07-26 23:55:29577}
578
rockot6d7be622016-06-15 18:25:19579void SyncChannel::WaitForReply(SyncContext* context, bool pump_messages) {
[email protected]54af05f2011-04-08 03:38:21580 context->DispatchMessages();
rockot97912712016-06-15 05:28:42581
rockot6d7be622016-06-15 18:25:19582 PumpMessagesEvent* pump_messages_event = nullptr;
583 if (pump_messages)
584 pump_messages_event = PumpMessagesEvent::Acquire();
585
586 scoped_refptr<mojo::SyncHandleRegistry> registry =
587 mojo::SyncHandleRegistry::current();
588
589 while (true) {
590 bool dispatch = false;
591 bool send_done = false;
592 bool should_pump_messages = false;
593 bool error = false;
594 registry->RegisterHandle(context->GetDispatchEvent()->GetHandle(),
595 MOJO_HANDLE_SIGNAL_READABLE,
596 base::Bind(&OnSyncHandleReady, &dispatch, &error));
597 registry->RegisterHandle(
598 context->GetSendDoneEvent()->GetHandle(),
599 MOJO_HANDLE_SIGNAL_READABLE,
600 base::Bind(&OnSyncHandleReady, &send_done, &error));
601 if (pump_messages_event) {
602 registry->RegisterHandle(
603 pump_messages_event->GetHandle(), MOJO_HANDLE_SIGNAL_READABLE,
604 base::Bind(&OnSyncHandleReady, &should_pump_messages, &error));
605 }
606
607 const bool* stop_flags[] = { &dispatch, &send_done, &should_pump_messages };
608 bool result = registry->WatchAllHandles(stop_flags, 3);
609 DCHECK(result);
610 DCHECK(!error);
611
612 registry->UnregisterHandle(context->GetDispatchEvent()->GetHandle());
613 registry->UnregisterHandle(context->GetSendDoneEvent()->GetHandle());
614 if (pump_messages_event)
615 registry->UnregisterHandle(pump_messages_event->GetHandle());
616
617 if (dispatch) {
[email protected]3cdb7af812008-10-24 19:21:13618 // We're waiting for a reply, but we received a blocking synchronous
619 // call. We must process it or otherwise a deadlock might occur.
[email protected]9eec2252009-12-01 02:34:18620 context->GetDispatchEvent()->Reset();
621 context->DispatchMessages();
[email protected]3cdb7af812008-10-24 19:21:13622 continue;
623 }
624
rockot6d7be622016-06-15 18:25:19625 DCHECK(send_done || should_pump_messages);
626
627 if (should_pump_messages)
[email protected]9eec2252009-12-01 02:34:18628 WaitForReplyWithNestedMessageLoop(context); // Run a nested message loop.
[email protected]3cdb7af812008-10-24 19:21:13629
630 break;
631 }
rockot6d7be622016-06-15 18:25:19632
633 if (pump_messages_event)
634 PumpMessagesEvent::Release();
[email protected]3cdb7af812008-10-24 19:21:13635}
636
[email protected]9eec2252009-12-01 02:34:18637void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) {
rockot6d7be622016-06-15 18:25:19638 mojo::Watcher send_done_watcher;
[email protected]ac0efda2009-10-14 16:22:02639
[email protected]9eec2252009-12-01 02:34:18640 ReceivedSyncMsgQueue* sync_msg_queue = context->received_sync_msgs();
rockot6d7be622016-06-15 18:25:19641 DCHECK_NE(sync_msg_queue, nullptr);
[email protected]ac0efda2009-10-14 16:22:02642
rockot6d7be622016-06-15 18:25:19643 mojo::Watcher* old_watcher = sync_msg_queue->top_send_done_watcher();
644 mojo::Handle old_handle(mojo::kInvalidHandleValue);
645 mojo::Watcher::ReadyCallback old_callback;
[email protected]ac0efda2009-10-14 16:22:02646
rockot6d7be622016-06-15 18:25:19647 // Maintain a thread-local stack of watchers to ensure nested calls complete
648 // in the correct sequence, i.e. the outermost call completes first, etc.
649 if (old_watcher) {
650 old_callback = old_watcher->ready_callback();
651 old_handle = old_watcher->handle();
652 old_watcher->Cancel();
[email protected]ac0efda2009-10-14 16:22:02653 }
654
655 sync_msg_queue->set_top_send_done_watcher(&send_done_watcher);
656
tommycli5628ee32016-06-15 15:54:55657 {
rockot6d7be622016-06-15 18:25:19658 base::RunLoop nested_loop;
659 send_done_watcher.Start(
660 context->GetSendDoneEvent()->GetHandle(), MOJO_HANDLE_SIGNAL_READABLE,
661 base::Bind(&RunOnHandleReady, nested_loop.QuitClosure()));
662
[email protected]fd0a773a2013-04-30 20:55:03663 base::MessageLoop::ScopedNestableTaskAllower allow(
664 base::MessageLoop::current());
rockot6d7be622016-06-15 18:25:19665 nested_loop.Run();
666 send_done_watcher.Cancel();
[email protected]b5717a42012-02-14 19:33:52667 }
[email protected]ac0efda2009-10-14 16:22:02668
rockot6d7be622016-06-15 18:25:19669 sync_msg_queue->set_top_send_done_watcher(old_watcher);
670 if (old_watcher)
671 old_watcher->Start(old_handle, MOJO_HANDLE_SIGNAL_READABLE, old_callback);
[email protected]3cdb7af812008-10-24 19:21:13672}
673
rockot6d7be622016-06-15 18:25:19674void SyncChannel::OnDispatchHandleReady(MojoResult result) {
675 DCHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_ABORTED);
676 if (result == MOJO_RESULT_OK) {
677 sync_context()->GetDispatchEvent()->Reset();
678 sync_context()->DispatchMessages();
679 }
initial.commit09911bf2008-07-26 23:55:29680}
681
[email protected]952394af2011-11-16 01:06:46682void SyncChannel::StartWatching() {
683 // Ideally we only want to watch this object when running a nested message
684 // loop. However, we don't know when it exits if there's another nested
685 // message loop running under it or not, so we wouldn't know whether to
rockot6d7be622016-06-15 18:25:19686 // stop or keep watching. So we always watch it.
687 dispatch_watcher_.Start(sync_context()->GetDispatchEvent()->GetHandle(),
688 MOJO_HANDLE_SIGNAL_READABLE,
689 base::Bind(&SyncChannel::OnDispatchHandleReady,
690 base::Unretained(this)));
[email protected]952394af2011-11-16 01:06:46691}
692
rockot29ade1b2015-08-07 06:23:59693void SyncChannel::OnChannelInit() {
694 for (const auto& filter : pre_init_sync_message_filters_) {
695 filter->set_is_channel_send_thread_safe(
696 context()->IsChannelSendThreadSafe());
697 }
698 pre_init_sync_message_filters_.clear();
699}
700
rockot868f89e72016-05-25 16:25:45701bool SyncChannel::SendNow(std::unique_ptr<Message> message) {
702#ifdef IPC_MESSAGE_LOG_ENABLED
703 std::string name;
704 Logging::GetInstance()->GetMessageText(
705 message->type(), &name, message.get(), nullptr);
706 TRACE_EVENT1("ipc", "SyncChannel::SendNow", "name", name);
707#else
708 TRACE_EVENT2("ipc", "SyncChannel::SendNow",
709 "class", IPC_MESSAGE_ID_CLASS(message->type()),
710 "line", IPC_MESSAGE_ID_LINE(message->type()));
711#endif
712 if (!message->is_sync())
713 return ChannelProxy::SendNow(std::move(message));
714 return Send(message.release());
715}
716
717bool SyncChannel::SendOnIPCThread(std::unique_ptr<Message> message) {
718#ifdef IPC_MESSAGE_LOG_ENABLED
719 std::string name;
720 Logging::GetInstance()->GetMessageText(
721 message->type(), &name, message.get(), nullptr);
722 TRACE_EVENT1("ipc", "SyncChannel::SendOnIPCThread", "name", name);
723#else
724 TRACE_EVENT2("ipc", "SyncChannel::SendOnIPCThread",
725 "class", IPC_MESSAGE_ID_CLASS(message->type()),
726 "line", IPC_MESSAGE_ID_LINE(message->type()));
727#endif
728 if (!message->is_sync())
729 return ChannelProxy::SendOnIPCThread(std::move(message));
730 return Send(message.release());
731}
732
initial.commit09911bf2008-07-26 23:55:29733} // namespace IPC