Chromium Code Reviews| 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 "base/message_loop.h" | 5 #include "base/message_loop.h" |
| 6 #include "base/ref_counted.h" | 6 #include "base/ref_counted.h" |
| 7 #include "base/scoped_ptr.h" | 7 #include "base/scoped_ptr.h" |
| 8 #include "base/thread.h" | 8 #include "base/thread.h" |
| 9 #include "ipc/ipc_channel_proxy.h" | 9 #include "ipc/ipc_channel_proxy.h" |
| 10 #include "ipc/ipc_logging.h" | 10 #include "ipc/ipc_logging.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 54 return false; | 54 return false; |
| 55 } | 55 } |
| 56 | 56 |
| 57 void ChannelProxy::MessageFilter::OnDestruct() const { | 57 void ChannelProxy::MessageFilter::OnDestruct() const { |
| 58 delete this; | 58 delete this; |
| 59 } | 59 } |
| 60 | 60 |
| 61 //------------------------------------------------------------------------------ | 61 //------------------------------------------------------------------------------ |
| 62 | 62 |
| 63 ChannelProxy::Context::Context(Channel::Listener* listener, | 63 ChannelProxy::Context::Context(Channel::Listener* listener, |
| 64 MessageFilter* filter, | |
| 65 MessageLoop* ipc_message_loop) | 64 MessageLoop* ipc_message_loop) |
| 66 : listener_message_loop_(MessageLoop::current()), | 65 : listener_message_loop_(MessageLoop::current()), |
| 67 listener_(listener), | 66 listener_(listener), |
| 68 ipc_message_loop_(ipc_message_loop), | 67 ipc_message_loop_(ipc_message_loop), |
| 69 channel_(NULL), | 68 channel_(NULL), |
| 70 peer_pid_(0), | 69 peer_pid_(0), |
| 71 channel_connected_called_(false) { | 70 channel_connected_called_(false) { |
| 72 if (filter) | |
| 73 filters_.push_back(make_scoped_refptr(filter)); | |
| 74 } | 71 } |
| 75 | 72 |
| 76 void ChannelProxy::Context::CreateChannel(const std::string& id, | 73 void ChannelProxy::Context::CreateChannel(const std::string& id, |
| 77 const Channel::Mode& mode) { | 74 const Channel::Mode& mode) { |
| 78 DCHECK(channel_ == NULL); | 75 DCHECK(channel_ == NULL); |
| 79 channel_id_ = id; | 76 channel_id_ = id; |
| 80 channel_ = new Channel(id, mode, this); | 77 channel_ = new Channel(id, mode, this); |
| 81 } | 78 } |
| 82 | 79 |
| 83 bool ChannelProxy::Context::TryFilters(const Message& message) { | 80 bool ChannelProxy::Context::TryFilters(const Message& message) { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 111 // NOTE: This code relies on the listener's message loop not going away while | 108 // NOTE: This code relies on the listener's message loop not going away while |
| 112 // this thread is active. That should be a reasonable assumption, but it | 109 // this thread is active. That should be a reasonable assumption, but it |
| 113 // feels risky. We may want to invent some more indirect way of referring to | 110 // feels risky. We may want to invent some more indirect way of referring to |
| 114 // a MessageLoop if this becomes a problem. | 111 // a MessageLoop if this becomes a problem. |
| 115 listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 112 listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 116 this, &Context::OnDispatchMessage, message)); | 113 this, &Context::OnDispatchMessage, message)); |
| 117 } | 114 } |
| 118 | 115 |
| 119 // Called on the IPC::Channel thread | 116 // Called on the IPC::Channel thread |
| 120 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) { | 117 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) { |
| 118 // Add any pending filters. This avoids a race condition where someone | |
| 119 // creates a ChannelProxy, calls AddFilter, and then right after starts the | |
| 120 // peer process. The IO thread could receive a message before the task to add | |
| 121 // the filter is run on the IO thread. | |
| 122 OnAddFilter(); | |
| 123 | |
| 121 peer_pid_ = peer_pid; | 124 peer_pid_ = peer_pid; |
| 122 for (size_t i = 0; i < filters_.size(); ++i) | 125 for (size_t i = 0; i < filters_.size(); ++i) |
| 123 filters_[i]->OnChannelConnected(peer_pid); | 126 filters_[i]->OnChannelConnected(peer_pid); |
| 124 | 127 |
| 125 // See above comment about using listener_message_loop_ here. | 128 // See above comment about using listener_message_loop_ here. |
| 126 listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( | 129 listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
| 127 this, &Context::OnDispatchConnected)); | 130 this, &Context::OnDispatchConnected)); |
| 128 } | 131 } |
| 129 | 132 |
| 130 // Called on the IPC::Channel thread | 133 // Called on the IPC::Channel thread |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 if (!channel_) { | 185 if (!channel_) { |
| 183 delete message; | 186 delete message; |
| 184 OnChannelClosed(); | 187 OnChannelClosed(); |
| 185 return; | 188 return; |
| 186 } | 189 } |
| 187 if (!channel_->Send(message)) | 190 if (!channel_->Send(message)) |
| 188 OnChannelError(); | 191 OnChannelError(); |
| 189 } | 192 } |
| 190 | 193 |
| 191 // Called on the IPC::Channel thread | 194 // Called on the IPC::Channel thread |
| 192 void ChannelProxy::Context::OnAddFilter(MessageFilter* filter) { | 195 void ChannelProxy::Context::OnAddFilter() { |
| 193 filters_.push_back(make_scoped_refptr(filter)); | 196 std::vector<scoped_refptr<MessageFilter> > filters; |
| 197 { | |
| 198 AutoLock auto_lock(pending_filters_lock_); | |
| 199 filters.swap(pending_filters_); | |
| 200 } | |
| 194 | 201 |
| 195 // If the channel has already been created, then we need to send this message | 202 for (size_t i = 0; i < filters.size(); ++i) { |
| 196 // so that the filter gets access to the Channel. | 203 filters_.push_back(filters[i]); |
| 197 if (channel_) | 204 |
| 198 filter->OnFilterAdded(channel_); | 205 // If the channel has already been created, then we need to send this |
| 206 // message so that the filter gets access to the Channel. | |
| 207 if (channel_) | |
| 208 filters[i]->OnFilterAdded(channel_); | |
| 209 // Ditto for the peer process id. | |
| 210 if (peer_pid_) | |
| 211 filters[i]->OnChannelConnected(peer_pid_); | |
| 212 } | |
| 199 } | 213 } |
| 200 | 214 |
| 201 // Called on the IPC::Channel thread | 215 // Called on the IPC::Channel thread |
| 202 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) { | 216 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) { |
| 203 for (size_t i = 0; i < filters_.size(); ++i) { | 217 for (size_t i = 0; i < filters_.size(); ++i) { |
| 204 if (filters_[i].get() == filter) { | 218 if (filters_[i].get() == filter) { |
| 205 filter->OnFilterRemoved(); | 219 filter->OnFilterRemoved(); |
| 206 filters_.erase(filters_.begin() + i); | 220 filters_.erase(filters_.begin() + i); |
| 207 return; | 221 return; |
| 208 } | 222 } |
| 209 } | 223 } |
| 210 | 224 |
| 211 NOTREACHED() << "filter to be removed not found"; | 225 NOTREACHED() << "filter to be removed not found"; |
| 212 } | 226 } |
| 213 | 227 |
| 214 // Called on the listener's thread | 228 // Called on the listener's thread |
| 229 void ChannelProxy::Context::AddFilter(MessageFilter* filter) { | |
| 230 AutoLock auto_lock(pending_filters_lock_); | |
| 231 pending_filters_.push_back(make_scoped_refptr(filter)); | |
| 232 ipc_message_loop_->PostTask( | |
| 233 FROM_HERE, | |
| 234 NewRunnableMethod(this, &Context::OnAddFilter)); | |
| 235 } | |
| 236 | |
| 237 // Called on the listener's thread | |
| 215 void ChannelProxy::Context::OnDispatchMessage(const Message& message) { | 238 void ChannelProxy::Context::OnDispatchMessage(const Message& message) { |
| 216 if (!listener_) | 239 if (!listener_) |
| 217 return; | 240 return; |
| 218 | 241 |
| 219 OnDispatchConnected(); | 242 OnDispatchConnected(); |
| 220 | 243 |
| 221 #ifdef IPC_MESSAGE_LOG_ENABLED | 244 #ifdef IPC_MESSAGE_LOG_ENABLED |
| 222 Logging* logger = Logging::current(); | 245 Logging* logger = Logging::current(); |
| 223 if (message.type() == IPC_LOGGING_ID) { | 246 if (message.type() == IPC_LOGGING_ID) { |
| 224 logger->OnReceivedLoggingMessage(message); | 247 logger->OnReceivedLoggingMessage(message); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 248 } | 271 } |
| 249 | 272 |
| 250 // Called on the listener's thread | 273 // Called on the listener's thread |
| 251 void ChannelProxy::Context::OnDispatchError() { | 274 void ChannelProxy::Context::OnDispatchError() { |
| 252 if (listener_) | 275 if (listener_) |
| 253 listener_->OnChannelError(); | 276 listener_->OnChannelError(); |
| 254 } | 277 } |
| 255 | 278 |
| 256 //----------------------------------------------------------------------------- | 279 //----------------------------------------------------------------------------- |
| 257 | 280 |
| 258 ChannelProxy::ChannelProxy(const std::string& channel_id, Channel::Mode mode, | 281 ChannelProxy::ChannelProxy(const std::string& channel_id, |
| 259 Channel::Listener* listener, MessageFilter* filter, | 282 Channel::Mode mode, |
| 283 Channel::Listener* listener, | |
| 260 MessageLoop* ipc_thread) | 284 MessageLoop* ipc_thread) |
| 261 : context_(new Context(listener, filter, ipc_thread)) { | 285 : context_(new Context(listener, ipc_thread)) { |
| 262 Init(channel_id, mode, ipc_thread, true); | 286 Init(channel_id, mode, ipc_thread, true); |
| 263 } | 287 } |
| 264 | 288 |
| 265 ChannelProxy::ChannelProxy(const std::string& channel_id, Channel::Mode mode, | 289 ChannelProxy::ChannelProxy(const std::string& channel_id, |
| 266 MessageLoop* ipc_thread, Context* context, | 290 Channel::Mode mode, |
| 291 MessageLoop* ipc_thread, | |
| 292 Context* context, | |
| 267 bool create_pipe_now) | 293 bool create_pipe_now) |
| 268 : context_(context) { | 294 : context_(context) { |
| 269 Init(channel_id, mode, ipc_thread, create_pipe_now); | 295 Init(channel_id, mode, ipc_thread, create_pipe_now); |
| 270 } | 296 } |
| 271 | 297 |
| 272 ChannelProxy::~ChannelProxy() { | 298 ChannelProxy::~ChannelProxy() { |
| 273 Close(); | 299 Close(); |
| 274 } | 300 } |
| 275 | 301 |
| 276 void ChannelProxy::Init(const std::string& channel_id, Channel::Mode mode, | 302 void ChannelProxy::Init(const std::string& channel_id, Channel::Mode mode, |
| 277 MessageLoop* ipc_thread_loop, bool create_pipe_now) { | 303 MessageLoop* ipc_thread_loop, bool create_pipe_now) { |
| 278 if (create_pipe_now) { | 304 if (create_pipe_now) { |
| 279 // Create the channel immediately. This effectively sets up the | 305 // Create the channel immediately. This effectively sets up the |
| 280 // low-level pipe so that the client can connect. Without creating | 306 // low-level pipe so that the client can connect. Without creating |
| 281 // the pipe immediately, it is possible for a listener to attempt | 307 // the pipe immediately, it is possible for a listener to attempt |
| 282 // to connect and get an error since the pipe doesn't exist yet. | 308 // to connect and get an error since the pipe doesn't exist yet. |
| 283 context_->CreateChannel(channel_id, mode); | 309 context_->CreateChannel(channel_id, mode); |
| 284 } else { | 310 } else { |
| 285 context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( | 311 context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 286 context_.get(), &Context::CreateChannel, channel_id, mode)); | 312 context_.get(), &Context::CreateChannel, channel_id, mode)); |
| 287 } | 313 } |
| 288 | 314 |
| 289 // complete initialization on the background thread | 315 // complete initialization on the background thread |
| 290 context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( | 316 context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 291 context_.get(), &Context::OnChannelOpened)); | 317 context_.get(), &Context::OnChannelOpened)); |
|
Matt Perry
2010/12/02 19:00:39
Couldn't this cause OnChannelOpened to run, then O
jam
2010/12/02 19:08:53
That's fine, since OnAddFilter will call OnChannel
| |
| 292 } | 318 } |
| 293 | 319 |
| 294 void ChannelProxy::Close() { | 320 void ChannelProxy::Close() { |
| 295 // Clear the backpointer to the listener so that any pending calls to | 321 // Clear the backpointer to the listener so that any pending calls to |
| 296 // Context::OnDispatchMessage or OnDispatchError will be ignored. It is | 322 // Context::OnDispatchMessage or OnDispatchError will be ignored. It is |
| 297 // possible that the channel could be closed while it is receiving messages! | 323 // possible that the channel could be closed while it is receiving messages! |
| 298 context_->Clear(); | 324 context_->Clear(); |
| 299 | 325 |
| 300 if (context_->ipc_message_loop()) { | 326 if (context_->ipc_message_loop()) { |
| 301 context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( | 327 context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( |
| 302 context_.get(), &Context::OnChannelClosed)); | 328 context_.get(), &Context::OnChannelClosed)); |
| 303 } | 329 } |
| 304 } | 330 } |
| 305 | 331 |
| 306 bool ChannelProxy::Send(Message* message) { | 332 bool ChannelProxy::Send(Message* message) { |
| 307 #ifdef IPC_MESSAGE_LOG_ENABLED | 333 #ifdef IPC_MESSAGE_LOG_ENABLED |
| 308 Logging::current()->OnSendMessage(message, context_->channel_id()); | 334 Logging::current()->OnSendMessage(message, context_->channel_id()); |
| 309 #endif | 335 #endif |
| 310 | 336 |
| 311 context_->ipc_message_loop()->PostTask(FROM_HERE, | 337 context_->ipc_message_loop()->PostTask(FROM_HERE, |
| 312 new SendTask(context_.get(), message)); | 338 new SendTask(context_.get(), message)); |
| 313 return true; | 339 return true; |
| 314 } | 340 } |
| 315 | 341 |
| 316 void ChannelProxy::AddFilter(MessageFilter* filter) { | 342 void ChannelProxy::AddFilter(MessageFilter* filter) { |
| 317 context_->ipc_message_loop()->PostTask( | 343 context_->AddFilter(filter); |
| 318 FROM_HERE, | |
| 319 NewRunnableMethod( | |
| 320 context_.get(), | |
| 321 &Context::OnAddFilter, | |
| 322 make_scoped_refptr(filter))); | |
| 323 } | 344 } |
| 324 | 345 |
| 325 void ChannelProxy::RemoveFilter(MessageFilter* filter) { | 346 void ChannelProxy::RemoveFilter(MessageFilter* filter) { |
| 326 context_->ipc_message_loop()->PostTask( | 347 context_->ipc_message_loop()->PostTask( |
| 327 FROM_HERE, NewRunnableMethod( | 348 FROM_HERE, NewRunnableMethod( |
| 328 context_.get(), | 349 context_.get(), |
| 329 &Context::OnRemoveFilter, | 350 &Context::OnRemoveFilter, |
| 330 make_scoped_refptr(filter))); | 351 make_scoped_refptr(filter))); |
| 331 } | 352 } |
| 332 | 353 |
| 333 void ChannelProxy::ClearIPCMessageLoop() { | 354 void ChannelProxy::ClearIPCMessageLoop() { |
| 334 context()->ClearIPCMessageLoop(); | 355 context()->ClearIPCMessageLoop(); |
| 335 } | 356 } |
| 336 | 357 |
| 337 #if defined(OS_POSIX) && !defined(OS_NACL) | 358 #if defined(OS_POSIX) && !defined(OS_NACL) |
| 338 // See the TODO regarding lazy initialization of the channel in | 359 // See the TODO regarding lazy initialization of the channel in |
| 339 // ChannelProxy::Init(). | 360 // ChannelProxy::Init(). |
| 340 // We assume that IPC::Channel::GetClientFileDescriptorMapping() is thread-safe. | 361 // We assume that IPC::Channel::GetClientFileDescriptorMapping() is thread-safe. |
| 341 int ChannelProxy::GetClientFileDescriptor() const { | 362 int ChannelProxy::GetClientFileDescriptor() const { |
| 342 Channel *channel = context_.get()->channel_; | 363 Channel *channel = context_.get()->channel_; |
| 343 DCHECK(channel); // Channel must have been created first. | 364 DCHECK(channel); // Channel must have been created first. |
| 344 return channel->GetClientFileDescriptor(); | 365 return channel->GetClientFileDescriptor(); |
| 345 } | 366 } |
| 346 #endif | 367 #endif |
| 347 | 368 |
| 348 //----------------------------------------------------------------------------- | 369 //----------------------------------------------------------------------------- |
| 349 | 370 |
| 350 } // namespace IPC | 371 } // namespace IPC |
| OLD | NEW |