1 : // Copyright (c) 2006-2008 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 "chrome/common/ipc_sync_channel.h"
6 :
7 : #include "base/lazy_instance.h"
8 : #include "base/logging.h"
9 : #include "base/thread_local.h"
10 : #include "base/message_loop.h"
11 : #include "base/waitable_event.h"
12 : #include "base/waitable_event_watcher.h"
13 : #include "chrome/common/ipc_sync_message.h"
14 :
15 : using base::TimeDelta;
16 : using base::TimeTicks;
17 : using base::WaitableEvent;
18 :
19 : namespace IPC {
20 : // When we're blocked in a Send(), we need to process incoming synchronous
21 : // messages right away because it could be blocking our reply (either
22 : // directly from the same object we're calling, or indirectly through one or
23 : // more other channels). That means that in SyncContext's OnMessageReceived,
24 : // we need to process sync message right away if we're blocked. However a
25 : // simple check isn't sufficient, because the listener thread can be in the
26 : // process of calling Send.
27 : // To work around this, when SyncChannel filters a sync message, it sets
28 : // an event that the listener thread waits on during its Send() call. This
29 : // allows us to dispatch incoming sync messages when blocked. The race
30 : // condition is handled because if Send is in the process of being called, it
31 : // will check the event. In case the listener thread isn't sending a message,
32 : // we queue a task on the listener thread to dispatch the received messages.
33 : // The messages are stored in this queue object that's shared among all
34 : // SyncChannel objects on the same thread (since one object can receive a
35 : // sync message while another one is blocked).
36 :
37 : class SyncChannel::ReceivedSyncMsgQueue :
38 : public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> {
39 : public:
40 : // Returns the ReceivedSyncMsgQueue instance for this thread, creating one
41 : // if necessary. Call RemoveContext on the same thread when done.
42 0 : static ReceivedSyncMsgQueue* AddContext() {
43 : // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple
44 : // SyncChannel objects can block the same thread).
45 0 : ReceivedSyncMsgQueue* rv = lazy_tls_ptr_.Pointer()->Get();
46 0 : if (!rv) {
47 0 : rv = new ReceivedSyncMsgQueue();
48 0 : ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Set(rv);
49 : }
50 0 : rv->listener_count_++;
51 0 : return rv;
52 : }
53 :
54 0 : ~ReceivedSyncMsgQueue() {
55 0 : }
56 :
57 : // Called on IPC thread when a synchronous message or reply arrives.
58 0 : void QueueMessage(const Message& msg, SyncChannel::SyncContext* context) {
59 : bool was_task_pending;
60 : {
61 0 : AutoLock auto_lock(message_lock_);
62 :
63 0 : was_task_pending = task_pending_;
64 0 : task_pending_ = true;
65 :
66 : // We set the event in case the listener thread is blocked (or is about
67 : // to). In case it's not, the PostTask dispatches the messages.
68 0 : message_queue_.push_back(QueuedMessage(new Message(msg), context));
69 : }
70 :
71 0 : dispatch_event_.Signal();
72 0 : if (!was_task_pending) {
73 : listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
74 0 : this, &ReceivedSyncMsgQueue::DispatchMessagesTask));
75 : }
76 0 : }
77 :
78 0 : void QueueReply(const Message &msg, SyncChannel::SyncContext* context) {
79 0 : received_replies_.push_back(QueuedMessage(new Message(msg), context));
80 0 : }
81 :
82 : // Called on the listener's thread to process any queues synchronous
83 : // messages.
84 0 : void DispatchMessagesTask() {
85 : {
86 0 : AutoLock auto_lock(message_lock_);
87 0 : task_pending_ = false;
88 : }
89 0 : DispatchMessages();
90 0 : }
91 :
92 0 : void DispatchMessages() {
93 0 : while (true) {
94 : Message* message;
95 0 : scoped_refptr<SyncChannel::SyncContext> context;
96 : {
97 0 : AutoLock auto_lock(message_lock_);
98 0 : if (message_queue_.empty())
99 : break;
100 :
101 0 : message = message_queue_.front().message;
102 0 : context = message_queue_.front().context;
103 0 : message_queue_.pop_front();
104 : }
105 :
106 0 : context->OnDispatchMessage(*message);
107 0 : delete message;
108 : }
109 0 : }
110 :
111 : // SyncChannel calls this in its destructor.
112 0 : void RemoveContext(SyncContext* context) {
113 0 : AutoLock auto_lock(message_lock_);
114 :
115 0 : SyncMessageQueue::iterator iter = message_queue_.begin();
116 0 : while (iter != message_queue_.end()) {
117 0 : if (iter->context == context) {
118 0 : delete iter->message;
119 0 : iter = message_queue_.erase(iter);
120 : } else {
121 0 : iter++;
122 : }
123 : }
124 :
125 0 : if (--listener_count_ == 0) {
126 0 : DCHECK(lazy_tls_ptr_.Pointer()->Get());
127 0 : lazy_tls_ptr_.Pointer()->Set(NULL);
128 : }
129 0 : }
130 :
131 0 : WaitableEvent* dispatch_event() { return &dispatch_event_; }
132 : MessageLoop* listener_message_loop() { return listener_message_loop_; }
133 :
134 : // Holds a pointer to the per-thread ReceivedSyncMsgQueue object.
135 : static base::LazyInstance<base::ThreadLocalPointer<ReceivedSyncMsgQueue> >
136 : lazy_tls_ptr_;
137 :
138 : // Called on the ipc thread to check if we can unblock any current Send()
139 : // calls based on a queued reply.
140 0 : void DispatchReplies() {
141 0 : for (size_t i = 0; i < received_replies_.size(); ++i) {
142 0 : Message* message = received_replies_[i].message;
143 0 : if (received_replies_[i].context->TryToUnblockListener(message)) {
144 0 : delete message;
145 0 : received_replies_.erase(received_replies_.begin() + i);
146 0 : return;
147 : }
148 : }
149 : }
150 :
151 : private:
152 : // See the comment in SyncChannel::SyncChannel for why this event is created
153 : // as manual reset.
154 0 : ReceivedSyncMsgQueue() :
155 : dispatch_event_(true, false),
156 0 : listener_message_loop_(MessageLoop::current()),
157 : task_pending_(false),
158 0 : listener_count_(0) {
159 0 : }
160 :
161 : // Holds information about a queued synchronous message or reply.
162 0 : struct QueuedMessage {
163 0 : QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { }
164 : Message* message;
165 : scoped_refptr<SyncChannel::SyncContext> context;
166 : };
167 :
168 : typedef std::deque<QueuedMessage> SyncMessageQueue;
169 : SyncMessageQueue message_queue_;
170 :
171 : std::vector<QueuedMessage> received_replies_;
172 :
173 : // Set when we got a synchronous message that we must respond to as the
174 : // sender needs its reply before it can reply to our original synchronous
175 : // message.
176 : WaitableEvent dispatch_event_;
177 : MessageLoop* listener_message_loop_;
178 : Lock message_lock_;
179 : bool task_pending_;
180 : int listener_count_;
181 : };
182 :
183 : base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> >
184 1464 : SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_(base::LINKER_INITIALIZED);
185 :
186 0 : SyncChannel::SyncContext::SyncContext(
187 : Channel::Listener* listener,
188 : MessageFilter* filter,
189 : MessageLoop* ipc_thread,
190 : WaitableEvent* shutdown_event)
191 : : ChannelProxy::Context(listener, filter, ipc_thread),
192 : received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()),
193 0 : shutdown_event_(shutdown_event) {
194 0 : }
195 :
196 0 : SyncChannel::SyncContext::~SyncContext() {
197 0 : while (!deserializers_.empty())
198 0 : Pop();
199 0 : }
200 :
201 : // Adds information about an outgoing sync message to the context so that
202 : // we know how to deserialize the reply. Returns a handle that's set when
203 : // the reply has arrived.
204 0 : void SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
205 : // The event is created as manual reset because in between Signal and
206 : // OnObjectSignalled, another Send can happen which would stop the watcher
207 : // from being called. The event would get watched later, when the nested
208 : // Send completes, so the event will need to remain set.
209 : PendingSyncMsg pending(SyncMessage::GetMessageId(*sync_msg),
210 : sync_msg->GetReplyDeserializer(),
211 0 : new WaitableEvent(true, false));
212 0 : AutoLock auto_lock(deserializers_lock_);
213 0 : deserializers_.push_back(pending);
214 0 : }
215 :
216 0 : bool SyncChannel::SyncContext::Pop() {
217 : bool result;
218 : {
219 0 : AutoLock auto_lock(deserializers_lock_);
220 0 : PendingSyncMsg msg = deserializers_.back();
221 0 : delete msg.deserializer;
222 0 : delete msg.done_event;
223 0 : msg.done_event = NULL;
224 0 : deserializers_.pop_back();
225 0 : result = msg.send_result;
226 : }
227 :
228 : // We got a reply to a synchronous Send() call that's blocking the listener
229 : // thread. However, further down the call stack there could be another
230 : // blocking Send() call, whose reply we received after we made this last
231 : // Send() call. So check if we have any queued replies available that
232 : // can now unblock the listener thread.
233 : ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
234 0 : received_sync_msgs_.get(), &ReceivedSyncMsgQueue::DispatchReplies));
235 :
236 0 : return result;
237 : }
238 :
239 0 : WaitableEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
240 0 : AutoLock auto_lock(deserializers_lock_);
241 0 : return deserializers_.back().done_event;
242 : }
243 :
244 0 : WaitableEvent* SyncChannel::SyncContext::GetDispatchEvent() {
245 0 : return received_sync_msgs_->dispatch_event();
246 : }
247 :
248 0 : void SyncChannel::SyncContext::DispatchMessages() {
249 0 : received_sync_msgs_->DispatchMessages();
250 0 : }
251 :
252 0 : bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) {
253 0 : AutoLock auto_lock(deserializers_lock_);
254 0 : if (deserializers_.empty() ||
255 0 : !SyncMessage::IsMessageReplyTo(*msg, deserializers_.back().id)) {
256 0 : return false;
257 : }
258 :
259 0 : if (!msg->is_reply_error()) {
260 0 : deserializers_.back().send_result = deserializers_.back().deserializer->
261 0 : SerializeOutputParameters(*msg);
262 : }
263 0 : deserializers_.back().done_event->Signal();
264 :
265 0 : return true;
266 : }
267 :
268 0 : void SyncChannel::SyncContext::Clear() {
269 0 : CancelPendingSends();
270 0 : received_sync_msgs_->RemoveContext(this);
271 :
272 0 : Context::Clear();
273 0 : }
274 :
275 0 : void SyncChannel::SyncContext::OnMessageReceived(const Message& msg) {
276 : // Give the filters a chance at processing this message.
277 0 : if (TryFilters(msg))
278 0 : return;
279 :
280 0 : if (TryToUnblockListener(&msg))
281 0 : return;
282 :
283 0 : if (msg.should_unblock()) {
284 0 : received_sync_msgs_->QueueMessage(msg, this);
285 0 : return;
286 : }
287 :
288 0 : if (msg.is_reply()) {
289 0 : received_sync_msgs_->QueueReply(msg, this);
290 0 : return;
291 : }
292 :
293 0 : return Context::OnMessageReceivedNoFilter(msg);
294 : }
295 :
296 0 : void SyncChannel::SyncContext::OnChannelError() {
297 0 : CancelPendingSends();
298 0 : shutdown_watcher_.StopWatching();
299 0 : Context::OnChannelError();
300 0 : }
301 :
302 0 : void SyncChannel::SyncContext::OnChannelOpened() {
303 0 : shutdown_watcher_.StartWatching(shutdown_event_, this);
304 0 : Context::OnChannelOpened();
305 0 : }
306 :
307 0 : void SyncChannel::SyncContext::OnChannelClosed() {
308 0 : shutdown_watcher_.StopWatching();
309 0 : Context::OnChannelClosed();
310 0 : }
311 :
312 0 : void SyncChannel::SyncContext::OnSendTimeout(int message_id) {
313 0 : AutoLock auto_lock(deserializers_lock_);
314 0 : PendingSyncMessageQueue::iterator iter;
315 0 : for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
316 0 : if (iter->id == message_id) {
317 0 : iter->done_event->Signal();
318 0 : break;
319 : }
320 : }
321 0 : }
322 :
323 0 : void SyncChannel::SyncContext::CancelPendingSends() {
324 0 : AutoLock auto_lock(deserializers_lock_);
325 0 : PendingSyncMessageQueue::iterator iter;
326 0 : for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++)
327 0 : iter->done_event->Signal();
328 0 : }
329 :
330 0 : void SyncChannel::SyncContext::OnWaitableEventSignaled(WaitableEvent* event) {
331 0 : DCHECK(event == shutdown_event_);
332 : // Process shut down before we can get a reply to a synchronous message.
333 : // Cancel pending Send calls, which will end up setting the send done event.
334 0 : CancelPendingSends();
335 0 : }
336 :
337 :
338 0 : SyncChannel::SyncChannel(
339 : const std::wstring& channel_id, Channel::Mode mode,
340 : Channel::Listener* listener, MessageFilter* filter,
341 : MessageLoop* ipc_message_loop, bool create_pipe_now,
342 : WaitableEvent* shutdown_event)
343 : : ChannelProxy(
344 : channel_id, mode, ipc_message_loop,
345 0 : new SyncContext(listener, filter, ipc_message_loop, shutdown_event),
346 : create_pipe_now),
347 0 : sync_messages_with_no_timeout_allowed_(true) {
348 : // Ideally we only want to watch this object when running a nested message
349 : // loop. However, we don't know when it exits if there's another nested
350 : // message loop running under it or not, so we wouldn't know whether to
351 : // stop or keep watching. So we always watch it, and create the event as
352 : // manual reset since the object watcher might otherwise reset the event
353 : // when we're doing a WaitMany.
354 0 : dispatch_watcher_.StartWatching(sync_context()->GetDispatchEvent(), this);
355 0 : }
356 :
357 0 : SyncChannel::~SyncChannel() {
358 0 : }
359 :
360 0 : bool SyncChannel::Send(Message* message) {
361 0 : return SendWithTimeout(message, base::kNoTimeout);
362 : }
363 :
364 0 : bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) {
365 0 : if (!message->is_sync()) {
366 0 : ChannelProxy::Send(message);
367 0 : return true;
368 : }
369 :
370 : // *this* might get deleted in WaitForReply.
371 0 : scoped_refptr<SyncContext> context(sync_context());
372 0 : if (context->shutdown_event()->IsSignaled()) {
373 0 : delete message;
374 0 : return false;
375 : }
376 :
377 0 : DCHECK(sync_messages_with_no_timeout_allowed_ ||
378 0 : timeout_ms != base::kNoTimeout);
379 0 : SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
380 0 : context->Push(sync_msg);
381 0 : int message_id = SyncMessage::GetMessageId(*sync_msg);
382 0 : WaitableEvent* pump_messages_event = sync_msg->pump_messages_event();
383 :
384 0 : ChannelProxy::Send(message);
385 :
386 0 : if (timeout_ms != base::kNoTimeout) {
387 : // We use the sync message id so that when a message times out, we don't
388 : // confuse it with another send that is either above/below this Send in
389 : // the call stack.
390 0 : context->ipc_message_loop()->PostDelayedTask(FROM_HERE,
391 : NewRunnableMethod(context.get(),
392 0 : &SyncContext::OnSendTimeout, message_id), timeout_ms);
393 : }
394 :
395 : // Wait for reply, or for any other incoming synchronous messages.
396 0 : WaitForReply(pump_messages_event);
397 :
398 0 : return context->Pop();
399 : }
400 :
401 0 : void SyncChannel::WaitForReply(WaitableEvent* pump_messages_event) {
402 0 : while (true) {
403 : WaitableEvent* objects[] = {
404 0 : sync_context()->GetDispatchEvent(),
405 0 : sync_context()->GetSendDoneEvent(),
406 : pump_messages_event
407 0 : };
408 :
409 0 : unsigned count = pump_messages_event ? 3: 2;
410 0 : unsigned result = WaitableEvent::WaitMany(objects, count);
411 0 : if (result == 0 /* dispatch event */) {
412 : // We're waiting for a reply, but we received a blocking synchronous
413 : // call. We must process it or otherwise a deadlock might occur.
414 0 : sync_context()->GetDispatchEvent()->Reset();
415 0 : sync_context()->DispatchMessages();
416 0 : continue;
417 : }
418 :
419 0 : if (result == 2 /* pump_messages_event */)
420 0 : WaitForReplyWithNestedMessageLoop(); // Start a nested message loop.
421 :
422 : break;
423 : }
424 0 : }
425 :
426 0 : void SyncChannel::WaitForReplyWithNestedMessageLoop() {
427 0 : WaitableEvent* old_done_event = send_done_watcher_.GetWatchedEvent();
428 0 : send_done_watcher_.StopWatching();
429 0 : send_done_watcher_.StartWatching(sync_context()->GetSendDoneEvent(), this);
430 0 : bool old_state = MessageLoop::current()->NestableTasksAllowed();
431 0 : MessageLoop::current()->SetNestableTasksAllowed(true);
432 0 : MessageLoop::current()->Run();
433 0 : MessageLoop::current()->SetNestableTasksAllowed(old_state);
434 0 : if (old_done_event)
435 0 : send_done_watcher_.StartWatching(old_done_event, this);
436 0 : }
437 :
438 0 : void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) {
439 0 : WaitableEvent* dispatch_event = sync_context()->GetDispatchEvent();
440 0 : if (event == dispatch_event) {
441 : // The call to DispatchMessages might delete this object, so reregister
442 : // the object watcher first.
443 0 : dispatch_event->Reset();
444 0 : dispatch_watcher_.StartWatching(dispatch_event, this);
445 0 : sync_context()->DispatchMessages();
446 : } else {
447 : // We got the reply, timed out or the process shutdown.
448 0 : DCHECK(event == sync_context()->GetSendDoneEvent());
449 0 : MessageLoop::current()->Quit();
450 : }
451 0 : }
452 :
453 4392 : } // namespace IPC
|