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 CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
6 #define CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
10 #include "base/synchronization/lock.h"
11 #include "ipc/ipc_channel_proxy.h"
13 // Base class used to allow synchronous IPC messages to be sent and
14 // received in an asynchronous manner. To use this class add it as a filter to
15 // your IPC channel using ChannelProxy::AddFilter(). From then on, before
16 // sending a synchronous message, call SyncMessageReplyDispatcher::Push() with
17 // a callback and a key. This class will then handle the message response and
18 // will call the callback when it is received.
20 // This class is intended to be extended by classes implementing
21 // HandleMessageType with delegation for the messages they expect to receive in
22 // cases where you care about the return values of synchronous messages.
24 // Sample usage pattern:
25 // Define a class which inherits from SyncMessageCallContext which specifies
26 // the output_type tuple and has a Completed member function.
27 // class SampleContext
28 // : public SyncMessageReplyDispatcher::SyncMessageCallContext {
30 // typedef Tuple1<int> output_type;
31 // void Completed(int arg) {}
34 // // Add handling for desired message types.
35 // class SyncMessageReplyDispatcherImpl : public SyncMessageReplyDispatcher {
36 // virtual bool HandleMessageType(const IPC::Message& msg,
37 // SyncMessageReplyDispatcher* context) {
38 // switch (context->message_type()) {
39 // case AutomationMsg_CreateExternalTab::ID:
40 // InvokeCallback<CreateExternalTabContext>(msg, context);
42 // [HANDLING FOR OTHER EXPECTED MESSAGE TYPES]
47 // IPC::SyncChannel channel_;
48 // channel_.AddFilter(new SyncMessageReplyDispatcherImpl());
50 // sync_->Push(msg, new SampleContext, this);
51 // channel_->ChannelProxy::Send(msg);
53 class SyncMessageReplyDispatcher
: public IPC::ChannelProxy::MessageFilter
{
55 class SyncMessageCallContext
{
57 SyncMessageCallContext()
62 virtual ~SyncMessageCallContext() {}
64 uint32
message_type() const {
73 friend class SyncMessageReplyDispatcher
;
76 SyncMessageReplyDispatcher() {}
77 void Push(IPC::SyncMessage
* msg
, SyncMessageCallContext
* context
,
79 void Cancel(void* key
);
82 typedef std::deque
<SyncMessageCallContext
*> PendingSyncMessageQueue
;
84 SyncMessageCallContext
* GetContext(const IPC::Message
& msg
);
86 virtual bool OnMessageReceived(const IPC::Message
& msg
);
88 // Child classes must implement a handler for the message types they are
89 // interested in handling responses for. If you don't care about the replies
90 // to any of the sync messages you are handling, then you don't have to
92 virtual bool HandleMessageType(const IPC::Message
& msg
,
93 SyncMessageCallContext
* context
);
96 void InvokeCallback(const IPC::Message
& msg
,
97 SyncMessageCallContext
* call_context
) {
98 if (!call_context
|| !call_context
->key_
) {
99 NOTREACHED() << "Invalid context parameter";
103 T
* context
= static_cast<T
*>(call_context
);
104 T::output_type tmp
; // Acts as "initializer" for output parameters.
105 IPC::ParamDeserializer
<T::output_type
> deserializer(tmp
);
106 if (deserializer
.MessageReplyDeserializer::SerializeOutputParameters(msg
)) {
107 DispatchToMethod(context
, &T::Completed
, deserializer
.out_
);
110 // TODO(stoyan): How to handle errors?
114 PendingSyncMessageQueue message_queue_
;
115 base::Lock message_queue_lock_
;
118 #endif // CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_