| // Copyright 2019 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/connection_group.h" |
| |
| #include "base/bind.h" |
| |
| namespace mojo { |
| |
| ConnectionGroup::Ref::Ref() = default; |
| |
| ConnectionGroup::Ref::Ref(const Ref& other) { |
| *this = other; |
| } |
| |
| ConnectionGroup::Ref::Ref(Ref&& other) noexcept { |
| *this = std::move(other); |
| } |
| |
| ConnectionGroup::Ref::~Ref() { |
| reset(); |
| } |
| |
| ConnectionGroup::Ref& ConnectionGroup::Ref::operator=(const Ref& other) { |
| reset(); |
| type_ = Type::kStrong; |
| group_ = other.group_; |
| group_->AddGroupRef(); |
| return *this; |
| } |
| |
| ConnectionGroup::Ref& ConnectionGroup::Ref::operator=(Ref&& other) noexcept { |
| reset(); |
| type_ = other.type_; |
| group_.swap(other.group_); |
| return *this; |
| } |
| |
| void ConnectionGroup::Ref::reset() { |
| if (type_ == Type::kStrong && group_) |
| group_->ReleaseGroupRef(); |
| type_ = Type::kWeak; |
| group_.reset(); |
| } |
| |
| ConnectionGroup::Ref ConnectionGroup::Ref::WeakCopy() const { |
| DCHECK(group_->notification_task_runner_->RunsTasksInCurrentSequence()); |
| return Ref(group_); |
| } |
| |
| bool ConnectionGroup::Ref::HasZeroRefs() const { |
| DCHECK(group_->notification_task_runner_->RunsTasksInCurrentSequence()); |
| return group_->num_refs_ == 0; |
| } |
| |
| void ConnectionGroup::Ref::SetParentGroup(Ref parent_group) { |
| group_->notification_task_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&ConnectionGroup::SetParentGroup, group_, |
| std::move(parent_group))); |
| } |
| |
| ConnectionGroup::Ref::Ref(scoped_refptr<ConnectionGroup> group) |
| : group_(std::move(group)) {} |
| |
| // static |
| ConnectionGroup::Ref ConnectionGroup::Create( |
| base::RepeatingClosure callback, |
| scoped_refptr<base::SequencedTaskRunner> task_runner) { |
| return Ref(base::WrapRefCounted( |
| new ConnectionGroup(std::move(callback), std::move(task_runner)))); |
| } |
| |
| ConnectionGroup::ConnectionGroup( |
| base::RepeatingClosure callback, |
| scoped_refptr<base::SequencedTaskRunner> task_runner) |
| : notification_callback_(std::move(callback)), |
| notification_task_runner_(std::move(task_runner)) {} |
| |
| ConnectionGroup::~ConnectionGroup() { |
| // Just a sanity check. This ref-count should always be adjusted before the |
| // internal RefCountedThreadSafe ref-count, so we should never hit the |
| // destructor with a non-zero |num_refs_|. |
| DCHECK_EQ(num_refs_, 0u); |
| } |
| |
| void ConnectionGroup::AddGroupRef() { |
| ++num_refs_; |
| } |
| |
| void ConnectionGroup::ReleaseGroupRef() { |
| DCHECK_GT(num_refs_, 0u); |
| --num_refs_; |
| if (num_refs_ == 0 && notification_task_runner_) { |
| notification_task_runner_->PostTask(FROM_HERE, |
| base::BindOnce(notification_callback_)); |
| } |
| } |
| |
| void ConnectionGroup::SetParentGroup(Ref parent_group) { |
| DCHECK(notification_task_runner_->RunsTasksInCurrentSequence()); |
| DCHECK(!parent_group_); |
| parent_group_ = std::move(parent_group); |
| } |
| |
| } // namespace mojo |