aboutsummaryrefslogtreecommitdiff
path: root/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
diff options
context:
space:
mode:
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.cc382
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