OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ipc/ipc_sync_channel.h" | 5 #include "ipc/ipc_sync_channel.h" |
6 | 6 |
7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/thread_local.h" | 9 #include "base/thread_local.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 } | 336 } |
337 | 337 |
338 void SyncChannel::SyncContext::CancelPendingSends() { | 338 void SyncChannel::SyncContext::CancelPendingSends() { |
339 AutoLock auto_lock(deserializers_lock_); | 339 AutoLock auto_lock(deserializers_lock_); |
340 PendingSyncMessageQueue::iterator iter; | 340 PendingSyncMessageQueue::iterator iter; |
341 for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) | 341 for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) |
342 iter->done_event->Signal(); | 342 iter->done_event->Signal(); |
343 } | 343 } |
344 | 344 |
345 void SyncChannel::SyncContext::OnWaitableEventSignaled(WaitableEvent* event) { | 345 void SyncChannel::SyncContext::OnWaitableEventSignaled(WaitableEvent* event) { |
346 DCHECK(event == shutdown_event_); | 346 if (event == shutdown_event_) { |
347 // Process shut down before we can get a reply to a synchronous message. | 347 // Process shut down before we can get a reply to a synchronous message. |
348 // Cancel pending Send calls, which will end up setting the send done event. | 348 // Cancel pending Send calls, which will end up setting the send done event. |
349 CancelPendingSends(); | 349 CancelPendingSends(); |
| 350 } else { |
| 351 // We got the reply, timed out or the process shutdown. |
| 352 DCHECK(event == GetSendDoneEvent()); |
| 353 MessageLoop::current()->Quit(); |
| 354 } |
350 } | 355 } |
351 | 356 |
352 | 357 |
353 SyncChannel::SyncChannel( | 358 SyncChannel::SyncChannel( |
354 const std::string& channel_id, Channel::Mode mode, | 359 const std::string& channel_id, Channel::Mode mode, |
355 Channel::Listener* listener, MessageFilter* filter, | 360 Channel::Listener* listener, MessageFilter* filter, |
356 MessageLoop* ipc_message_loop, bool create_pipe_now, | 361 MessageLoop* ipc_message_loop, bool create_pipe_now, |
357 WaitableEvent* shutdown_event) | 362 WaitableEvent* shutdown_event) |
358 : ChannelProxy( | 363 : ChannelProxy( |
359 channel_id, mode, ipc_message_loop, | 364 channel_id, mode, ipc_message_loop, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 if (timeout_ms != base::kNoTimeout) { | 406 if (timeout_ms != base::kNoTimeout) { |
402 // We use the sync message id so that when a message times out, we don't | 407 // We use the sync message id so that when a message times out, we don't |
403 // confuse it with another send that is either above/below this Send in | 408 // confuse it with another send that is either above/below this Send in |
404 // the call stack. | 409 // the call stack. |
405 context->ipc_message_loop()->PostDelayedTask(FROM_HERE, | 410 context->ipc_message_loop()->PostDelayedTask(FROM_HERE, |
406 NewRunnableMethod(context.get(), | 411 NewRunnableMethod(context.get(), |
407 &SyncContext::OnSendTimeout, message_id), timeout_ms); | 412 &SyncContext::OnSendTimeout, message_id), timeout_ms); |
408 } | 413 } |
409 | 414 |
410 // Wait for reply, or for any other incoming synchronous messages. | 415 // Wait for reply, or for any other incoming synchronous messages. |
411 WaitForReply(pump_messages_event); | 416 // *this* might get deleted, so only call static functions at this point. |
| 417 WaitForReply(context, pump_messages_event); |
412 | 418 |
413 return context->Pop(); | 419 return context->Pop(); |
414 } | 420 } |
415 | 421 |
416 void SyncChannel::WaitForReply(WaitableEvent* pump_messages_event) { | 422 void SyncChannel::WaitForReply( |
| 423 SyncContext* context, WaitableEvent* pump_messages_event) { |
417 while (true) { | 424 while (true) { |
418 WaitableEvent* objects[] = { | 425 WaitableEvent* objects[] = { |
419 sync_context()->GetDispatchEvent(), | 426 context->GetDispatchEvent(), |
420 sync_context()->GetSendDoneEvent(), | 427 context->GetSendDoneEvent(), |
421 pump_messages_event | 428 pump_messages_event |
422 }; | 429 }; |
423 | 430 |
424 unsigned count = pump_messages_event ? 3: 2; | 431 unsigned count = pump_messages_event ? 3: 2; |
425 size_t result = WaitableEvent::WaitMany(objects, count); | 432 size_t result = WaitableEvent::WaitMany(objects, count); |
426 if (result == 0 /* dispatch event */) { | 433 if (result == 0 /* dispatch event */) { |
427 // We're waiting for a reply, but we received a blocking synchronous | 434 // We're waiting for a reply, but we received a blocking synchronous |
428 // call. We must process it or otherwise a deadlock might occur. | 435 // call. We must process it or otherwise a deadlock might occur. |
429 sync_context()->GetDispatchEvent()->Reset(); | 436 context->GetDispatchEvent()->Reset(); |
430 sync_context()->DispatchMessages(); | 437 context->DispatchMessages(); |
431 continue; | 438 continue; |
432 } | 439 } |
433 | 440 |
434 if (result == 2 /* pump_messages_event */) | 441 if (result == 2 /* pump_messages_event */) |
435 WaitForReplyWithNestedMessageLoop(); // Start a nested message loop. | 442 WaitForReplyWithNestedMessageLoop(context); // Run a nested message loop. |
436 | 443 |
437 break; | 444 break; |
438 } | 445 } |
439 } | 446 } |
440 | 447 |
441 void SyncChannel::WaitForReplyWithNestedMessageLoop() { | 448 void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) { |
442 base::WaitableEventWatcher send_done_watcher; | 449 base::WaitableEventWatcher send_done_watcher; |
443 | 450 |
444 ReceivedSyncMsgQueue* sync_msg_queue = sync_context()->received_sync_msgs(); | 451 ReceivedSyncMsgQueue* sync_msg_queue = context->received_sync_msgs(); |
445 DCHECK(sync_msg_queue != NULL); | 452 DCHECK(sync_msg_queue != NULL); |
446 | 453 |
447 base::WaitableEventWatcher* old_send_done_event_watcher = | 454 base::WaitableEventWatcher* old_send_done_event_watcher = |
448 sync_msg_queue->top_send_done_watcher(); | 455 sync_msg_queue->top_send_done_watcher(); |
449 | 456 |
450 base::WaitableEventWatcher::Delegate* old_delegate = NULL; | 457 base::WaitableEventWatcher::Delegate* old_delegate = NULL; |
451 base::WaitableEvent* old_event = NULL; | 458 base::WaitableEvent* old_event = NULL; |
452 | 459 |
453 // Maintain a local global stack of send done delegates to ensure that | 460 // Maintain a local global stack of send done delegates to ensure that |
454 // nested sync calls complete in the correct sequence, i.e. the | 461 // nested sync calls complete in the correct sequence, i.e. the |
455 // outermost call completes first, etc. | 462 // outermost call completes first, etc. |
456 if (old_send_done_event_watcher) { | 463 if (old_send_done_event_watcher) { |
457 old_delegate = old_send_done_event_watcher->delegate(); | 464 old_delegate = old_send_done_event_watcher->delegate(); |
458 old_event = old_send_done_event_watcher->GetWatchedEvent(); | 465 old_event = old_send_done_event_watcher->GetWatchedEvent(); |
459 old_send_done_event_watcher->StopWatching(); | 466 old_send_done_event_watcher->StopWatching(); |
460 } | 467 } |
461 | 468 |
462 sync_msg_queue->set_top_send_done_watcher(&send_done_watcher); | 469 sync_msg_queue->set_top_send_done_watcher(&send_done_watcher); |
463 | 470 |
464 send_done_watcher.StartWatching(sync_context()->GetSendDoneEvent(), this); | 471 send_done_watcher.StartWatching(context->GetSendDoneEvent(), context); |
465 bool old_state = MessageLoop::current()->NestableTasksAllowed(); | 472 bool old_state = MessageLoop::current()->NestableTasksAllowed(); |
466 | 473 |
467 MessageLoop::current()->SetNestableTasksAllowed(true); | 474 MessageLoop::current()->SetNestableTasksAllowed(true); |
468 MessageLoop::current()->Run(); | 475 MessageLoop::current()->Run(); |
469 MessageLoop::current()->SetNestableTasksAllowed(old_state); | 476 MessageLoop::current()->SetNestableTasksAllowed(old_state); |
470 | 477 |
471 sync_msg_queue->set_top_send_done_watcher(old_send_done_event_watcher); | 478 sync_msg_queue->set_top_send_done_watcher(old_send_done_event_watcher); |
472 if (old_send_done_event_watcher && old_event) { | 479 if (old_send_done_event_watcher && old_event) { |
473 old_send_done_event_watcher->StartWatching(old_event, old_delegate); | 480 old_send_done_event_watcher->StartWatching(old_event, old_delegate); |
474 } | 481 } |
475 } | 482 } |
476 | 483 |
477 void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) { | 484 void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) { |
478 WaitableEvent* dispatch_event = sync_context()->GetDispatchEvent(); | 485 DCHECK(event == sync_context()->GetDispatchEvent()); |
479 if (event == dispatch_event) { | 486 // The call to DispatchMessages might delete this object, so reregister |
480 // The call to DispatchMessages might delete this object, so reregister | 487 // the object watcher first. |
481 // the object watcher first. | 488 event->Reset(); |
482 dispatch_event->Reset(); | 489 dispatch_watcher_.StartWatching(event, this); |
483 dispatch_watcher_.StartWatching(dispatch_event, this); | 490 sync_context()->DispatchMessages(); |
484 sync_context()->DispatchMessages(); | |
485 } else { | |
486 // We got the reply, timed out or the process shutdown. | |
487 DCHECK(event == sync_context()->GetSendDoneEvent()); | |
488 MessageLoop::current()->Quit(); | |
489 } | |
490 } | 491 } |
491 | 492 |
492 } // namespace IPC | 493 } // namespace IPC |
OLD | NEW |