| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "mojo/edk/system/channel.h" | 5 #include "mojo/edk/system/channel.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 is_running_ = false; | 65 is_running_ = false; |
| 66 | 66 |
| 67 // We need to deal with it outside the lock. | 67 // We need to deal with it outside the lock. |
| 68 std::swap(to_destroy, local_id_to_endpoint_map_); | 68 std::swap(to_destroy, local_id_to_endpoint_map_); |
| 69 } | 69 } |
| 70 | 70 |
| 71 size_t num_live = 0; | 71 size_t num_live = 0; |
| 72 size_t num_zombies = 0; | 72 size_t num_zombies = 0; |
| 73 for (IdToEndpointMap::iterator it = to_destroy.begin(); | 73 for (IdToEndpointMap::iterator it = to_destroy.begin(); |
| 74 it != to_destroy.end(); ++it) { | 74 it != to_destroy.end(); ++it) { |
| 75 if (it->second.get()) { | 75 if (it->second) { |
| 76 num_live++; | 76 num_live++; |
| 77 it->second->DetachFromChannel(); | 77 it->second->DetachFromChannel(); |
| 78 } else { | 78 } else { |
| 79 num_zombies++; | 79 num_zombies++; |
| 80 } | 80 } |
| 81 } | 81 } |
| 82 DVLOG_IF(2, num_live || num_zombies) << "Shut down Channel with " << num_live | 82 DVLOG_IF(2, num_live || num_zombies) << "Shut down Channel with " << num_live |
| 83 << " live endpoints and " << num_zombies | 83 << " live endpoints and " << num_zombies |
| 84 << " zombies"; | 84 << " zombies"; |
| 85 } | 85 } |
| 86 | 86 |
| 87 void Channel::WillShutdownSoon() { | 87 void Channel::WillShutdownSoon() { |
| 88 base::AutoLock locker(lock_); | 88 base::AutoLock locker(lock_); |
| 89 is_shutting_down_ = true; | 89 is_shutting_down_ = true; |
| 90 channel_manager_ = nullptr; | 90 channel_manager_ = nullptr; |
| 91 } | 91 } |
| 92 | 92 |
| 93 // Note: |endpoint| being a |scoped_refptr| makes this function safe, since it | 93 // Note: |endpoint| being a |scoped_refptr| makes this function safe, since it |
| 94 // keeps the endpoint alive even after the lock is released. Otherwise, there's | 94 // keeps the endpoint alive even after the lock is released. Otherwise, there's |
| 95 // the temptation to simply pass the result of |new ChannelEndpoint(...)| | 95 // the temptation to simply pass the result of |new ChannelEndpoint(...)| |
| 96 // directly to this function, which wouldn't be sufficient for safety. | 96 // directly to this function, which wouldn't be sufficient for safety. |
| 97 ChannelEndpointId Channel::AttachAndRunEndpoint( | 97 ChannelEndpointId Channel::AttachAndRunEndpoint( |
| 98 scoped_refptr<ChannelEndpoint> endpoint, | 98 scoped_refptr<ChannelEndpoint> endpoint, |
| 99 bool is_bootstrap) { | 99 bool is_bootstrap) { |
| 100 DCHECK(endpoint.get()); | 100 DCHECK(endpoint); |
| 101 | 101 |
| 102 ChannelEndpointId local_id; | 102 ChannelEndpointId local_id; |
| 103 ChannelEndpointId remote_id; | 103 ChannelEndpointId remote_id; |
| 104 { | 104 { |
| 105 base::AutoLock locker(lock_); | 105 base::AutoLock locker(lock_); |
| 106 | 106 |
| 107 DLOG_IF(WARNING, is_shutting_down_) | 107 DLOG_IF(WARNING, is_shutting_down_) |
| 108 << "AttachEndpoint() while shutting down"; | 108 << "AttachEndpoint() while shutting down"; |
| 109 | 109 |
| 110 if (is_bootstrap) { | 110 if (is_bootstrap) { |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 return; | 178 return; |
| 179 | 179 |
| 180 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); | 180 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); |
| 181 // We detach immediately if we receive a remove message, so it's possible | 181 // We detach immediately if we receive a remove message, so it's possible |
| 182 // that the local ID is no longer in |local_id_to_endpoint_map_|, or even | 182 // that the local ID is no longer in |local_id_to_endpoint_map_|, or even |
| 183 // that it's since been reused for another endpoint. In both cases, there's | 183 // that it's since been reused for another endpoint. In both cases, there's |
| 184 // nothing more to do. | 184 // nothing more to do. |
| 185 if (it == local_id_to_endpoint_map_.end() || it->second.get() != endpoint) | 185 if (it == local_id_to_endpoint_map_.end() || it->second.get() != endpoint) |
| 186 return; | 186 return; |
| 187 | 187 |
| 188 DCHECK(it->second.get()); | 188 DCHECK(it->second); |
| 189 it->second = nullptr; | 189 it->second = nullptr; |
| 190 | 190 |
| 191 // Send a remove message outside the lock. | 191 // Send a remove message outside the lock. |
| 192 } | 192 } |
| 193 | 193 |
| 194 if (!SendControlMessage( | 194 if (!SendControlMessage( |
| 195 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint, local_id, | 195 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint, local_id, |
| 196 remote_id)) { | 196 remote_id)) { |
| 197 HandleLocalError(base::StringPrintf( | 197 HandleLocalError(base::StringPrintf( |
| 198 "Failed to send message to remove remote message pipe endpoint (local " | 198 "Failed to send message to remove remote message pipe endpoint (local " |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 | 299 |
| 300 // Since we own |raw_channel_|, and this method and |Shutdown()| should only | 300 // Since we own |raw_channel_|, and this method and |Shutdown()| should only |
| 301 // be called from the creation thread, |raw_channel_| should never be null | 301 // be called from the creation thread, |raw_channel_| should never be null |
| 302 // here. | 302 // here. |
| 303 DCHECK(is_running_); | 303 DCHECK(is_running_); |
| 304 | 304 |
| 305 IdToEndpointMap::const_iterator it = | 305 IdToEndpointMap::const_iterator it = |
| 306 local_id_to_endpoint_map_.find(local_id); | 306 local_id_to_endpoint_map_.find(local_id); |
| 307 if (it != local_id_to_endpoint_map_.end()) { | 307 if (it != local_id_to_endpoint_map_.end()) { |
| 308 // Ignore messages for zombie endpoints (not an error). | 308 // Ignore messages for zombie endpoints (not an error). |
| 309 if (!it->second.get()) { | 309 if (!it->second) { |
| 310 DVLOG(2) << "Ignoring downstream message for zombie endpoint (local ID " | 310 DVLOG(2) << "Ignoring downstream message for zombie endpoint (local ID " |
| 311 "= " << local_id | 311 "= " << local_id |
| 312 << ", remote ID = " << message_view.source_id() << ")"; | 312 << ", remote ID = " << message_view.source_id() << ")"; |
| 313 return; | 313 return; |
| 314 } | 314 } |
| 315 | 315 |
| 316 endpoint = it->second; | 316 endpoint = it->second; |
| 317 } | 317 } |
| 318 } | 318 } |
| 319 if (!endpoint.get()) { | 319 if (!endpoint) { |
| 320 HandleRemoteError(base::StringPrintf( | 320 HandleRemoteError(base::StringPrintf( |
| 321 "Received a message for nonexistent local destination ID %u", | 321 "Received a message for nonexistent local destination ID %u", |
| 322 static_cast<unsigned>(local_id.value()))); | 322 static_cast<unsigned>(local_id.value()))); |
| 323 // This is strongly indicative of some problem. However, it's not a fatal | 323 // This is strongly indicative of some problem. However, it's not a fatal |
| 324 // error, since it may indicate a buggy (or hostile) remote process. Don't | 324 // error, since it may indicate a buggy (or hostile) remote process. Don't |
| 325 // die even for Debug builds, since handling this properly needs to be | 325 // die even for Debug builds, since handling this properly needs to be |
| 326 // tested (TODO(vtl)). | 326 // tested (TODO(vtl)). |
| 327 DLOG(ERROR) << "This should not happen under normal operation."; | 327 DLOG(ERROR) << "This should not happen under normal operation."; |
| 328 return; | 328 return; |
| 329 } | 329 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 446 scoped_refptr<ChannelEndpoint> endpoint; | 446 scoped_refptr<ChannelEndpoint> endpoint; |
| 447 { | 447 { |
| 448 base::AutoLock locker(lock_); | 448 base::AutoLock locker(lock_); |
| 449 | 449 |
| 450 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); | 450 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); |
| 451 if (it == local_id_to_endpoint_map_.end()) { | 451 if (it == local_id_to_endpoint_map_.end()) { |
| 452 DVLOG(2) << "Remove message pipe endpoint error: not found"; | 452 DVLOG(2) << "Remove message pipe endpoint error: not found"; |
| 453 return false; | 453 return false; |
| 454 } | 454 } |
| 455 | 455 |
| 456 if (!it->second.get()) { | 456 if (!it->second) { |
| 457 // Remove messages "crossed"; we have to wait for the ack. | 457 // Remove messages "crossed"; we have to wait for the ack. |
| 458 return true; | 458 return true; |
| 459 } | 459 } |
| 460 | 460 |
| 461 endpoint = it->second; | 461 endpoint = it->second; |
| 462 local_id_to_endpoint_map_.erase(it); | 462 local_id_to_endpoint_map_.erase(it); |
| 463 // Detach and send the remove ack message outside the lock. | 463 // Detach and send the remove ack message outside the lock. |
| 464 } | 464 } |
| 465 | 465 |
| 466 endpoint->DetachFromChannel(); | 466 endpoint->DetachFromChannel(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 482 DCHECK(creation_thread_checker_.CalledOnValidThread()); | 482 DCHECK(creation_thread_checker_.CalledOnValidThread()); |
| 483 | 483 |
| 484 base::AutoLock locker(lock_); | 484 base::AutoLock locker(lock_); |
| 485 | 485 |
| 486 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); | 486 IdToEndpointMap::iterator it = local_id_to_endpoint_map_.find(local_id); |
| 487 if (it == local_id_to_endpoint_map_.end()) { | 487 if (it == local_id_to_endpoint_map_.end()) { |
| 488 DVLOG(2) << "Remove message pipe endpoint ack error: not found"; | 488 DVLOG(2) << "Remove message pipe endpoint ack error: not found"; |
| 489 return false; | 489 return false; |
| 490 } | 490 } |
| 491 | 491 |
| 492 if (it->second.get()) { | 492 if (it->second) { |
| 493 DVLOG(2) << "Remove message pipe endpoint ack error: wrong state"; | 493 DVLOG(2) << "Remove message pipe endpoint ack error: wrong state"; |
| 494 return false; | 494 return false; |
| 495 } | 495 } |
| 496 | 496 |
| 497 local_id_to_endpoint_map_.erase(it); | 497 local_id_to_endpoint_map_.erase(it); |
| 498 return true; | 498 return true; |
| 499 } | 499 } |
| 500 | 500 |
| 501 bool Channel::SendControlMessage(MessageInTransit::Subtype subtype, | 501 bool Channel::SendControlMessage(MessageInTransit::Subtype subtype, |
| 502 ChannelEndpointId local_id, | 502 ChannelEndpointId local_id, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 520 // TODO(vtl): Is this how we really want to handle this? | 520 // TODO(vtl): Is this how we really want to handle this? |
| 521 // Sometimes we'll want to propagate the error back to the message pipe | 521 // Sometimes we'll want to propagate the error back to the message pipe |
| 522 // (endpoint), and notify it that the remote is (effectively) closed. | 522 // (endpoint), and notify it that the remote is (effectively) closed. |
| 523 // Sometimes we'll want to kill the channel (and notify all the endpoints that | 523 // Sometimes we'll want to kill the channel (and notify all the endpoints that |
| 524 // their remotes are dead. | 524 // their remotes are dead. |
| 525 LOG(WARNING) << error_message; | 525 LOG(WARNING) << error_message; |
| 526 } | 526 } |
| 527 | 527 |
| 528 } // namespace system | 528 } // namespace system |
| 529 } // namespace mojo | 529 } // namespace mojo |
| OLD | NEW |