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