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