| // 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. |
| |
| #ifndef MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_GROUP_H_ |
| #define MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_GROUP_H_ |
| |
| #include <atomic> |
| |
| #include "base/callback.h" |
| #include "base/component_export.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/task_runner.h" |
| |
| namespace mojo { |
| |
| // A ConnectionGroup is used to loosely track groups of related interface |
| // receivers. Any Receiver or PendingReceiver can reference a single |
| // ConnectionGroup by holding onto a corresponding Ref. |
| // |
| // Belonging to a connection group is a viral property: if a Receiver belongs to |
| // a connection group, any PendingReceivers arriving in inbound messages |
| // automatically inherit a Ref to the same group. Likewise if a PendingReceiver |
| // belongs to a group, any Receiver which consumes and binds that |
| // PendingReceiver inherits its group membership. |
| class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) ConnectionGroup |
| : public base::RefCountedThreadSafe<ConnectionGroup> { |
| public: |
| // A single opaque reference to a ConnectionGroup. May be freely moved and |
| // copied. |
| class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) Ref { |
| public: |
| Ref(); |
| Ref(const Ref&); |
| Ref(Ref&&) noexcept; |
| ~Ref(); |
| |
| Ref& operator=(const Ref&); |
| Ref& operator=(Ref&&) noexcept; |
| |
| explicit operator bool() const { return group_ != nullptr; } |
| void reset(); |
| |
| // Returns a real reference to the underlying ConnectionGroup. Should only |
| // be used in testing. |
| scoped_refptr<ConnectionGroup> GetGroupForTesting() { return group_; } |
| |
| // Returns a weak copy of this Ref. Does not increase ref-count. |
| Ref WeakCopy() const; |
| |
| // Indicates whether the underlying ConnectionGroup has zero strong |
| // references. Must ONLY be called from the sequence which owns the |
| // primordial weak Ref, since that sequence may increase the ref count at |
| // any time and otherwise this accessor would be unreliable. |
| bool HasZeroRefs() const; |
| |
| private: |
| friend class ConnectionGroup; |
| |
| enum class Type { |
| // A weak Ref does not influence the ref-count of its referenced group. |
| // Weak references always produce strong references when copied. |
| kWeak, |
| |
| // A strong Ref influences the ref-count of its reference group. |
| kStrong, |
| }; |
| |
| explicit Ref(scoped_refptr<ConnectionGroup> group); |
| |
| Type type_ = Type::kWeak; |
| scoped_refptr<ConnectionGroup> group_; |
| }; |
| |
| // Constructs a new ConnectionGroup and returns an initial Ref to it. This |
| // initial reference does *not* increase the group's ref-count. All other |
| // copies of Ref increase the ref-count. Any time the ref-count is decremented |
| // to zero, |callback| is invoked on |task_runner|. If |task_runner| is null |
| // (useless except perhaps in tests), |callback| is ignored. |
| static Ref Create(base::RepeatingClosure callback, |
| scoped_refptr<base::TaskRunner> task_runner); |
| |
| unsigned int GetNumRefsForTesting() const { return num_refs_; } |
| |
| private: |
| friend class base::RefCountedThreadSafe<ConnectionGroup>; |
| friend class Ref; |
| |
| ConnectionGroup(base::RepeatingClosure callback, |
| scoped_refptr<base::TaskRunner> task_runner); |
| virtual ~ConnectionGroup(); |
| |
| void AddGroupRef(); |
| void ReleaseGroupRef(); |
| |
| const base::RepeatingClosure notification_callback_; |
| const scoped_refptr<base::TaskRunner> notification_task_runner_; |
| |
| // We maintain our own ref count because we need to trigger behavior on |
| // release, and doing that in conjunction with the RefCountedThreadSafe's own |
| // lifetime-controlling ref count is not safely possible. |
| std::atomic<unsigned int> num_refs_{0}; |
| |
| DISALLOW_COPY_AND_ASSIGN(ConnectionGroup); |
| }; |
| |
| } // namespace mojo |
| |
| #endif // MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_GROUP_H_ |