1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef IPC_IPC_SYNC_SENDER_H__
6 #define IPC_IPC_SYNC_SENDER_H__
12 #include "base/basictypes.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/synchronization/lock.h"
15 #include "base/synchronization/waitable_event_watcher.h"
16 #include "ipc/ipc_channel_handle.h"
17 #include "ipc/ipc_channel_proxy.h"
18 #include "ipc/ipc_sync_message.h"
27 class MessageReplyDeserializer;
29 // This is similar to ChannelProxy, with the added feature of supporting sending
30 // synchronous messages.
32 // Overview of how the sync channel works
33 // --------------------------------------
34 // When the sending thread sends a synchronous message, we create a bunch
35 // of tracking info (created in SendWithTimeout, stored in the PendingSyncMsg
36 // structure) associated with the message that we identify by the unique
37 // "MessageId" on the SyncMessage. Among the things we save is the
38 // "Deserializer" which is provided by the sync message. This object is in
39 // charge of reading the parameters from the reply message and putting them in
40 // the output variables provided by its caller.
42 // The info gets stashed in a queue since we could have a nested stack of sync
43 // messages (each side could send sync messages in response to sync messages,
44 // so it works like calling a function). The message is sent to the I/O thread
45 // for dispatch and the original thread blocks waiting for the reply.
47 // SyncContext maintains the queue in a threadsafe way and listens for replies
48 // on the I/O thread. When a reply comes in that matches one of the messages
49 // it's looking for (using the unique message ID), it will execute the
50 // deserializer stashed from before, and unblock the original thread.
53 // Significant complexity results from the fact that messages are still coming
54 // in while the original thread is blocked. Normal async messages are queued
55 // and dispatched after the blocking call is complete. Sync messages must
56 // be dispatched in a reentrant manner to avoid deadlock.
59 // Note that care must be taken that the lifetime of the ipc_thread argument
60 // is more than this object. If the message loop goes away while this object
61 // is running and it's used to send a message, then it will use the invalid
62 // message loop pointer to proxy it to the ipc thread.
63 class IPC_EXPORT SyncChannel : public ChannelProxy,
64 public base::WaitableEventWatcher::Delegate {
66 SyncChannel(const IPC::ChannelHandle& channel_handle,
68 Channel::Listener* listener,
69 base::MessageLoopProxy* ipc_message_loop,
71 base::WaitableEvent* shutdown_event);
72 virtual ~SyncChannel();
74 virtual bool Send(Message* message);
75 virtual bool SendWithTimeout(Message* message, int timeout_ms);
77 // Whether we allow sending messages with no time-out.
78 void set_sync_messages_with_no_timeout_allowed(bool value) {
79 sync_messages_with_no_timeout_allowed_ = value;
82 // Sets this channel to only dispatch its incoming unblocking messages when it
83 // is itself blocked on sending a sync message, not when other channels are.
85 // Normally, any unblocking message coming from any channel can be dispatched
86 // when any (possibly other) channel is blocked on sending a message. This is
87 // needed in some cases to unblock certain loops (e.g. necessary when some
88 // processes share a window hierarchy), but may cause re-entrancy issues in
89 // some cases where such loops are not possible. This flags allows the tagging
90 // of some particular channels to not re-enter in such cases.
91 void SetRestrictDispatchToSameChannel(bool value);
94 class ReceivedSyncMsgQueue;
95 friend class ReceivedSyncMsgQueue;
97 // SyncContext holds the per object data for SyncChannel, so that SyncChannel
98 // can be deleted while it's being used in a different thread. See
99 // ChannelProxy::Context for more information.
100 class SyncContext : public Context,
101 public base::WaitableEventWatcher::Delegate {
103 SyncContext(Channel::Listener* listener,
104 base::MessageLoopProxy* ipc_thread,
105 base::WaitableEvent* shutdown_event);
107 // Adds information about an outgoing sync message to the context so that
108 // we know how to deserialize the reply.
109 void Push(SyncMessage* sync_msg);
111 // Cleanly remove the top deserializer (and throw it away). Returns the
112 // result of the Send call for that message.
115 // Returns an event that's set when the send is complete, timed out or the
116 // process shut down.
117 base::WaitableEvent* GetSendDoneEvent();
119 // Returns an event that's set when an incoming message that's not the reply
120 // needs to get dispatched (by calling SyncContext::DispatchMessages).
121 base::WaitableEvent* GetDispatchEvent();
123 void DispatchMessages();
125 // Checks if the given message is blocking the listener thread because of a
126 // synchronous send. If it is, the thread is unblocked and true is
127 // returned. Otherwise the function returns false.
128 bool TryToUnblockListener(const Message* msg);
130 // Called on the IPC thread when a sync send that runs a nested message loop
132 void OnSendTimeout(int message_id);
134 base::WaitableEvent* shutdown_event() { return shutdown_event_; }
136 ReceivedSyncMsgQueue* received_sync_msgs() {
137 return received_sync_msgs_;
140 void set_restrict_dispatch(bool value) { restrict_dispatch_ = value; }
141 bool restrict_dispatch() const { return restrict_dispatch_; }
144 virtual ~SyncContext();
145 // ChannelProxy methods that we override.
147 // Called on the listener thread.
148 virtual void Clear();
150 // Called on the IPC thread.
151 virtual bool OnMessageReceived(const Message& msg);
152 virtual void OnChannelError();
153 virtual void OnChannelOpened();
154 virtual void OnChannelClosed();
156 // Cancels all pending Send calls.
157 void CancelPendingSends();
159 // WaitableEventWatcher::Delegate implementation.
160 virtual void OnWaitableEventSignaled(base::WaitableEvent* arg);
162 typedef std::deque<PendingSyncMsg> PendingSyncMessageQueue;
163 PendingSyncMessageQueue deserializers_;
164 base::Lock deserializers_lock_;
166 scoped_refptr<ReceivedSyncMsgQueue> received_sync_msgs_;
168 base::WaitableEvent* shutdown_event_;
169 base::WaitableEventWatcher shutdown_watcher_;
170 bool restrict_dispatch_;
174 // WaitableEventWatcher::Delegate implementation.
175 virtual void OnWaitableEventSignaled(base::WaitableEvent* arg);
177 SyncContext* sync_context() {
178 return reinterpret_cast<SyncContext*>(context());
181 // Both these functions wait for a reply, timeout or process shutdown. The
182 // latter one also runs a nested message loop in the meantime.
183 static void WaitForReply(
184 SyncContext* context, base::WaitableEvent* pump_messages_event);
186 // Runs a nested message loop until a reply arrives, times out, or the process
188 static void WaitForReplyWithNestedMessageLoop(SyncContext* context);
190 bool sync_messages_with_no_timeout_allowed_;
192 // Used to signal events between the IPC and listener threads.
193 base::WaitableEventWatcher dispatch_watcher_;
195 DISALLOW_COPY_AND_ASSIGN(SyncChannel);
200 #endif // IPC_IPC_SYNC_SENDER_H__