From 21a249e4d9cb0b2ec6f0ff84ed5f7939ea67ac52 Mon Sep 17 00:00:00 2001 From: Luis Hector Chavez Date: Wed, 26 Jul 2017 17:38:05 +0000 Subject: Revert "libmojo: Uprev the library to r456626 from Chromium" This reverts commit 8ac9103e05b66812c25348943383f9365d1ce3e0. Reason for revert: Broke the mac_sdk Exempt-From-Owner-Approval: Fixing mac_sdk Change-Id: I0b74d1abaa66933a93fd6f82ff018e8948c1204e --- .../lib/scoped_interface_endpoint_handle.cc | 370 ++------------------- 1 file changed, 30 insertions(+), 340 deletions(-) (limited to 'mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc') diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc index c134507..f54c3f7 100644 --- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc +++ b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc @@ -4,379 +4,69 @@ #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 { - public: - State() = default; - - State(InterfaceId id, - scoped_refptr group_controller) - : id_(id), group_controller_(group_controller) {} - - void InitPendingState(scoped_refptr peer) { - DCHECK(!lock_); - DCHECK(!pending_association_); - - lock_.emplace(); - pending_association_ = true; - peer_state_ = std::move(peer); - } - - void Close(const base::Optional& reason) { - scoped_refptr cached_group_controller; - InterfaceId cached_id = kInvalidInterfaceId; - scoped_refptr 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 peer_group_controller) { - scoped_refptr 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& disconnect_reason() const { - internal::MayAutoLock locker(&lock_); - return disconnect_reason_; - } - - private: - friend class base::RefCountedThreadSafe; - - ~State() { - DCHECK(!pending_association_); - DCHECK(!IsValidInterfaceId(id_)); - } - - // Called by the peer, maybe from a different thread. - void OnAssociated(InterfaceId id, - scoped_refptr 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& 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 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 lock_; - - bool pending_association_ = false; - base::Optional disconnect_reason_; - - scoped_refptr peer_state_; - - AssociationEventCallback association_event_handler_; - scoped_refptr runner_; - - InterfaceId id_ = kInvalidInterfaceId; - scoped_refptr 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(kInvalidInterfaceId, true, nullptr) {} ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle( ScopedInterfaceEndpointHandle&& other) - : state_(new State) { - state_.swap(other.state_); + : id_(other.id_), is_local_(other.is_local_) { + group_controller_.swap(other.group_controller_); + other.id_ = kInvalidInterfaceId; } ScopedInterfaceEndpointHandle::~ScopedInterfaceEndpointHandle() { - state_->Close(base::nullopt); + reset(); } ScopedInterfaceEndpointHandle& ScopedInterfaceEndpointHandle::operator=( ScopedInterfaceEndpointHandle&& other) { reset(); - state_.swap(other.state_); - return *this; -} + swap(other); -bool ScopedInterfaceEndpointHandle::is_valid() const { - return state_->is_valid(); + return *this; } -bool ScopedInterfaceEndpointHandle::pending_association() const { - return state_->pending_association(); -} +void ScopedInterfaceEndpointHandle::reset() { + if (!IsValidInterfaceId(id_)) + return; -InterfaceId ScopedInterfaceEndpointHandle::id() const { - return state_->id(); -} + group_controller_->CloseEndpointHandle(id_, is_local_); -AssociatedGroupController* ScopedInterfaceEndpointHandle::group_controller() - const { - return state_->group_controller(); + id_ = kInvalidInterfaceId; + is_local_ = true; + group_controller_ = nullptr; } -const base::Optional& -ScopedInterfaceEndpointHandle::disconnect_reason() const { - return state_->disconnect_reason(); +void ScopedInterfaceEndpointHandle::swap(ScopedInterfaceEndpointHandle& other) { + using std::swap; + swap(other.id_, id_); + swap(other.is_local_, is_local_); + swap(other.group_controller_, group_controller_); } -void ScopedInterfaceEndpointHandle::SetAssociationEventHandler( - AssociationEventCallback handler) { - state_->SetAssociationEventHandler(std::move(handler)); -} +InterfaceId ScopedInterfaceEndpointHandle::release() { + InterfaceId result = id_; -void ScopedInterfaceEndpointHandle::reset() { - ResetInternal(base::nullopt); -} + id_ = kInvalidInterfaceId; + is_local_ = true; + group_controller_ = nullptr; -void ScopedInterfaceEndpointHandle::ResetWithReason( - uint32_t custom_reason, - const std::string& description) { - ResetInternal(DisconnectReason(custom_reason, description)); + return result; } ScopedInterfaceEndpointHandle::ScopedInterfaceEndpointHandle( InterfaceId id, + bool is_local, scoped_refptr group_controller) - : state_(new State(id, std::move(group_controller))) { - DCHECK(!IsValidInterfaceId(state_->id()) || state_->group_controller()); -} - -bool ScopedInterfaceEndpointHandle::NotifyAssociation( - InterfaceId id, - scoped_refptr peer_group_controller) { - return state_->NotifyAssociation(id, peer_group_controller); -} - -void ScopedInterfaceEndpointHandle::ResetInternal( - const base::Optional& reason) { - scoped_refptr new_state(new State); - state_->Close(reason); - state_.swap(new_state); -} - -base::Callback -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_); + : id_(id), + is_local_(is_local), + group_controller_(std::move(group_controller)) { + DCHECK(!IsValidInterfaceId(id) || group_controller_); } } // namespace mojo -- cgit v1.2.3