ipc_sync_channel.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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.
4
5#ifndef IPC_IPC_SYNC_CHANNEL_H_
6#define IPC_IPC_SYNC_CHANNEL_H_
7
8#include <string>
9#include <deque>
10
11#include "base/basictypes.h"
12#include "base/memory/ref_counted.h"
13#include "base/synchronization/lock.h"
14#include "base/synchronization/waitable_event_watcher.h"
15#include "ipc/ipc_channel_handle.h"
16#include "ipc/ipc_channel_proxy.h"
17#include "ipc/ipc_sync_message.h"
18
19namespace base {
20class WaitableEvent;
21};
22
23namespace IPC {
24
25class SyncMessage;
26
27// This is similar to ChannelProxy, with the added feature of supporting sending
28// synchronous messages.
29//
30// Overview of how the sync channel works
31// --------------------------------------
32// When the sending thread sends a synchronous message, we create a bunch
33// of tracking info (created in SendWithTimeout, stored in the PendingSyncMsg
34// structure) associated with the message that we identify by the unique
35// "MessageId" on the SyncMessage. Among the things we save is the
36// "Deserializer" which is provided by the sync message. This object is in
37// charge of reading the parameters from the reply message and putting them in
38// the output variables provided by its caller.
39//
40// The info gets stashed in a queue since we could have a nested stack of sync
41// messages (each side could send sync messages in response to sync messages,
42// so it works like calling a function). The message is sent to the I/O thread
43// for dispatch and the original thread blocks waiting for the reply.
44//
45// SyncContext maintains the queue in a threadsafe way and listens for replies
46// on the I/O thread. When a reply comes in that matches one of the messages
47// it's looking for (using the unique message ID), it will execute the
48// deserializer stashed from before, and unblock the original thread.
49//
50//
51// Significant complexity results from the fact that messages are still coming
52// in while the original thread is blocked. Normal async messages are queued
53// and dispatched after the blocking call is complete. Sync messages must
54// be dispatched in a reentrant manner to avoid deadlock.
55//
56//
57// Note that care must be taken that the lifetime of the ipc_thread argument
58// is more than this object.  If the message loop goes away while this object
59// is running and it's used to send a message, then it will use the invalid
60// message loop pointer to proxy it to the ipc thread.
61class IPC_EXPORT SyncChannel : public ChannelProxy,
62                               public base::WaitableEventWatcher::Delegate {
63 public:
64  enum RestrictDispatchGroup {
65    kRestrictDispatchGroup_None = 0,
66  };
67
68  // Creates and initializes a sync channel. If create_pipe_now is specified,
69  // the channel will be initialized synchronously.
70  SyncChannel(const IPC::ChannelHandle& channel_handle,
71              Channel::Mode mode,
72              Listener* listener,
73              base::SingleThreadTaskRunner* ipc_task_runner,
74              bool create_pipe_now,
75              base::WaitableEvent* shutdown_event);
76
77  // Creates an uninitialized sync channel. Call ChannelProxy::Init to
78  // initialize the channel. This two-step setup allows message filters to be
79  // added before any messages are sent or received.
80  SyncChannel(Listener* listener,
81              base::SingleThreadTaskRunner* ipc_task_runner,
82              base::WaitableEvent* shutdown_event);
83
84  virtual ~SyncChannel();
85
86  virtual bool Send(Message* message) OVERRIDE;
87  virtual bool SendWithTimeout(Message* message, int timeout_ms);
88
89  // Whether we allow sending messages with no time-out.
90  void set_sync_messages_with_no_timeout_allowed(bool value) {
91    sync_messages_with_no_timeout_allowed_ = value;
92  }
93
94  // Sets the dispatch group for this channel, to only allow re-entrant dispatch
95  // of messages to other channels in the same group.
96  //
97  // Normally, any unblocking message coming from any channel can be dispatched
98  // when any (possibly other) channel is blocked on sending a message. This is
99  // needed in some cases to unblock certain loops (e.g. necessary when some
100  // processes share a window hierarchy), but may cause re-entrancy issues in
101  // some cases where such loops are not possible. This flags allows the tagging
102  // of some particular channels to only re-enter in known correct cases.
103  //
104  // Incoming messages on channels belonging to a group that is not
105  // kRestrictDispatchGroup_None will only be dispatched while a sync message is
106  // being sent on a channel of the *same* group.
107  // Incoming messages belonging to the kRestrictDispatchGroup_None group (the
108  // default) will be dispatched in any case.
109  void SetRestrictDispatchChannelGroup(int group);
110
111 protected:
112  class ReceivedSyncMsgQueue;
113  friend class ReceivedSyncMsgQueue;
114
115  // SyncContext holds the per object data for SyncChannel, so that SyncChannel
116  // can be deleted while it's being used in a different thread.  See
117  // ChannelProxy::Context for more information.
118  class SyncContext : public Context,
119                      public base::WaitableEventWatcher::Delegate {
120   public:
121    SyncContext(Listener* listener,
122                base::SingleThreadTaskRunner* ipc_task_runner,
123                base::WaitableEvent* shutdown_event);
124
125    // Adds information about an outgoing sync message to the context so that
126    // we know how to deserialize the reply.
127    void Push(SyncMessage* sync_msg);
128
129    // Cleanly remove the top deserializer (and throw it away).  Returns the
130    // result of the Send call for that message.
131    bool Pop();
132
133    // Returns an event that's set when the send is complete, timed out or the
134    // process shut down.
135    base::WaitableEvent* GetSendDoneEvent();
136
137    // Returns an event that's set when an incoming message that's not the reply
138    // needs to get dispatched (by calling SyncContext::DispatchMessages).
139    base::WaitableEvent* GetDispatchEvent();
140
141    void DispatchMessages();
142
143    // Checks if the given message is blocking the listener thread because of a
144    // synchronous send.  If it is, the thread is unblocked and true is
145    // returned. Otherwise the function returns false.
146    bool TryToUnblockListener(const Message* msg);
147
148    // Called on the IPC thread when a sync send that runs a nested message loop
149    // times out.
150    void OnSendTimeout(int message_id);
151
152    base::WaitableEvent* shutdown_event() { return shutdown_event_; }
153
154    ReceivedSyncMsgQueue* received_sync_msgs() {
155      return received_sync_msgs_;
156    }
157
158    void set_restrict_dispatch_group(int group) {
159      restrict_dispatch_group_ = group;
160    }
161
162    int restrict_dispatch_group() const {
163      return restrict_dispatch_group_;
164    }
165
166   private:
167    virtual ~SyncContext();
168    // ChannelProxy methods that we override.
169
170    // Called on the listener thread.
171    virtual void Clear() OVERRIDE;
172
173    // Called on the IPC thread.
174    virtual bool OnMessageReceived(const Message& msg) OVERRIDE;
175    virtual void OnChannelError() OVERRIDE;
176    virtual void OnChannelOpened() OVERRIDE;
177    virtual void OnChannelClosed() OVERRIDE;
178
179    // Cancels all pending Send calls.
180    void CancelPendingSends();
181
182    // WaitableEventWatcher::Delegate implementation.
183    virtual void OnWaitableEventSignaled(base::WaitableEvent* arg) OVERRIDE;
184
185    typedef std::deque<PendingSyncMsg> PendingSyncMessageQueue;
186    PendingSyncMessageQueue deserializers_;
187    base::Lock deserializers_lock_;
188
189    scoped_refptr<ReceivedSyncMsgQueue> received_sync_msgs_;
190
191    base::WaitableEvent* shutdown_event_;
192    base::WaitableEventWatcher shutdown_watcher_;
193    int restrict_dispatch_group_;
194  };
195
196 private:
197  // WaitableEventWatcher::Delegate implementation.
198  virtual void OnWaitableEventSignaled(base::WaitableEvent* arg) OVERRIDE;
199
200  SyncContext* sync_context() {
201    return reinterpret_cast<SyncContext*>(context());
202  }
203
204  // Both these functions wait for a reply, timeout or process shutdown.  The
205  // latter one also runs a nested message loop in the meantime.
206  static void WaitForReply(
207      SyncContext* context, base::WaitableEvent* pump_messages_event);
208
209  // Runs a nested message loop until a reply arrives, times out, or the process
210  // shuts down.
211  static void WaitForReplyWithNestedMessageLoop(SyncContext* context);
212
213  // Starts the dispatch watcher.
214  void StartWatching();
215
216  bool sync_messages_with_no_timeout_allowed_;
217
218  // Used to signal events between the IPC and listener threads.
219  base::WaitableEventWatcher dispatch_watcher_;
220
221  DISALLOW_COPY_AND_ASSIGN(SyncChannel);
222};
223
224}  // namespace IPC
225
226#endif  // IPC_IPC_SYNC_CHANNEL_H_
227