| Index: ipc/ipc_sync_channel.h
 | 
| diff --git a/ipc/ipc_sync_channel.h b/ipc/ipc_sync_channel.h
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..f5d2addec8f7ad2948d2b6aa15196355db55905c
 | 
| --- /dev/null
 | 
| +++ b/ipc/ipc_sync_channel.h
 | 
| @@ -0,0 +1,162 @@
 | 
| +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#ifndef IPC_IPC_SYNC_SENDER_H__
 | 
| +#define IPC_IPC_SYNC_SENDER_H__
 | 
| +
 | 
| +#include <string>
 | 
| +#include <deque>
 | 
| +
 | 
| +#include "base/basictypes.h"
 | 
| +#include "base/lock.h"
 | 
| +#include "base/ref_counted.h"
 | 
| +#include "base/waitable_event_watcher.h"
 | 
| +#include "ipc/ipc_channel_proxy.h"
 | 
| +
 | 
| +namespace base {
 | 
| +class WaitableEvent;
 | 
| +};
 | 
| +
 | 
| +namespace IPC {
 | 
| +
 | 
| +class SyncMessage;
 | 
| +class MessageReplyDeserializer;
 | 
| +
 | 
| +// This is similar to IPC::ChannelProxy, with the added feature of supporting
 | 
| +// sending synchronous messages.
 | 
| +// Note that care must be taken that the lifetime of the ipc_thread argument
 | 
| +// is more than this object.  If the message loop goes away while this object
 | 
| +// is running and it's used to send a message, then it will use the invalid
 | 
| +// message loop pointer to proxy it to the ipc thread.
 | 
| +class SyncChannel : public ChannelProxy,
 | 
| +                    public base::WaitableEventWatcher::Delegate {
 | 
| + public:
 | 
| +  SyncChannel(const std::string& channel_id, Channel::Mode mode,
 | 
| +              Channel::Listener* listener, MessageFilter* filter,
 | 
| +              MessageLoop* ipc_message_loop, bool create_pipe_now,
 | 
| +              base::WaitableEvent* shutdown_event);
 | 
| +  ~SyncChannel();
 | 
| +
 | 
| +  virtual bool Send(Message* message);
 | 
| +  virtual bool SendWithTimeout(Message* message, int timeout_ms);
 | 
| +
 | 
| +  // Whether we allow sending messages with no time-out.
 | 
| +  void set_sync_messages_with_no_timeout_allowed(bool value) {
 | 
| +    sync_messages_with_no_timeout_allowed_ = value;
 | 
| +  }
 | 
| +
 | 
| + protected:
 | 
| +  class ReceivedSyncMsgQueue;
 | 
| +  friend class ReceivedSyncMsgQueue;
 | 
| +
 | 
| +  // SyncContext holds the per object data for SyncChannel, so that SyncChannel
 | 
| +  // can be deleted while it's being used in a different thread.  See
 | 
| +  // ChannelProxy::Context for more information.
 | 
| +  class SyncContext : public Context,
 | 
| +                      public base::WaitableEventWatcher::Delegate {
 | 
| +   public:
 | 
| +    SyncContext(Channel::Listener* listener,
 | 
| +                MessageFilter* filter,
 | 
| +                MessageLoop* ipc_thread,
 | 
| +                base::WaitableEvent* shutdown_event);
 | 
| +
 | 
| +    ~SyncContext();
 | 
| +
 | 
| +    // Adds information about an outgoing sync message to the context so that
 | 
| +    // we know how to deserialize the reply.
 | 
| +    void Push(IPC::SyncMessage* sync_msg);
 | 
| +
 | 
| +    // Cleanly remove the top deserializer (and throw it away).  Returns the
 | 
| +    // result of the Send call for that message.
 | 
| +    bool Pop();
 | 
| +
 | 
| +    // Returns an event that's set when the send is complete, timed out or the
 | 
| +    // process shut down.
 | 
| +    base::WaitableEvent* GetSendDoneEvent();
 | 
| +
 | 
| +    // Returns an event that's set when an incoming message that's not the reply
 | 
| +    // needs to get dispatched (by calling SyncContext::DispatchMessages).
 | 
| +    base::WaitableEvent* GetDispatchEvent();
 | 
| +
 | 
| +    void DispatchMessages();
 | 
| +
 | 
| +    // Checks if the given message is blocking the listener thread because of a
 | 
| +    // synchronous send.  If it is, the thread is unblocked and true is
 | 
| +    // returned. Otherwise the function returns false.
 | 
| +    bool TryToUnblockListener(const Message* msg);
 | 
| +
 | 
| +    // Called on the IPC thread when a sync send that runs a nested message loop
 | 
| +    // times out.
 | 
| +    void OnSendTimeout(int message_id);
 | 
| +
 | 
| +    base::WaitableEvent* shutdown_event() { return shutdown_event_; }
 | 
| +
 | 
| +   private:
 | 
| +    // IPC::ChannelProxy methods that we override.
 | 
| +
 | 
| +    // Called on the listener thread.
 | 
| +   virtual void Clear();
 | 
| +
 | 
| +    // Called on the IPC thread.
 | 
| +    virtual void OnMessageReceived(const Message& msg);
 | 
| +    virtual void OnChannelError();
 | 
| +    virtual void OnChannelOpened();
 | 
| +    virtual void OnChannelClosed();
 | 
| +
 | 
| +    // Cancels all pending Send calls.
 | 
| +    void CancelPendingSends();
 | 
| +
 | 
| +    // WaitableEventWatcher::Delegate implementation.
 | 
| +    virtual void OnWaitableEventSignaled(base::WaitableEvent* arg);
 | 
| +
 | 
| +    // When sending a synchronous message, this structure contains an object
 | 
| +    // that knows how to deserialize the response.
 | 
| +    struct PendingSyncMsg {
 | 
| +      PendingSyncMsg(int id, IPC::MessageReplyDeserializer* d,
 | 
| +                     base::WaitableEvent* e) :
 | 
| +          id(id), deserializer(d), done_event(e), send_result(false) { }
 | 
| +      int id;
 | 
| +      IPC::MessageReplyDeserializer* deserializer;
 | 
| +      base::WaitableEvent* done_event;
 | 
| +      bool send_result;
 | 
| +    };
 | 
| +
 | 
| +    typedef std::deque<PendingSyncMsg> PendingSyncMessageQueue;
 | 
| +    PendingSyncMessageQueue deserializers_;
 | 
| +    Lock deserializers_lock_;
 | 
| +
 | 
| +    scoped_refptr<ReceivedSyncMsgQueue> received_sync_msgs_;
 | 
| +
 | 
| +    base::WaitableEvent* shutdown_event_;
 | 
| +    base::WaitableEventWatcher shutdown_watcher_;
 | 
| +  };
 | 
| +
 | 
| + private:
 | 
| +  // WaitableEventWatcher::Delegate implementation.
 | 
| +  virtual void OnWaitableEventSignaled(base::WaitableEvent* arg);
 | 
| +
 | 
| +  SyncContext* sync_context() {
 | 
| +    return reinterpret_cast<SyncContext*>(context());
 | 
| +  }
 | 
| +
 | 
| +  // Both these functions wait for a reply, timeout or process shutdown.  The
 | 
| +  // latter one also runs a nested message loop in the meantime.
 | 
| +  void WaitForReply(base::WaitableEvent* pump_messages_event);
 | 
| +
 | 
| +  // Runs a nested message loop until a reply arrives, times out, or the process
 | 
| +  // shuts down.
 | 
| +  void WaitForReplyWithNestedMessageLoop();
 | 
| +
 | 
| +  bool sync_messages_with_no_timeout_allowed_;
 | 
| +
 | 
| +  // Used to signal events between the IPC and listener threads.
 | 
| +  base::WaitableEventWatcher send_done_watcher_;
 | 
| +  base::WaitableEventWatcher dispatch_watcher_;
 | 
| +
 | 
| +  DISALLOW_EVIL_CONSTRUCTORS(SyncChannel);
 | 
| +};
 | 
| +
 | 
| +}  // namespace IPC
 | 
| +
 | 
| +#endif  // IPC_IPC_SYNC_SENDER_H__
 | 
| 
 |