1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
// Copyright 2019 The Chromium Authors
// 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/component_export.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/task/sequenced_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;
// Attaches this group to another group, causing the former to retain a
// reference to the latter throughout its lifetime.
void SetParentGroup(Ref parent_group);
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::SequencedTaskRunner> task_runner);
ConnectionGroup(const ConnectionGroup&) = delete;
ConnectionGroup& operator=(const ConnectionGroup&) = delete;
unsigned int GetNumRefsForTesting() const { return num_refs_; }
private:
friend class base::RefCountedThreadSafe<ConnectionGroup>;
friend class Ref;
ConnectionGroup(base::RepeatingClosure callback,
scoped_refptr<base::SequencedTaskRunner> task_runner);
virtual ~ConnectionGroup();
void AddGroupRef();
void ReleaseGroupRef();
void SetParentGroup(Ref parent_group);
const base::RepeatingClosure notification_callback_;
const scoped_refptr<base::SequencedTaskRunner> notification_task_runner_;
// A reference to this group's parent group, if any.
Ref parent_group_;
// 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};
};
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_GROUP_H_
|