| 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 | 
|---|