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