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 <windows.h> | 5 #include <windows.h> |
6 | 6 |
7 #include "chrome/common/ipc_sync_channel.h" | 7 #include "chrome/common/ipc_sync_channel.h" |
8 | 8 |
| 9 #include "base/lazy_instance.h" |
9 #include "base/logging.h" | 10 #include "base/logging.h" |
10 #include "base/thread_local_storage.h" | 11 #include "base/thread_local.h" |
11 #include "chrome/common/child_process.h" | 12 #include "chrome/common/child_process.h" |
12 #include "chrome/common/ipc_logging.h" | 13 #include "chrome/common/ipc_logging.h" |
13 #include "chrome/common/ipc_sync_message.h" | 14 #include "chrome/common/ipc_sync_message.h" |
14 | 15 |
15 | 16 |
16 namespace IPC { | 17 namespace IPC { |
17 // When we're blocked in a Send(), we need to process incoming synchronous | 18 // When we're blocked in a Send(), we need to process incoming synchronous |
18 // messages right away because it could be blocking our reply (either | 19 // messages right away because it could be blocking our reply (either |
19 // directly from the same object we're calling, or indirectly through one or | 20 // directly from the same object we're calling, or indirectly through one or |
20 // more other channels). That means that in SyncContext's OnMessageReceived, | 21 // more other channels). That means that in SyncContext's OnMessageReceived, |
21 // we need to process sync message right away if we're blocked. However a | 22 // we need to process sync message right away if we're blocked. However a |
22 // simple check isn't sufficient, because the listener thread can be in the | 23 // simple check isn't sufficient, because the listener thread can be in the |
23 // process of calling Send. | 24 // process of calling Send. |
24 // To work around this, when SyncChannel filters a sync message, it sets | 25 // To work around this, when SyncChannel filters a sync message, it sets |
25 // an event that the listener thread waits on during its Send() call. This | 26 // an event that the listener thread waits on during its Send() call. This |
26 // allows us to dispatch incoming sync messages when blocked. The race | 27 // allows us to dispatch incoming sync messages when blocked. The race |
27 // condition is handled because if Send is in the process of being called, it | 28 // condition is handled because if Send is in the process of being called, it |
28 // will check the event. In case the listener thread isn't sending a message, | 29 // will check the event. In case the listener thread isn't sending a message, |
29 // we queue a task on the listener thread to dispatch the received messages. | 30 // we queue a task on the listener thread to dispatch the received messages. |
30 // The messages are stored in this queue object that's shared among all | 31 // The messages are stored in this queue object that's shared among all |
31 // SyncChannel objects on the same thread (since one object can receive a | 32 // SyncChannel objects on the same thread (since one object can receive a |
32 // sync message while another one is blocked). | 33 // sync message while another one is blocked). |
33 | 34 |
34 // Holds a pointer to the per-thread ReceivedSyncMsgQueue object. | 35 class SyncChannel::ReceivedSyncMsgQueue; |
35 // TODO(evanm): this shouldn't rely on static initialization. | |
36 static TLSSlot g_tls_index; | |
37 | 36 |
38 class SyncChannel::ReceivedSyncMsgQueue : | 37 class SyncChannel::ReceivedSyncMsgQueue : |
39 public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> { | 38 public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> { |
40 public: | 39 public: |
41 ReceivedSyncMsgQueue() : | 40 ReceivedSyncMsgQueue() : |
42 blocking_event_(CreateEvent(NULL, FALSE, FALSE, NULL)), | 41 blocking_event_(CreateEvent(NULL, FALSE, FALSE, NULL)), |
43 task_pending_(false), | 42 task_pending_(false), |
44 listener_message_loop_(MessageLoop::current()) { | 43 listener_message_loop_(MessageLoop::current()) { |
45 } | 44 } |
46 | 45 |
47 ~ReceivedSyncMsgQueue() { | 46 ~ReceivedSyncMsgQueue() { |
48 DCHECK(g_tls_index.Get()); | 47 DCHECK(lazy_tls_ptr_.Pointer()->Get()); |
49 DCHECK(MessageLoop::current() == listener_message_loop_); | 48 DCHECK(MessageLoop::current() == listener_message_loop_); |
50 CloseHandle(blocking_event_); | 49 CloseHandle(blocking_event_); |
51 g_tls_index.Set(NULL); | 50 lazy_tls_ptr_.Pointer()->Set(NULL); |
52 } | 51 } |
53 | 52 |
54 // Called on IPC thread when a synchronous message or reply arrives. | 53 // Called on IPC thread when a synchronous message or reply arrives. |
55 void QueueMessage(const Message& msg, Channel::Listener* listener, | 54 void QueueMessage(const Message& msg, Channel::Listener* listener, |
56 const std::wstring& channel_id) { | 55 const std::wstring& channel_id) { |
57 bool was_task_pending; | 56 bool was_task_pending; |
58 { | 57 { |
59 AutoLock auto_lock(message_lock_); | 58 AutoLock auto_lock(message_lock_); |
60 | 59 |
61 was_task_pending = task_pending_; | 60 was_task_pending = task_pending_; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 | 147 |
149 while (!temp_queue.empty()) { | 148 while (!temp_queue.empty()) { |
150 message_queue_.push(temp_queue.front()); | 149 message_queue_.push(temp_queue.front()); |
151 temp_queue.pop(); | 150 temp_queue.pop(); |
152 } | 151 } |
153 } | 152 } |
154 | 153 |
155 HANDLE blocking_event() { return blocking_event_; } | 154 HANDLE blocking_event() { return blocking_event_; } |
156 MessageLoop* listener_message_loop() { return listener_message_loop_; } | 155 MessageLoop* listener_message_loop() { return listener_message_loop_; } |
157 | 156 |
| 157 // Holds a pointer to the per-thread ReceivedSyncMsgQueue object. |
| 158 static base::LazyInstance<base::ThreadLocalPointer<ReceivedSyncMsgQueue> > |
| 159 lazy_tls_ptr_; |
| 160 |
158 private: | 161 private: |
159 // Called on the ipc thread to check if we can unblock any current Send() | 162 // Called on the ipc thread to check if we can unblock any current Send() |
160 // calls based on a queued reply. | 163 // calls based on a queued reply. |
161 void DispatchReplies() { | 164 void DispatchReplies() { |
162 for (size_t i = 0; i < received_replies_.size(); ++i) { | 165 for (size_t i = 0; i < received_replies_.size(); ++i) { |
163 Message* message = received_replies_[i].message; | 166 Message* message = received_replies_[i].message; |
164 if (received_replies_[i].context->UnblockListener(message)) { | 167 if (received_replies_[i].context->UnblockListener(message)) { |
165 delete message; | 168 delete message; |
166 received_replies_.erase(received_replies_.begin() + i); | 169 received_replies_.erase(received_replies_.begin() + i); |
167 return; | 170 return; |
(...skipping 28 matching lines...) Expand all Loading... |
196 : message(m), | 199 : message(m), |
197 context(c) { } | 200 context(c) { } |
198 | 201 |
199 Message* message; | 202 Message* message; |
200 scoped_refptr<SyncChannel::SyncContext> context; | 203 scoped_refptr<SyncChannel::SyncContext> context; |
201 }; | 204 }; |
202 | 205 |
203 std::vector<Reply> received_replies_; | 206 std::vector<Reply> received_replies_; |
204 }; | 207 }; |
205 | 208 |
| 209 base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> > |
| 210 SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_(base::LINKER_INITIALIZED); |
206 | 211 |
207 SyncChannel::SyncContext::SyncContext( | 212 SyncChannel::SyncContext::SyncContext( |
208 Channel::Listener* listener, | 213 Channel::Listener* listener, |
209 MessageFilter* filter, | 214 MessageFilter* filter, |
210 MessageLoop* ipc_thread) | 215 MessageLoop* ipc_thread) |
211 : ChannelProxy::Context(listener, filter, ipc_thread), | 216 : ChannelProxy::Context(listener, filter, ipc_thread), |
212 channel_closed_(false), | 217 channel_closed_(false), |
213 reply_deserialize_result_(false) { | 218 reply_deserialize_result_(false) { |
214 // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple | 219 // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple |
215 // SyncChannel objects that can block the same thread). | 220 // SyncChannel objects that can block the same thread). |
216 received_sync_msgs_ = static_cast<ReceivedSyncMsgQueue*>(g_tls_index.Get()); | 221 received_sync_msgs_ = ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Get(); |
217 | 222 |
218 if (!received_sync_msgs_) { | 223 if (!received_sync_msgs_) { |
219 // Stash a pointer to the listener thread's ReceivedSyncMsgQueue, as we | 224 // Stash a pointer to the listener thread's ReceivedSyncMsgQueue, as we |
220 // need to be able to access it in the IPC thread. | 225 // need to be able to access it in the IPC thread. |
221 received_sync_msgs_ = new ReceivedSyncMsgQueue(); | 226 received_sync_msgs_ = new ReceivedSyncMsgQueue(); |
222 g_tls_index.Set(received_sync_msgs_); | 227 ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Set(received_sync_msgs_); |
223 } | 228 } |
224 | 229 |
225 // Addref manually so that we can ensure destruction on the listener thread | 230 // Addref manually so that we can ensure destruction on the listener thread |
226 // (so that the TLS object is NULLd). | 231 // (so that the TLS object is NULLd). |
227 received_sync_msgs_->AddRef(); | 232 received_sync_msgs_->AddRef(); |
228 } | 233 } |
229 | 234 |
230 SyncChannel::SyncContext::~SyncContext() { | 235 SyncChannel::SyncContext::~SyncContext() { |
231 while (!deserializers_.empty()) | 236 while (!deserializers_.empty()) |
232 PopDeserializer(true); | 237 PopDeserializer(true); |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 // or we time-out. | 477 // or we time-out. |
473 } while (true); | 478 } while (true); |
474 } | 479 } |
475 | 480 |
476 bool SyncChannel::UnblockListener(Message* message) { | 481 bool SyncChannel::UnblockListener(Message* message) { |
477 return sync_context()->UnblockListener(message); | 482 return sync_context()->UnblockListener(message); |
478 } | 483 } |
479 | 484 |
480 } // namespace IPC | 485 } // namespace IPC |
481 | 486 |
OLD | NEW |