diff options
Diffstat (limited to 'mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc')
-rw-r--r-- | mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc | 382 |
1 files changed, 0 insertions, 382 deletions
diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc deleted file mode 100644 index c134507..0000000 --- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/synchronization/lock.h" -#include "mojo/public/cpp/bindings/associated_group_controller.h" -#include "mojo/public/cpp/bindings/lib/may_auto_lock.h" - -namespace mojo { - -// ScopedInterfaceEndpointHandle::State ---------------------------------------- - -// State could be called from multiple threads. -class ScopedInterfaceEndpointHandle::State - : public base::RefCountedThreadSafe<State> { - public: - State() = default; - - State(InterfaceId id, - scoped_refptr<AssociatedGroupController> group_controller) - : id_(id), group_controller_(group_controller) {} - - void InitPendingState(scoped_refptr<State> peer) { - DCHECK(!lock_); - DCHECK(!pending_association_); - - lock_.emplace(); - pending_association_ = true; - peer_state_ = std::move(peer); - } - - void Close(const base::Optional<DisconnectReason>& reason) { - scoped_refptr<AssociatedGroupController> cached_group_controller; - InterfaceId cached_id = kInvalidInterfaceId; - scoped_refptr<State> cached_peer_state; - - { - internal::MayAutoLock locker(&lock_); - - if (!association_event_handler_.is_null()) { - association_event_handler_.Reset(); - runner_ = nullptr; - } - - if (!pending_association_) { - if (IsValidInterfaceId(id_)) { - // Intentionally keep |group_controller_| unchanged. - // That is because the callback created by - // CreateGroupControllerGetter() could still be used after this point, - // potentially from another thread. We would like it to continue - // returning the same group controller. - // - // Imagine there is a ThreadSafeForwarder A: - // (1) On the IO thread, A's underlying associated interface pointer - // is closed. - // (2) On the proxy thread, the user makes a call on A to pass an - // associated request B_asso_req. The callback returned by - // CreateGroupControllerGetter() is used to associate B_asso_req. - // (3) On the proxy thread, the user immediately binds B_asso_ptr_info - // to B_asso_ptr and makes calls on it. - // - // If we reset |group_controller_| in step (1), step (2) won't be able - // to associate B_asso_req. Therefore, in step (3) B_asso_ptr won't be - // able to serialize associated endpoints or send message because it - // is still in "pending_association" state and doesn't have a group - // controller. - // - // We could "address" this issue by ignoring messages if there isn't a - // group controller. But the side effect is that we cannot detect - // programming errors of "using associated interface pointer before - // sending associated request". - - cached_group_controller = group_controller_; - cached_id = id_; - id_ = kInvalidInterfaceId; - } - } else { - pending_association_ = false; - cached_peer_state = std::move(peer_state_); - } - } - - if (cached_group_controller) { - cached_group_controller->CloseEndpointHandle(cached_id, reason); - } else if (cached_peer_state) { - cached_peer_state->OnPeerClosedBeforeAssociation(reason); - } - } - - void SetAssociationEventHandler(AssociationEventCallback handler) { - internal::MayAutoLock locker(&lock_); - - if (!pending_association_ && !IsValidInterfaceId(id_)) - return; - - association_event_handler_ = std::move(handler); - if (association_event_handler_.is_null()) { - runner_ = nullptr; - return; - } - - runner_ = base::ThreadTaskRunnerHandle::Get(); - if (!pending_association_) { - runner_->PostTask( - FROM_HERE, - base::Bind( - &ScopedInterfaceEndpointHandle::State::RunAssociationEventHandler, - this, runner_, ASSOCIATED)); - } else if (!peer_state_) { - runner_->PostTask( - FROM_HERE, - base::Bind( - &ScopedInterfaceEndpointHandle::State::RunAssociationEventHandler, - this, runner_, PEER_CLOSED_BEFORE_ASSOCIATION)); - } - } - - bool NotifyAssociation( - InterfaceId id, - scoped_refptr<AssociatedGroupController> peer_group_controller) { - scoped_refptr<State> cached_peer_state; - { - internal::MayAutoLock locker(&lock_); - - DCHECK(pending_association_); - pending_association_ = false; - cached_peer_state = std::move(peer_state_); - } - - if (cached_peer_state) { - cached_peer_state->OnAssociated(id, std::move(peer_group_controller)); - return true; - } - return false; - } - - bool is_valid() const { - internal::MayAutoLock locker(&lock_); - return pending_association_ || IsValidInterfaceId(id_); - } - - bool pending_association() const { - internal::MayAutoLock locker(&lock_); - return pending_association_; - } - - InterfaceId id() const { - internal::MayAutoLock locker(&lock_); - return id_; - } - - AssociatedGroupController* group_controller() const { - internal::MayAutoLock locker(&lock_); - return group_controller_.get(); - } - - const base::Optional<DisconnectReason>& disconnect_reason() const { - internal::MayAutoLock locker(&lock_); - return disconnect_reason_; - } - - private: - friend class base::RefCountedThreadSafe<State>; - - ~State() { - DCHECK(!pending_association_); - DCHECK(!IsValidInterfaceId(id_)); - } - - // Called by the peer, maybe from a different thread. - void OnAssociated(InterfaceId id, - scoped_refptr<AssociatedGroupController> group_controller) { - AssociationEventCallback handler; - { - internal::MayAutoLock locker(&lock_); - - // There may be race between Close() of endpoint A and - // NotifyPeerAssociation() of endpoint A_peer on different threads. - // Therefore, it is possible that endpoint A has been closed but it - // still gets OnAssociated() call from its peer. - if (!pending_association_) - return; - - pending_association_ = false; - peer_state_ = nullptr; - id_ = id; - group_controller_ = std::move(group_controller); - - if (!association_event_handler_.is_null()) { - if (runner_->BelongsToCurrentThread()) { - handler = std::move(association_event_handler_); - runner_ = nullptr; - } else { - runner_->PostTask(FROM_HERE, - base::Bind(&ScopedInterfaceEndpointHandle::State:: - RunAssociationEventHandler, - this, runner_, ASSOCIATED)); - } - } - } - - if (!handler.is_null()) - std::move(handler).Run(ASSOCIATED); - } - - // Called by the peer, maybe from a different thread. - void OnPeerClosedBeforeAssociation( - const base::Optional<DisconnectReason>& reason) { - AssociationEventCallback handler; - { - internal::MayAutoLock locker(&lock_); - - // There may be race between Close()/NotifyPeerAssociation() of endpoint - // A and Close() of endpoint A_peer on different threads. - // Therefore, it is possible that endpoint A is not in pending association - // state but still gets OnPeerClosedBeforeAssociation() call from its - // peer. - if (!pending_association_) - return; - - disconnect_reason_ = reason; - // NOTE: This handle itself is still pending. - peer_state_ = nullptr; - - if (!association_event_handler_.is_null()) { - if (runner_->BelongsToCurrentThread()) { - handler = std::move(association_event_handler_); - runner_ = nullptr; - } else { - runner_->PostTask( - FROM_HERE, - base::Bind(&ScopedInterfaceEndpointHandle::State:: - RunAssociationEventHandler, - this, runner_, PEER_CLOSED_BEFORE_ASSOCIATION)); - } - } - } - - if (!handler.is_null()) - std::move(handler).Run(PEER_CLOSED_BEFORE_ASSOCIATION); - } - - void RunAssociationEventHandler( - scoped_refptr<base::SingleThreadTaskRunner> posted_to_runner, - AssociationEvent event) { - AssociationEventCallback handler; - - { - internal::MayAutoLock locker(&lock_); - if (posted_to_runner == runner_) { - runner_ = nullptr; - handler = std::move(association_event_handler_); - } - } - - if (!handler.is_null()) - std::move(handler).Run(event); - } - - // Protects the following members if the handle is initially set to pending - // association. - mutable base::Optional<base::Lock> lock_; - - bool pending_association_ = false; - base::Optional<DisconnectReason> disconnect_reason_; - - scoped_refptr<State> peer_state_; - - AssociationEventCallback association_event_handler_; - scoped_refptr<base::SingleThreadTaskRunner> runner_; - - InterfaceId id_ = kInvalidInterfaceId; - scoped_refptr<AssociatedGroupController> group_controller_; - - DISALLOW_COPY_AND_ASSIGN(State); -}; - -// ScopedInterfaceEndpointHandle ----------------------------------------------- - -// static -void ScopedInterfaceEndpointHandle::CreatePairPendingAssociation( - ScopedInterfaceEndpointHandle* handle0, - ScopedInterfaceEndpointHandle* handle1) { - ScopedInterfaceEndpointHandle result0; - ScopedInterfaceEndpointHandle result1; - result0.state_->InitPendingState(result1.state_); - result1.state_->InitPendingState(result0.state_); - - *handle0 = std::move(result0); - *handle1 = std::move(result1); -} - -ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle() - : state_(new State) {} - -ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle( - ScopedInterfaceEndpointHandle&& other) - : state_(new State) { - state_.swap(other.state_); -} - -ScopedInterfaceEndpointHandle::~ScopedInterfaceEndpointHandle() { - state_->Close(base::nullopt); -} - -ScopedInterfaceEndpointHandle& ScopedInterfaceEndpointHandle::operator=( - ScopedInterfaceEndpointHandle&& other) { - reset(); - state_.swap(other.state_); - return *this; -} - -bool ScopedInterfaceEndpointHandle::is_valid() const { - return state_->is_valid(); -} - -bool ScopedInterfaceEndpointHandle::pending_association() const { - return state_->pending_association(); -} - -InterfaceId ScopedInterfaceEndpointHandle::id() const { - return state_->id(); -} - -AssociatedGroupController* ScopedInterfaceEndpointHandle::group_controller() - const { - return state_->group_controller(); -} - -const base::Optional<DisconnectReason>& -ScopedInterfaceEndpointHandle::disconnect_reason() const { - return state_->disconnect_reason(); -} - -void ScopedInterfaceEndpointHandle::SetAssociationEventHandler( - AssociationEventCallback handler) { - state_->SetAssociationEventHandler(std::move(handler)); -} - -void ScopedInterfaceEndpointHandle::reset() { - ResetInternal(base::nullopt); -} - -void ScopedInterfaceEndpointHandle::ResetWithReason( - uint32_t custom_reason, - const std::string& description) { - ResetInternal(DisconnectReason(custom_reason, description)); -} - -ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle( - InterfaceId id, - scoped_refptr<AssociatedGroupController> group_controller) - : state_(new State(id, std::move(group_controller))) { - DCHECK(!IsValidInterfaceId(state_->id()) || state_->group_controller()); -} - -bool ScopedInterfaceEndpointHandle::NotifyAssociation( - InterfaceId id, - scoped_refptr<AssociatedGroupController> peer_group_controller) { - return state_->NotifyAssociation(id, peer_group_controller); -} - -void ScopedInterfaceEndpointHandle::ResetInternal( - const base::Optional<DisconnectReason>& reason) { - scoped_refptr<State> new_state(new State); - state_->Close(reason); - state_.swap(new_state); -} - -base::Callback<AssociatedGroupController*()> -ScopedInterfaceEndpointHandle::CreateGroupControllerGetter() const { - // We allow this callback to be run on any thread. If this handle is created - // in non-pending state, we don't have a lock but it should still be safe - // because the group controller never changes. - return base::Bind(&State::group_controller, state_); -} - -} // namespace mojo |