Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(357)

Side by Side Diff: ipc/ipc_sync_channel.cc

Issue 271033: Multiple sync channels if used in the same listener thread could result in ca... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ipc/ipc_sync_channel.h ('k') | ipc/ipc_sync_channel_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 for (size_t i = 0; i < received_replies_.size(); ++i) { 141 for (size_t i = 0; i < received_replies_.size(); ++i) {
142 Message* message = received_replies_[i].message; 142 Message* message = received_replies_[i].message;
143 if (received_replies_[i].context->TryToUnblockListener(message)) { 143 if (received_replies_[i].context->TryToUnblockListener(message)) {
144 delete message; 144 delete message;
145 received_replies_.erase(received_replies_.begin() + i); 145 received_replies_.erase(received_replies_.begin() + i);
146 return; 146 return;
147 } 147 }
148 } 148 }
149 } 149 }
150 150
151 base::WaitableEventWatcher* top_send_done_watcher() {
152 return top_send_done_watcher_;
153 }
154
155 void set_top_send_done_watcher(base::WaitableEventWatcher* watcher) {
156 top_send_done_watcher_ = watcher;
157 }
158
151 private: 159 private:
152 // See the comment in SyncChannel::SyncChannel for why this event is created 160 // See the comment in SyncChannel::SyncChannel for why this event is created
153 // as manual reset. 161 // as manual reset.
154 ReceivedSyncMsgQueue() : 162 ReceivedSyncMsgQueue() :
155 dispatch_event_(true, false), 163 dispatch_event_(true, false),
156 listener_message_loop_(MessageLoop::current()), 164 listener_message_loop_(MessageLoop::current()),
157 task_pending_(false), 165 task_pending_(false),
158 listener_count_(0) { 166 listener_count_(0),
167 top_send_done_watcher_(NULL) {
159 } 168 }
160 169
161 // Holds information about a queued synchronous message or reply. 170 // Holds information about a queued synchronous message or reply.
162 struct QueuedMessage { 171 struct QueuedMessage {
163 QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { } 172 QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { }
164 Message* message; 173 Message* message;
165 scoped_refptr<SyncChannel::SyncContext> context; 174 scoped_refptr<SyncChannel::SyncContext> context;
166 }; 175 };
167 176
168 typedef std::deque<QueuedMessage> SyncMessageQueue; 177 typedef std::deque<QueuedMessage> SyncMessageQueue;
169 SyncMessageQueue message_queue_; 178 SyncMessageQueue message_queue_;
170 179
171 std::vector<QueuedMessage> received_replies_; 180 std::vector<QueuedMessage> received_replies_;
172 181
173 // Set when we got a synchronous message that we must respond to as the 182 // 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 183 // sender needs its reply before it can reply to our original synchronous
175 // message. 184 // message.
176 WaitableEvent dispatch_event_; 185 WaitableEvent dispatch_event_;
177 MessageLoop* listener_message_loop_; 186 MessageLoop* listener_message_loop_;
178 Lock message_lock_; 187 Lock message_lock_;
179 bool task_pending_; 188 bool task_pending_;
180 int listener_count_; 189 int listener_count_;
190
191 // The current send done event watcher for this thread. Used to maintain
192 // a local global stack of send done watchers to ensure that nested sync
193 // message loops complete correctly.
194 base::WaitableEventWatcher* top_send_done_watcher_;
181 }; 195 };
182 196
183 base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> > 197 base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> >
184 SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_(base::LINKER_INITIALIZED); 198 SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_(base::LINKER_INITIALIZED);
185 199
186 SyncChannel::SyncContext::SyncContext( 200 SyncChannel::SyncContext::SyncContext(
187 Channel::Listener* listener, 201 Channel::Listener* listener,
188 MessageFilter* filter, 202 MessageFilter* filter,
189 MessageLoop* ipc_thread, 203 MessageLoop* ipc_thread,
190 WaitableEvent* shutdown_event) 204 WaitableEvent* shutdown_event)
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 } 431 }
418 432
419 if (result == 2 /* pump_messages_event */) 433 if (result == 2 /* pump_messages_event */)
420 WaitForReplyWithNestedMessageLoop(); // Start a nested message loop. 434 WaitForReplyWithNestedMessageLoop(); // Start a nested message loop.
421 435
422 break; 436 break;
423 } 437 }
424 } 438 }
425 439
426 void SyncChannel::WaitForReplyWithNestedMessageLoop() { 440 void SyncChannel::WaitForReplyWithNestedMessageLoop() {
427 WaitableEvent* old_done_event = send_done_watcher_.GetWatchedEvent(); 441 base::WaitableEventWatcher send_done_watcher;
428 send_done_watcher_.StopWatching(); 442
429 send_done_watcher_.StartWatching(sync_context()->GetSendDoneEvent(), this); 443 ReceivedSyncMsgQueue* sync_msg_queue = sync_context()->received_sync_msgs();
444 DCHECK(sync_msg_queue != NULL);
445
446 base::WaitableEventWatcher* old_send_done_event_watcher =
447 sync_msg_queue->top_send_done_watcher();
448
449 base::WaitableEventWatcher::Delegate* old_delegate = NULL;
450 base::WaitableEvent* old_event = NULL;
451
452 // Maintain a local global stack of send done delegates to ensure that
453 // nested sync calls complete in the correct sequence, i.e. the
454 // outermost call completes first, etc.
455 if (old_send_done_event_watcher) {
456 old_delegate = old_send_done_event_watcher->delegate();
457 old_event = old_send_done_event_watcher->GetWatchedEvent();
458 old_send_done_event_watcher->StopWatching();
459 }
460
461 sync_msg_queue->set_top_send_done_watcher(&send_done_watcher);
462
463 send_done_watcher.StartWatching(sync_context()->GetSendDoneEvent(), this);
430 bool old_state = MessageLoop::current()->NestableTasksAllowed(); 464 bool old_state = MessageLoop::current()->NestableTasksAllowed();
465
431 MessageLoop::current()->SetNestableTasksAllowed(true); 466 MessageLoop::current()->SetNestableTasksAllowed(true);
432 MessageLoop::current()->Run(); 467 MessageLoop::current()->Run();
433 MessageLoop::current()->SetNestableTasksAllowed(old_state); 468 MessageLoop::current()->SetNestableTasksAllowed(old_state);
434 if (old_done_event) 469
435 send_done_watcher_.StartWatching(old_done_event, this); 470 sync_msg_queue->set_top_send_done_watcher(old_send_done_event_watcher);
471 if (old_send_done_event_watcher) {
472 old_send_done_event_watcher->StartWatching(old_event, old_delegate);
473 }
436 } 474 }
437 475
438 void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) { 476 void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) {
439 WaitableEvent* dispatch_event = sync_context()->GetDispatchEvent(); 477 WaitableEvent* dispatch_event = sync_context()->GetDispatchEvent();
440 if (event == dispatch_event) { 478 if (event == dispatch_event) {
441 // The call to DispatchMessages might delete this object, so reregister 479 // The call to DispatchMessages might delete this object, so reregister
442 // the object watcher first. 480 // the object watcher first.
443 dispatch_event->Reset(); 481 dispatch_event->Reset();
444 dispatch_watcher_.StartWatching(dispatch_event, this); 482 dispatch_watcher_.StartWatching(dispatch_event, this);
445 sync_context()->DispatchMessages(); 483 sync_context()->DispatchMessages();
446 } else { 484 } else {
447 // We got the reply, timed out or the process shutdown. 485 // We got the reply, timed out or the process shutdown.
448 DCHECK(event == sync_context()->GetSendDoneEvent()); 486 DCHECK(event == sync_context()->GetSendDoneEvent());
449 MessageLoop::current()->Quit(); 487 MessageLoop::current()->Quit();
450 } 488 }
451 } 489 }
452 490
453 } // namespace IPC 491 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/ipc_sync_channel.h ('k') | ipc/ipc_sync_channel_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698