| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/public/cpp/bindings/scoped_interface_endpoint_handle.h" | 5 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/memory/ptr_util.h" | |
| 10 #include "base/synchronization/lock.h" | 9 #include "base/synchronization/lock.h" |
| 11 #include "mojo/public/cpp/bindings/associated_group_controller.h" | 10 #include "mojo/public/cpp/bindings/associated_group_controller.h" |
| 12 #include "mojo/public/cpp/bindings/lib/may_auto_lock.h" | 11 #include "mojo/public/cpp/bindings/lib/may_auto_lock.h" |
| 13 | 12 |
| 14 namespace mojo { | 13 namespace mojo { |
| 15 | 14 |
| 16 // ScopedInterfaceEndpointHandle::State ---------------------------------------- | 15 // ScopedInterfaceEndpointHandle::State ---------------------------------------- |
| 17 | 16 |
| 18 // State could be called from multiple threads. | 17 // State could be called from multiple threads. |
| 19 class ScopedInterfaceEndpointHandle::State | 18 class ScopedInterfaceEndpointHandle::State |
| 20 : public base::RefCountedThreadSafe<State> { | 19 : public base::RefCountedThreadSafe<State> { |
| 21 public: | 20 public: |
| 22 State() = default; | 21 State() = default; |
| 23 | 22 |
| 24 State(InterfaceId id, | 23 State(InterfaceId id, |
| 25 scoped_refptr<AssociatedGroupController> group_controller) | 24 scoped_refptr<AssociatedGroupController> group_controller) |
| 26 : id_(id), group_controller_(group_controller) {} | 25 : id_(id), group_controller_(group_controller) {} |
| 27 | 26 |
| 28 void InitPendingState(scoped_refptr<State> peer) { | 27 void InitPendingState(scoped_refptr<State> peer) { |
| 29 DCHECK(!lock_); | 28 DCHECK(!lock_); |
| 30 DCHECK(!pending_association_); | 29 DCHECK(!pending_association_); |
| 31 | 30 |
| 32 lock_ = base::MakeUnique<base::Lock>(); | 31 lock_.emplace(); |
| 33 pending_association_ = true; | 32 pending_association_ = true; |
| 34 peer_state_ = std::move(peer); | 33 peer_state_ = std::move(peer); |
| 35 } | 34 } |
| 36 | 35 |
| 37 void Close(const base::Optional<DisconnectReason>& reason) { | 36 void Close(const base::Optional<DisconnectReason>& reason) { |
| 38 scoped_refptr<AssociatedGroupController> cached_group_controller; | 37 scoped_refptr<AssociatedGroupController> cached_group_controller; |
| 39 InterfaceId cached_id = kInvalidInterfaceId; | 38 InterfaceId cached_id = kInvalidInterfaceId; |
| 40 scoped_refptr<State> cached_peer_state; | 39 scoped_refptr<State> cached_peer_state; |
| 41 | 40 |
| 42 { | 41 { |
| 43 internal::MayAutoLock locker(lock_.get()); | 42 internal::MayAutoLock locker(&lock_); |
| 44 | 43 |
| 45 if (!association_event_handler_.is_null()) { | 44 if (!association_event_handler_.is_null()) { |
| 46 association_event_handler_.Reset(); | 45 association_event_handler_.Reset(); |
| 47 runner_ = nullptr; | 46 runner_ = nullptr; |
| 48 } | 47 } |
| 49 | 48 |
| 50 if (!pending_association_) { | 49 if (!pending_association_) { |
| 51 if (IsValidInterfaceId(id_)) { | 50 if (IsValidInterfaceId(id_)) { |
| 52 // Intentionally keep |group_controller_| unchanged. | 51 // Intentionally keep |group_controller_| unchanged. |
| 53 // That is because the callback created by | 52 // That is because the callback created by |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 } | 85 } |
| 87 | 86 |
| 88 if (cached_group_controller) { | 87 if (cached_group_controller) { |
| 89 cached_group_controller->CloseEndpointHandle(cached_id, reason); | 88 cached_group_controller->CloseEndpointHandle(cached_id, reason); |
| 90 } else if (cached_peer_state) { | 89 } else if (cached_peer_state) { |
| 91 cached_peer_state->OnPeerClosedBeforeAssociation(reason); | 90 cached_peer_state->OnPeerClosedBeforeAssociation(reason); |
| 92 } | 91 } |
| 93 } | 92 } |
| 94 | 93 |
| 95 void SetAssociationEventHandler(AssociationEventCallback handler) { | 94 void SetAssociationEventHandler(AssociationEventCallback handler) { |
| 96 internal::MayAutoLock locker(lock_.get()); | 95 internal::MayAutoLock locker(&lock_); |
| 97 | 96 |
| 98 if (!pending_association_ && !IsValidInterfaceId(id_)) | 97 if (!pending_association_ && !IsValidInterfaceId(id_)) |
| 99 return; | 98 return; |
| 100 | 99 |
| 101 association_event_handler_ = std::move(handler); | 100 association_event_handler_ = std::move(handler); |
| 102 if (association_event_handler_.is_null()) { | 101 if (association_event_handler_.is_null()) { |
| 103 runner_ = nullptr; | 102 runner_ = nullptr; |
| 104 return; | 103 return; |
| 105 } | 104 } |
| 106 | 105 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 118 &ScopedInterfaceEndpointHandle::State::RunAssociationEventHandler, | 117 &ScopedInterfaceEndpointHandle::State::RunAssociationEventHandler, |
| 119 this, runner_, PEER_CLOSED_BEFORE_ASSOCIATION)); | 118 this, runner_, PEER_CLOSED_BEFORE_ASSOCIATION)); |
| 120 } | 119 } |
| 121 } | 120 } |
| 122 | 121 |
| 123 bool NotifyAssociation( | 122 bool NotifyAssociation( |
| 124 InterfaceId id, | 123 InterfaceId id, |
| 125 scoped_refptr<AssociatedGroupController> peer_group_controller) { | 124 scoped_refptr<AssociatedGroupController> peer_group_controller) { |
| 126 scoped_refptr<State> cached_peer_state; | 125 scoped_refptr<State> cached_peer_state; |
| 127 { | 126 { |
| 128 internal::MayAutoLock locker(lock_.get()); | 127 internal::MayAutoLock locker(&lock_); |
| 129 | 128 |
| 130 DCHECK(pending_association_); | 129 DCHECK(pending_association_); |
| 131 pending_association_ = false; | 130 pending_association_ = false; |
| 132 cached_peer_state = std::move(peer_state_); | 131 cached_peer_state = std::move(peer_state_); |
| 133 } | 132 } |
| 134 | 133 |
| 135 if (cached_peer_state) { | 134 if (cached_peer_state) { |
| 136 cached_peer_state->OnAssociated(id, std::move(peer_group_controller)); | 135 cached_peer_state->OnAssociated(id, std::move(peer_group_controller)); |
| 137 return true; | 136 return true; |
| 138 } | 137 } |
| 139 return false; | 138 return false; |
| 140 } | 139 } |
| 141 | 140 |
| 142 bool is_valid() const { | 141 bool is_valid() const { |
| 143 internal::MayAutoLock locker(lock_.get()); | 142 internal::MayAutoLock locker(&lock_); |
| 144 return pending_association_ || IsValidInterfaceId(id_); | 143 return pending_association_ || IsValidInterfaceId(id_); |
| 145 } | 144 } |
| 146 | 145 |
| 147 bool pending_association() const { | 146 bool pending_association() const { |
| 148 internal::MayAutoLock locker(lock_.get()); | 147 internal::MayAutoLock locker(&lock_); |
| 149 return pending_association_; | 148 return pending_association_; |
| 150 } | 149 } |
| 151 | 150 |
| 152 InterfaceId id() const { | 151 InterfaceId id() const { |
| 153 internal::MayAutoLock locker(lock_.get()); | 152 internal::MayAutoLock locker(&lock_); |
| 154 return id_; | 153 return id_; |
| 155 } | 154 } |
| 156 | 155 |
| 157 AssociatedGroupController* group_controller() const { | 156 AssociatedGroupController* group_controller() const { |
| 158 internal::MayAutoLock locker(lock_.get()); | 157 internal::MayAutoLock locker(&lock_); |
| 159 return group_controller_.get(); | 158 return group_controller_.get(); |
| 160 } | 159 } |
| 161 | 160 |
| 162 const base::Optional<DisconnectReason>& disconnect_reason() const { | 161 const base::Optional<DisconnectReason>& disconnect_reason() const { |
| 163 internal::MayAutoLock locker(lock_.get()); | 162 internal::MayAutoLock locker(&lock_); |
| 164 return disconnect_reason_; | 163 return disconnect_reason_; |
| 165 } | 164 } |
| 166 | 165 |
| 167 private: | 166 private: |
| 168 friend class base::RefCountedThreadSafe<State>; | 167 friend class base::RefCountedThreadSafe<State>; |
| 169 | 168 |
| 170 ~State() { | 169 ~State() { |
| 171 DCHECK(!pending_association_); | 170 DCHECK(!pending_association_); |
| 172 DCHECK(!IsValidInterfaceId(id_)); | 171 DCHECK(!IsValidInterfaceId(id_)); |
| 173 } | 172 } |
| 174 | 173 |
| 175 // Called by the peer, maybe from a different thread. | 174 // Called by the peer, maybe from a different thread. |
| 176 void OnAssociated(InterfaceId id, | 175 void OnAssociated(InterfaceId id, |
| 177 scoped_refptr<AssociatedGroupController> group_controller) { | 176 scoped_refptr<AssociatedGroupController> group_controller) { |
| 178 AssociationEventCallback handler; | 177 AssociationEventCallback handler; |
| 179 { | 178 { |
| 180 internal::MayAutoLock locker(lock_.get()); | 179 internal::MayAutoLock locker(&lock_); |
| 181 | 180 |
| 182 // There may be race between Close() of endpoint A and | 181 // There may be race between Close() of endpoint A and |
| 183 // NotifyPeerAssociation() of endpoint A_peer on different threads. | 182 // NotifyPeerAssociation() of endpoint A_peer on different threads. |
| 184 // Therefore, it is possible that endpoint A has been closed but it | 183 // Therefore, it is possible that endpoint A has been closed but it |
| 185 // still gets OnAssociated() call from its peer. | 184 // still gets OnAssociated() call from its peer. |
| 186 if (!pending_association_) | 185 if (!pending_association_) |
| 187 return; | 186 return; |
| 188 | 187 |
| 189 pending_association_ = false; | 188 pending_association_ = false; |
| 190 peer_state_ = nullptr; | 189 peer_state_ = nullptr; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 206 | 205 |
| 207 if (!handler.is_null()) | 206 if (!handler.is_null()) |
| 208 std::move(handler).Run(ASSOCIATED); | 207 std::move(handler).Run(ASSOCIATED); |
| 209 } | 208 } |
| 210 | 209 |
| 211 // Called by the peer, maybe from a different thread. | 210 // Called by the peer, maybe from a different thread. |
| 212 void OnPeerClosedBeforeAssociation( | 211 void OnPeerClosedBeforeAssociation( |
| 213 const base::Optional<DisconnectReason>& reason) { | 212 const base::Optional<DisconnectReason>& reason) { |
| 214 AssociationEventCallback handler; | 213 AssociationEventCallback handler; |
| 215 { | 214 { |
| 216 internal::MayAutoLock locker(lock_.get()); | 215 internal::MayAutoLock locker(&lock_); |
| 217 | 216 |
| 218 // There may be race between Close()/NotifyPeerAssociation() of endpoint | 217 // There may be race between Close()/NotifyPeerAssociation() of endpoint |
| 219 // A and Close() of endpoint A_peer on different threads. | 218 // A and Close() of endpoint A_peer on different threads. |
| 220 // Therefore, it is possible that endpoint A is not in pending association | 219 // Therefore, it is possible that endpoint A is not in pending association |
| 221 // state but still gets OnPeerClosedBeforeAssociation() call from its | 220 // state but still gets OnPeerClosedBeforeAssociation() call from its |
| 222 // peer. | 221 // peer. |
| 223 if (!pending_association_) | 222 if (!pending_association_) |
| 224 return; | 223 return; |
| 225 | 224 |
| 226 disconnect_reason_ = reason; | 225 disconnect_reason_ = reason; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 244 if (!handler.is_null()) | 243 if (!handler.is_null()) |
| 245 std::move(handler).Run(PEER_CLOSED_BEFORE_ASSOCIATION); | 244 std::move(handler).Run(PEER_CLOSED_BEFORE_ASSOCIATION); |
| 246 } | 245 } |
| 247 | 246 |
| 248 void RunAssociationEventHandler( | 247 void RunAssociationEventHandler( |
| 249 scoped_refptr<base::SingleThreadTaskRunner> posted_to_runner, | 248 scoped_refptr<base::SingleThreadTaskRunner> posted_to_runner, |
| 250 AssociationEvent event) { | 249 AssociationEvent event) { |
| 251 AssociationEventCallback handler; | 250 AssociationEventCallback handler; |
| 252 | 251 |
| 253 { | 252 { |
| 254 internal::MayAutoLock locker(lock_.get()); | 253 internal::MayAutoLock locker(&lock_); |
| 255 if (posted_to_runner == runner_) { | 254 if (posted_to_runner == runner_) { |
| 256 runner_ = nullptr; | 255 runner_ = nullptr; |
| 257 handler = std::move(association_event_handler_); | 256 handler = std::move(association_event_handler_); |
| 258 } | 257 } |
| 259 } | 258 } |
| 260 | 259 |
| 261 if (!handler.is_null()) | 260 if (!handler.is_null()) |
| 262 std::move(handler).Run(event); | 261 std::move(handler).Run(event); |
| 263 } | 262 } |
| 264 | 263 |
| 265 // Protects the following members if the handle is initially set to pending | 264 // Protects the following members if the handle is initially set to pending |
| 266 // association. | 265 // association. |
| 267 std::unique_ptr<base::Lock> lock_; | 266 mutable base::Optional<base::Lock> lock_; |
| 268 | 267 |
| 269 bool pending_association_ = false; | 268 bool pending_association_ = false; |
| 270 base::Optional<DisconnectReason> disconnect_reason_; | 269 base::Optional<DisconnectReason> disconnect_reason_; |
| 271 | 270 |
| 272 scoped_refptr<State> peer_state_; | 271 scoped_refptr<State> peer_state_; |
| 273 | 272 |
| 274 AssociationEventCallback association_event_handler_; | 273 AssociationEventCallback association_event_handler_; |
| 275 scoped_refptr<base::SingleThreadTaskRunner> runner_; | 274 scoped_refptr<base::SingleThreadTaskRunner> runner_; |
| 276 | 275 |
| 277 InterfaceId id_ = kInvalidInterfaceId; | 276 InterfaceId id_ = kInvalidInterfaceId; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 | 373 |
| 375 base::Callback<AssociatedGroupController*()> | 374 base::Callback<AssociatedGroupController*()> |
| 376 ScopedInterfaceEndpointHandle::CreateGroupControllerGetter() const { | 375 ScopedInterfaceEndpointHandle::CreateGroupControllerGetter() const { |
| 377 // We allow this callback to be run on any thread. If this handle is created | 376 // We allow this callback to be run on any thread. If this handle is created |
| 378 // in non-pending state, we don't have a lock but it should still be safe | 377 // in non-pending state, we don't have a lock but it should still be safe |
| 379 // because the group controller never changes. | 378 // because the group controller never changes. |
| 380 return base::Bind(&State::group_controller, state_); | 379 return base::Bind(&State::group_controller, state_); |
| 381 } | 380 } |
| 382 | 381 |
| 383 } // namespace mojo | 382 } // namespace mojo |
| OLD | NEW |