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

Side by Side Diff: ipc/ipc_sync_channel.cc

Issue 9022038: Reimplement ReceivedSyncMsgQueue::DispatchMessages (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Try to avoid rescanning entire queue. Added unittest Created 8 years, 11 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 | « no previous file | ipc/ipc_sync_channel_unittest.cc » ('j') | ipc/ipc_sync_channel_unittest.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/bind.h" 7 #include "base/bind.h"
8 #include "base/lazy_instance.h" 8 #include "base/lazy_instance.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 bool was_task_pending; 57 bool was_task_pending;
58 { 58 {
59 base::AutoLock auto_lock(message_lock_); 59 base::AutoLock auto_lock(message_lock_);
60 60
61 was_task_pending = task_pending_; 61 was_task_pending = task_pending_;
62 task_pending_ = true; 62 task_pending_ = true;
63 63
64 // We set the event in case the listener thread is blocked (or is about 64 // We set the event in case the listener thread is blocked (or is about
65 // to). In case it's not, the PostTask dispatches the messages. 65 // to). In case it's not, the PostTask dispatches the messages.
66 message_queue_.push_back(QueuedMessage(new Message(msg), context)); 66 message_queue_.push_back(QueuedMessage(new Message(msg), context));
67 message_queue_modified_ = true;
67 } 68 }
68 69
69 dispatch_event_.Signal(); 70 dispatch_event_.Signal();
70 if (!was_task_pending) { 71 if (!was_task_pending) {
71 listener_message_loop_->PostTask( 72 listener_message_loop_->PostTask(
72 FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchMessagesTask, 73 FROM_HERE, base::Bind(&ReceivedSyncMsgQueue::DispatchMessagesTask,
73 this, scoped_refptr<SyncContext>(context))); 74 this, scoped_refptr<SyncContext>(context)));
74 } 75 }
75 } 76 }
76 77
77 void QueueReply(const Message &msg, SyncChannel::SyncContext* context) { 78 void QueueReply(const Message &msg, SyncChannel::SyncContext* context) {
78 received_replies_.push_back(QueuedMessage(new Message(msg), context)); 79 received_replies_.push_back(QueuedMessage(new Message(msg), context));
79 } 80 }
80 81
81 // Called on the listener's thread to process any queues synchronous 82 // Called on the listener's thread to process any queues synchronous
82 // messages. 83 // messages.
83 void DispatchMessagesTask(SyncContext* context) { 84 void DispatchMessagesTask(SyncContext* context) {
84 { 85 {
85 base::AutoLock auto_lock(message_lock_); 86 base::AutoLock auto_lock(message_lock_);
86 task_pending_ = false; 87 task_pending_ = false;
87 } 88 }
88 context->DispatchMessages(); 89 context->DispatchMessages();
89 } 90 }
90 91
91 void DispatchMessages(SyncContext* dispatching_context) { 92 void DispatchMessages(SyncContext* dispatching_context) {
92 SyncMessageQueue delayed_queue; 93 bool first_time = true;
94 SyncMessageQueue::iterator it;
93 while (true) { 95 while (true) {
94 Message* message; 96 Message* message = NULL;
95 scoped_refptr<SyncChannel::SyncContext> context; 97 scoped_refptr<SyncChannel::SyncContext> context;
96 { 98 {
97 base::AutoLock auto_lock(message_lock_); 99 base::AutoLock auto_lock(message_lock_);
98 if (message_queue_.empty()) { 100 if (first_time || message_queue_modified_) {
99 message_queue_ = delayed_queue; 101 it = message_queue_.begin();
100 break; 102 first_time = false;
103 message_queue_modified_ = false;
piman 2012/01/10 04:33:17 In case of nested dispatches, I'm not sure we can
Josh Horwich 2012/01/10 20:30:25 Done. But in a different manner - now I maintain
101 } 104 }
105 for (; it != message_queue_.end(); it++) {
106 if (!it->context->restrict_dispatch() ||
107 it->context == dispatching_context) {
108 message = it->message;
109 context = it->context;
110 it = message_queue_.erase(it);
111 break;
112 }
113 }
114 }
102 115
103 message = message_queue_.front().message; 116 if (message == NULL)
104 context = message_queue_.front().context; 117 break;
105 message_queue_.pop_front(); 118 context->OnDispatchMessage(*message);
106 } 119 delete message;
107 if (context->restrict_dispatch() && context != dispatching_context) {
108 delayed_queue.push_back(QueuedMessage(message, context));
109 } else {
110 context->OnDispatchMessage(*message);
111 delete message;
112 }
113 } 120 }
114 } 121 }
115 122
116 // SyncChannel calls this in its destructor. 123 // SyncChannel calls this in its destructor.
117 void RemoveContext(SyncContext* context) { 124 void RemoveContext(SyncContext* context) {
118 base::AutoLock auto_lock(message_lock_); 125 base::AutoLock auto_lock(message_lock_);
119 126
120 SyncMessageQueue::iterator iter = message_queue_.begin(); 127 SyncMessageQueue::iterator iter = message_queue_.begin();
121 while (iter != message_queue_.end()) { 128 while (iter != message_queue_.end()) {
122 if (iter->context == context) { 129 if (iter->context == context) {
123 delete iter->message; 130 delete iter->message;
124 iter = message_queue_.erase(iter); 131 iter = message_queue_.erase(iter);
132 message_queue_modified_ = true;
125 } else { 133 } else {
126 iter++; 134 iter++;
127 } 135 }
128 } 136 }
129 137
130 if (--listener_count_ == 0) { 138 if (--listener_count_ == 0) {
131 DCHECK(lazy_tls_ptr_.Pointer()->Get()); 139 DCHECK(lazy_tls_ptr_.Pointer()->Get());
132 lazy_tls_ptr_.Pointer()->Set(NULL); 140 lazy_tls_ptr_.Pointer()->Set(NULL);
133 } 141 }
134 } 142 }
(...skipping 27 matching lines...) Expand all
162 void set_top_send_done_watcher(base::WaitableEventWatcher* watcher) { 170 void set_top_send_done_watcher(base::WaitableEventWatcher* watcher) {
163 top_send_done_watcher_ = watcher; 171 top_send_done_watcher_ = watcher;
164 } 172 }
165 173
166 private: 174 private:
167 friend class base::RefCountedThreadSafe<ReceivedSyncMsgQueue>; 175 friend class base::RefCountedThreadSafe<ReceivedSyncMsgQueue>;
168 176
169 // See the comment in SyncChannel::SyncChannel for why this event is created 177 // See the comment in SyncChannel::SyncChannel for why this event is created
170 // as manual reset. 178 // as manual reset.
171 ReceivedSyncMsgQueue() : 179 ReceivedSyncMsgQueue() :
180 message_queue_modified_(false),
172 dispatch_event_(true, false), 181 dispatch_event_(true, false),
173 listener_message_loop_(base::MessageLoopProxy::current()), 182 listener_message_loop_(base::MessageLoopProxy::current()),
174 task_pending_(false), 183 task_pending_(false),
175 listener_count_(0), 184 listener_count_(0),
176 top_send_done_watcher_(NULL) { 185 top_send_done_watcher_(NULL) {
177 } 186 }
178 187
179 ~ReceivedSyncMsgQueue() {} 188 ~ReceivedSyncMsgQueue() {}
180 189
181 // Holds information about a queued synchronous message or reply. 190 // Holds information about a queued synchronous message or reply.
182 struct QueuedMessage { 191 struct QueuedMessage {
183 QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { } 192 QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { }
184 Message* message; 193 Message* message;
185 scoped_refptr<SyncChannel::SyncContext> context; 194 scoped_refptr<SyncChannel::SyncContext> context;
186 }; 195 };
187 196
188 typedef std::deque<QueuedMessage> SyncMessageQueue; 197 typedef std::list<QueuedMessage> SyncMessageQueue;
189 SyncMessageQueue message_queue_; 198 SyncMessageQueue message_queue_;
199 bool message_queue_modified_; // Used to signal DispatchMessages to rescan
190 200
191 std::vector<QueuedMessage> received_replies_; 201 std::vector<QueuedMessage> received_replies_;
192 202
193 // Set when we got a synchronous message that we must respond to as the 203 // Set when we got a synchronous message that we must respond to as the
194 // sender needs its reply before it can reply to our original synchronous 204 // sender needs its reply before it can reply to our original synchronous
195 // message. 205 // message.
196 WaitableEvent dispatch_event_; 206 WaitableEvent dispatch_event_;
197 scoped_refptr<base::MessageLoopProxy> listener_message_loop_; 207 scoped_refptr<base::MessageLoopProxy> listener_message_loop_;
198 base::Lock message_lock_; 208 base::Lock message_lock_;
199 bool task_pending_; 209 bool task_pending_;
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 // Ideally we only want to watch this object when running a nested message 529 // Ideally we only want to watch this object when running a nested message
520 // loop. However, we don't know when it exits if there's another nested 530 // loop. However, we don't know when it exits if there's another nested
521 // message loop running under it or not, so we wouldn't know whether to 531 // message loop running under it or not, so we wouldn't know whether to
522 // stop or keep watching. So we always watch it, and create the event as 532 // stop or keep watching. So we always watch it, and create the event as
523 // manual reset since the object watcher might otherwise reset the event 533 // manual reset since the object watcher might otherwise reset the event
524 // when we're doing a WaitMany. 534 // when we're doing a WaitMany.
525 dispatch_watcher_.StartWatching(sync_context()->GetDispatchEvent(), this); 535 dispatch_watcher_.StartWatching(sync_context()->GetDispatchEvent(), this);
526 } 536 }
527 537
528 } // namespace IPC 538 } // namespace IPC
OLDNEW
« no previous file with comments | « no previous file | ipc/ipc_sync_channel_unittest.cc » ('j') | ipc/ipc_sync_channel_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698