blob: 3f65ef38be0c6d045d06cad41ffff6f85f89a53c [file] [log] [blame]
piman@chromium.org5a00b882012-03-31 06:29:30 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
thestig@chromium.org519c9ac2011-11-15 09:29:48 +09005#ifndef IPC_IPC_SYNC_CHANNEL_H_
6#define IPC_IPC_SYNC_CHANNEL_H_
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09007
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09008#include <deque>
danakjc3fb6c52016-04-23 13:21:09 +09009#include <memory>
rockot8115a592015-08-07 15:23:59 +090010#include <string>
11#include <vector>
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090012
tfarina2d565d32015-09-16 18:56:21 +090013#include "base/macros.h"
levin@chromium.org5c528682011-03-28 10:54:15 +090014#include "base/memory/ref_counted.h"
brettw@chromium.orgabe477a2011-01-21 13:55:52 +090015#include "base/synchronization/lock.h"
brettw@chromium.org5238c7d2011-01-02 15:05:39 +090016#include "base/synchronization/waitable_event_watcher.h"
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +090017#include "ipc/ipc_channel_handle.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090018#include "ipc/ipc_channel_proxy.h"
jabdelmalek@google.comeb921652010-04-07 05:33:36 +090019#include "ipc/ipc_sync_message.h"
rockotedb92032015-08-06 09:32:29 +090020#include "ipc/ipc_sync_message_filter.h"
rockot0a321712016-07-08 05:26:02 +090021#include "mojo/public/c/system/types.h"
rockota07beef2017-03-16 08:57:47 +090022#include "mojo/public/cpp/system/simple_watcher.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090023
24namespace base {
rockot39af2742017-03-25 03:36:44 +090025class RunLoop;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090026class WaitableEvent;
27};
28
rockot0a321712016-07-08 05:26:02 +090029namespace mojo {
30class SyncHandleRegistry;
rockot0a321712016-07-08 05:26:02 +090031}
32
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090033namespace IPC {
34
rockot71bef072016-06-25 02:27:33 +090035class ChannelFactory;
rockot0a321712016-07-08 05:26:02 +090036class SyncMessage;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090037
jabdelmalek@google.comeb921652010-04-07 05:33:36 +090038// This is similar to ChannelProxy, with the added feature of supporting sending
39// synchronous messages.
brettw@chromium.orgb57fa132011-04-16 04:07:43 +090040//
41// Overview of how the sync channel works
42// --------------------------------------
43// When the sending thread sends a synchronous message, we create a bunch
piman@chromium.org609a6892014-04-17 01:50:43 +090044// of tracking info (created in Send, stored in the PendingSyncMsg
brettw@chromium.orgb57fa132011-04-16 04:07:43 +090045// structure) associated with the message that we identify by the unique
46// "MessageId" on the SyncMessage. Among the things we save is the
47// "Deserializer" which is provided by the sync message. This object is in
48// charge of reading the parameters from the reply message and putting them in
49// the output variables provided by its caller.
50//
51// The info gets stashed in a queue since we could have a nested stack of sync
52// messages (each side could send sync messages in response to sync messages,
53// so it works like calling a function). The message is sent to the I/O thread
54// for dispatch and the original thread blocks waiting for the reply.
55//
56// SyncContext maintains the queue in a threadsafe way and listens for replies
57// on the I/O thread. When a reply comes in that matches one of the messages
58// it's looking for (using the unique message ID), it will execute the
59// deserializer stashed from before, and unblock the original thread.
60//
61//
62// Significant complexity results from the fact that messages are still coming
63// in while the original thread is blocked. Normal async messages are queued
64// and dispatched after the blocking call is complete. Sync messages must
65// be dispatched in a reentrant manner to avoid deadlock.
66//
67//
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090068// Note that care must be taken that the lifetime of the ipc_thread argument
69// is more than this object. If the message loop goes away while this object
70// is running and it's used to send a message, then it will use the invalid
71// message loop pointer to proxy it to the ipc thread.
teravest@chromium.orgcd16b3a2013-02-05 03:14:28 +090072class IPC_EXPORT SyncChannel : public ChannelProxy {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090073 public:
piman@chromium.org5a00b882012-03-31 06:29:30 +090074 enum RestrictDispatchGroup {
75 kRestrictDispatchGroup_None = 0,
76 };
77
kkania@chromium.org9ccb4692011-11-16 10:06:46 +090078 // Creates and initializes a sync channel. If create_pipe_now is specified,
79 // the channel will be initialized synchronously.
morrita@chromium.org15b48602014-06-06 01:15:38 +090080 // The naming pattern follows IPC::Channel.
danakjc3fb6c52016-04-23 13:21:09 +090081 static std::unique_ptr<SyncChannel> Create(
morrita@chromium.org15b48602014-06-06 01:15:38 +090082 const IPC::ChannelHandle& channel_handle,
83 IPC::Channel::Mode mode,
84 Listener* listener,
dchengea780ac2014-08-29 01:59:29 +090085 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
morrita@chromium.org15b48602014-06-06 01:15:38 +090086 bool create_pipe_now,
erikchenc596f542015-09-24 12:26:38 +090087 base::WaitableEvent* shutdown_event);
kkania@chromium.org9ccb4692011-11-16 10:06:46 +090088
danakjc3fb6c52016-04-23 13:21:09 +090089 static std::unique_ptr<SyncChannel> Create(
90 std::unique_ptr<ChannelFactory> factory,
morrita@chromium.org15996aa2014-08-05 08:44:17 +090091 Listener* listener,
dchengea780ac2014-08-29 01:59:29 +090092 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
morrita@chromium.org15996aa2014-08-05 08:44:17 +090093 bool create_pipe_now,
94 base::WaitableEvent* shutdown_event);
95
kkania@chromium.org9ccb4692011-11-16 10:06:46 +090096 // Creates an uninitialized sync channel. Call ChannelProxy::Init to
97 // initialize the channel. This two-step setup allows message filters to be
98 // added before any messages are sent or received.
danakjc3fb6c52016-04-23 13:21:09 +090099 static std::unique_ptr<SyncChannel> Create(
morrita@chromium.org15b48602014-06-06 01:15:38 +0900100 Listener* listener,
dchengea780ac2014-08-29 01:59:29 +0900101 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
morrita@chromium.org15b48602014-06-06 01:15:38 +0900102 base::WaitableEvent* shutdown_event);
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900103
dchengef7721a2014-10-22 11:29:52 +0900104 ~SyncChannel() override;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900105
dchengef7721a2014-10-22 11:29:52 +0900106 bool Send(Message* message) override;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900107
piman@chromium.org5a00b882012-03-31 06:29:30 +0900108 // Sets the dispatch group for this channel, to only allow re-entrant dispatch
109 // of messages to other channels in the same group.
piman@google.com0cbefaa2011-04-08 12:38:21 +0900110 //
111 // Normally, any unblocking message coming from any channel can be dispatched
112 // when any (possibly other) channel is blocked on sending a message. This is
113 // needed in some cases to unblock certain loops (e.g. necessary when some
114 // processes share a window hierarchy), but may cause re-entrancy issues in
115 // some cases where such loops are not possible. This flags allows the tagging
piman@chromium.org5a00b882012-03-31 06:29:30 +0900116 // of some particular channels to only re-enter in known correct cases.
117 //
118 // Incoming messages on channels belonging to a group that is not
119 // kRestrictDispatchGroup_None will only be dispatched while a sync message is
120 // being sent on a channel of the *same* group.
121 // Incoming messages belonging to the kRestrictDispatchGroup_None group (the
122 // default) will be dispatched in any case.
123 void SetRestrictDispatchChannelGroup(int group);
piman@google.com0cbefaa2011-04-08 12:38:21 +0900124
rockotedb92032015-08-06 09:32:29 +0900125 // Creates a new IPC::SyncMessageFilter and adds it to this SyncChannel.
126 // This should be used instead of directly constructing a new
127 // SyncMessageFilter.
128 scoped_refptr<IPC::SyncMessageFilter> CreateSyncMessageFilter();
129
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900130 protected:
131 class ReceivedSyncMsgQueue;
132 friend class ReceivedSyncMsgQueue;
133
134 // SyncContext holds the per object data for SyncChannel, so that SyncChannel
135 // can be deleted while it's being used in a different thread. See
136 // ChannelProxy::Context for more information.
teravest@chromium.orgcd16b3a2013-02-05 03:14:28 +0900137 class SyncContext : public Context {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900138 public:
dchengea780ac2014-08-29 01:59:29 +0900139 SyncContext(
140 Listener* listener,
141 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
142 base::WaitableEvent* shutdown_event);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900143
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900144 // Adds information about an outgoing sync message to the context so that
145 // we know how to deserialize the reply.
rockot0a321712016-07-08 05:26:02 +0900146 bool Push(SyncMessage* sync_msg);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900147
148 // Cleanly remove the top deserializer (and throw it away). Returns the
149 // result of the Send call for that message.
150 bool Pop();
151
rockot0a321712016-07-08 05:26:02 +0900152 // Returns a Mojo Event that signals when a sync send is complete or timed
153 // out or the process shut down.
rockot39af2742017-03-25 03:36:44 +0900154 base::WaitableEvent* GetSendDoneEvent();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900155
rockot0a321712016-07-08 05:26:02 +0900156 // Returns a Mojo Event that signals when an incoming message that's not the
157 // pending reply needs to get dispatched (by calling DispatchMessages.)
rockot39af2742017-03-25 03:36:44 +0900158 base::WaitableEvent* GetDispatchEvent();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900159
160 void DispatchMessages();
161
162 // Checks if the given message is blocking the listener thread because of a
163 // synchronous send. If it is, the thread is unblocked and true is
164 // returned. Otherwise the function returns false.
165 bool TryToUnblockListener(const Message* msg);
166
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900167 base::WaitableEvent* shutdown_event() { return shutdown_event_; }
168
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900169 ReceivedSyncMsgQueue* received_sync_msgs() {
rsleevi@chromium.org23b66232013-06-01 13:11:27 +0900170 return received_sync_msgs_.get();
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900171 }
172
piman@chromium.org5a00b882012-03-31 06:29:30 +0900173 void set_restrict_dispatch_group(int group) {
174 restrict_dispatch_group_ = group;
175 }
176
177 int restrict_dispatch_group() const {
178 return restrict_dispatch_group_;
179 }
piman@google.com0cbefaa2011-04-08 12:38:21 +0900180
rockot39af2742017-03-25 03:36:44 +0900181 void OnSendDoneEventSignaled(base::RunLoop* nested_loop,
182 base::WaitableEvent* event);
183
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900184 private:
dchengef7721a2014-10-22 11:29:52 +0900185 ~SyncContext() override;
jabdelmalek@google.comeb921652010-04-07 05:33:36 +0900186 // ChannelProxy methods that we override.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900187
188 // Called on the listener thread.
dchengef7721a2014-10-22 11:29:52 +0900189 void Clear() override;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900190
191 // Called on the IPC thread.
dchengef7721a2014-10-22 11:29:52 +0900192 bool OnMessageReceived(const Message& msg) override;
193 void OnChannelError() override;
rockote7c47902016-09-09 03:24:56 +0900194 void OnChannelOpened() override;
dchengef7721a2014-10-22 11:29:52 +0900195 void OnChannelClosed() override;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900196
197 // Cancels all pending Send calls.
198 void CancelPendingSends();
199
rockot0a321712016-07-08 05:26:02 +0900200 void OnShutdownEventSignaled(base::WaitableEvent* event);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900201
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900202 typedef std::deque<PendingSyncMsg> PendingSyncMessageQueue;
203 PendingSyncMessageQueue deserializers_;
rockot0a321712016-07-08 05:26:02 +0900204 bool reject_new_deserializers_ = false;
brettw@chromium.orgabe477a2011-01-21 13:55:52 +0900205 base::Lock deserializers_lock_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900206
207 scoped_refptr<ReceivedSyncMsgQueue> received_sync_msgs_;
208
209 base::WaitableEvent* shutdown_event_;
210 base::WaitableEventWatcher shutdown_watcher_;
teravest@chromium.orgcd16b3a2013-02-05 03:14:28 +0900211 base::WaitableEventWatcher::EventCallback shutdown_watcher_callback_;
piman@chromium.org5a00b882012-03-31 06:29:30 +0900212 int restrict_dispatch_group_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900213 };
214
215 private:
dchengea780ac2014-08-29 01:59:29 +0900216 SyncChannel(
217 Listener* listener,
218 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
219 base::WaitableEvent* shutdown_event);
morrita@chromium.org15b48602014-06-06 01:15:38 +0900220
rockot39af2742017-03-25 03:36:44 +0900221 void OnDispatchEventSignaled(base::WaitableEvent* event);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900222
223 SyncContext* sync_context() {
224 return reinterpret_cast<SyncContext*>(context());
225 }
226
227 // Both these functions wait for a reply, timeout or process shutdown. The
228 // latter one also runs a nested message loop in the meantime.
rockot0a321712016-07-08 05:26:02 +0900229 static void WaitForReply(mojo::SyncHandleRegistry* registry,
230 SyncContext* context,
231 bool pump_messages);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900232
233 // Runs a nested message loop until a reply arrives, times out, or the process
234 // shuts down.
jam@chromium.orgebd07182009-12-01 11:34:18 +0900235 static void WaitForReplyWithNestedMessageLoop(SyncContext* context);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900236
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900237 // Starts the dispatch watcher.
238 void StartWatching();
239
rockot8115a592015-08-07 15:23:59 +0900240 // ChannelProxy overrides:
241 void OnChannelInit() override;
242
rockot0a321712016-07-08 05:26:02 +0900243 scoped_refptr<mojo::SyncHandleRegistry> sync_handle_registry_;
244
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900245 // Used to signal events between the IPC and listener threads.
rockot39af2742017-03-25 03:36:44 +0900246 base::WaitableEventWatcher dispatch_watcher_;
247 base::WaitableEventWatcher::EventCallback dispatch_watcher_callback_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900248
rockot8115a592015-08-07 15:23:59 +0900249 // Tracks SyncMessageFilters created before complete channel initialization.
250 std::vector<scoped_refptr<SyncMessageFilter>> pre_init_sync_message_filters_;
251
tfarina@chromium.orgb73eaee2010-06-07 11:10:18 +0900252 DISALLOW_COPY_AND_ASSIGN(SyncChannel);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900253};
254
255} // namespace IPC
256
thestig@chromium.org519c9ac2011-11-15 09:29:48 +0900257#endif // IPC_IPC_SYNC_CHANNEL_H_