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 |