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 #include "ipc/ipc_sync_message_filter.h" 6 7 #include "base/bind.h" 8 #include "base/location.h" 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/synchronization/waitable_event.h" 12 #include "ipc/ipc_sync_message.h" 13 14 using base::MessageLoopProxy; 15 16 namespace IPC { 17 18 SyncMessageFilter::SyncMessageFilter(base::WaitableEvent* shutdown_event) 19 : channel_(NULL), 20 listener_loop_(MessageLoopProxy::current()), 21 shutdown_event_(shutdown_event) { 22 } 23 24 bool SyncMessageFilter::Send(Message* message) { 25 { 26 base::AutoLock auto_lock(lock_); 27 if (!io_loop_.get()) { 28 delete message; 29 return false; 30 } 31 } 32 33 if (!message->is_sync()) { 34 io_loop_->PostTask( 35 FROM_HERE, base::Bind(&SyncMessageFilter::SendOnIOThread, this, message)); 36 return true; 37 } 38 39 base::WaitableEvent done_event(true, false); 40 PendingSyncMsg pending_message( 41 SyncMessage::GetMessageId(*message), 42 static_cast<SyncMessage*>(message)->GetReplyDeserializer(), 43 &done_event); 44 45 { 46 base::AutoLock auto_lock(lock_); 47 // Can't use this class on the main thread or else it can lead to deadlocks. 48 // Also by definition, can't use this on IO thread since we're blocking it. 49 DCHECK(MessageLoopProxy::current().get() != listener_loop_.get()); 50 DCHECK(MessageLoopProxy::current().get() != io_loop_.get()); 51 pending_sync_messages_.insert(&pending_message); 52 } 53 54 io_loop_->PostTask( 55 FROM_HERE, base::Bind(&SyncMessageFilter::SendOnIOThread, this, message)); 56 57 base::WaitableEvent* events[2] = { shutdown_event_, &done_event }; 58 base::WaitableEvent::WaitMany(events, 2); 59 60 { 61 base::AutoLock auto_lock(lock_); 62 delete pending_message.deserializer; 63 pending_sync_messages_.erase(&pending_message); 64 } 65 66 return pending_message.send_result; 67 } 68 69 void SyncMessageFilter::OnFilterAdded(Channel* channel) { 70 channel_ = channel; 71 base::AutoLock auto_lock(lock_); 72 io_loop_ = MessageLoopProxy::current(); 73 } 74 75 void SyncMessageFilter::OnChannelError() { 76 channel_ = NULL; 77 SignalAllEvents(); 78 } 79 80 void SyncMessageFilter::OnChannelClosing() { 81 channel_ = NULL; 82 SignalAllEvents(); 83 } 84 85 bool SyncMessageFilter::OnMessageReceived(const Message& message) { 86 base::AutoLock auto_lock(lock_); 87 for (PendingSyncMessages::iterator iter = pending_sync_messages_.begin(); 88 iter != pending_sync_messages_.end(); ++iter) { 89 if (SyncMessage::IsMessageReplyTo(message, (*iter)->id)) { 90 if (!message.is_reply_error()) { 91 (*iter)->send_result = 92 (*iter)->deserializer->SerializeOutputParameters(message); 93 } 94 (*iter)->done_event->Signal(); 95 return true; 96 } 97 } 98 99 return false; 100 } 101 102 SyncMessageFilter::~SyncMessageFilter() { 103 } 104 105 void SyncMessageFilter::SendOnIOThread(Message* message) { 106 if (channel_) { 107 channel_->Send(message); 108 return; 109 } 110 111 if (message->is_sync()) { 112 // We don't know which thread sent it, but it doesn't matter, just signal 113 // them all. 114 SignalAllEvents(); 115 } 116 117 delete message; 118 } 119 120 void SyncMessageFilter::SignalAllEvents() { 121 base::AutoLock auto_lock(lock_); 122 for (PendingSyncMessages::iterator iter = pending_sync_messages_.begin(); 123 iter != pending_sync_messages_.end(); ++iter) { 124 (*iter)->done_event->Signal(); 125 } 126 } 127 128 } // namespace IPC 129