Index: ipc/ipc_sync_channel.cc |
=================================================================== |
--- ipc/ipc_sync_channel.cc (revision 28676) |
+++ ipc/ipc_sync_channel.cc (working copy) |
@@ -148,6 +148,14 @@ |
} |
} |
+ base::WaitableEventWatcher* top_send_done_watcher() { |
+ return top_send_done_watcher_; |
+ } |
+ |
+ void set_top_send_done_watcher(base::WaitableEventWatcher* watcher) { |
+ top_send_done_watcher_ = watcher; |
+ } |
+ |
private: |
// See the comment in SyncChannel::SyncChannel for why this event is created |
// as manual reset. |
@@ -155,7 +163,8 @@ |
dispatch_event_(true, false), |
listener_message_loop_(MessageLoop::current()), |
task_pending_(false), |
- listener_count_(0) { |
+ listener_count_(0), |
+ top_send_done_watcher_(NULL) { |
} |
// Holds information about a queued synchronous message or reply. |
@@ -178,6 +187,11 @@ |
Lock message_lock_; |
bool task_pending_; |
int listener_count_; |
+ |
+ // The current send done event watcher for this thread. Used to maintain |
+ // a local global stack of send done watchers to ensure that nested sync |
+ // message loops complete correctly. |
+ base::WaitableEventWatcher* top_send_done_watcher_; |
}; |
base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> > |
@@ -424,15 +438,39 @@ |
} |
void SyncChannel::WaitForReplyWithNestedMessageLoop() { |
- WaitableEvent* old_done_event = send_done_watcher_.GetWatchedEvent(); |
- send_done_watcher_.StopWatching(); |
- send_done_watcher_.StartWatching(sync_context()->GetSendDoneEvent(), this); |
+ base::WaitableEventWatcher send_done_watcher; |
+ |
+ ReceivedSyncMsgQueue* sync_msg_queue = sync_context()->received_sync_msgs(); |
+ DCHECK(sync_msg_queue != NULL); |
+ |
+ base::WaitableEventWatcher* old_send_done_event_watcher = |
+ sync_msg_queue->top_send_done_watcher(); |
+ |
+ base::WaitableEventWatcher::Delegate* old_delegate = NULL; |
+ base::WaitableEvent* old_event = NULL; |
+ |
+ // Maintain a local global stack of send done delegates to ensure that |
+ // nested sync calls complete in the correct sequence, i.e. the |
+ // outermost call completes first, etc. |
+ if (old_send_done_event_watcher) { |
+ old_delegate = old_send_done_event_watcher->delegate(); |
+ old_event = old_send_done_event_watcher->GetWatchedEvent(); |
+ old_send_done_event_watcher->StopWatching(); |
+ } |
+ |
+ sync_msg_queue->set_top_send_done_watcher(&send_done_watcher); |
+ |
+ send_done_watcher.StartWatching(sync_context()->GetSendDoneEvent(), this); |
bool old_state = MessageLoop::current()->NestableTasksAllowed(); |
+ |
MessageLoop::current()->SetNestableTasksAllowed(true); |
MessageLoop::current()->Run(); |
MessageLoop::current()->SetNestableTasksAllowed(old_state); |
- if (old_done_event) |
- send_done_watcher_.StartWatching(old_done_event, this); |
+ |
+ sync_msg_queue->set_top_send_done_watcher(old_send_done_event_watcher); |
+ if (old_send_done_event_watcher) { |
+ old_send_done_event_watcher->StartWatching(old_event, old_delegate); |
+ } |
} |
void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) { |