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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
media / mojo / services / deferred_destroy_unique_receiver_set.h [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_MOJO_SERVICES_DEFERRED_DESTROY_UNIQUE_RECEIVER_SET_H_
#define MEDIA_MOJO_SERVICES_DEFERRED_DESTROY_UNIQUE_RECEIVER_SET_H_
#include <stdint.h>
#include <map>
#include <memory>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/task/bind_post_task.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
namespace media {
// A class that can be deferred destroyed by its owner. For example, when used
// in DeferredDestroyUniqueReceiverSet.
template <typename Interface>
class DeferredDestroy : public Interface {
public:
// Runs the |destroy_cb| to notify that it's okay to destroy |this|. The
// callback can be called synchronously. |this| will always be destroyed
// asynchronously after running |destroy_cb| to avoid reentrance issues.
virtual void OnDestroyPending(base::OnceClosure destroy_cb) = 0;
};
// Similar to mojo::UniqueReceiverSet, but provide a way to defer the
// destruction of the interface implementation:
// - When disconnection happened on a receiver, the receiver is immediately
// destroyed and removed from the set. The interface implementation will be
// destroyed when the DestroyCallback is called.
// - When the DeferredDestroyUniqueReceiverSet is destructed, all outstanding
// receivers and interface implementations in the set are destroyed immediately
// without any deferral.
template <typename Interface>
class DeferredDestroyUniqueReceiverSet {
public:
// Converts a delete callback to a deleter. If the callback is null or has
// been cancelled, callback bound with invalidated weak pointer, the pointer
// will be deleted with "delete" immediately.
class Deleter {
public:
using DeleteCallback =
base::RepeatingCallback<void(std::unique_ptr<Interface>)>;
Deleter() = default;
explicit Deleter(DeleteCallback delete_cb)
: delete_cb_(std::move(delete_cb)) {}
void operator()(Interface* p) {
// Immediately wrap |p| into a unique_ptr to avoid any potential leak.
auto ptr = base::WrapUnique<Interface>(p);
// Can be cancelled during DeferredDestroyUniqueReceiverSet destruction.
if (delete_cb_ && !delete_cb_.IsCancelled())
delete_cb_.Run(std::move(ptr));
else
ptr.reset();
}
private:
DeleteCallback delete_cb_;
};
DeferredDestroyUniqueReceiverSet() {}
DeferredDestroyUniqueReceiverSet(const DeferredDestroyUniqueReceiverSet&) =
delete;
DeferredDestroyUniqueReceiverSet& operator=(
const DeferredDestroyUniqueReceiverSet&) = delete;
void Add(std::unique_ptr<DeferredDestroy<Interface>> impl,
mojo::PendingReceiver<Interface> receiver) {
// Wrap the pointer into a unique_ptr with a deleter.
Deleter deleter(base::BindRepeating(
&DeferredDestroyUniqueReceiverSet::OnReceiverRemoved,
weak_factory_.GetWeakPtr()));
std::unique_ptr<Interface, Deleter> impl_with_deleter(impl.release(),
deleter);
receivers_.Add(std::move(impl_with_deleter), std::move(receiver));
}
// TODO(xhwang): Add RemoveReceiver() if needed.
void CloseAllReceivers() {
weak_factory_.InvalidateWeakPtrs();
receivers_.Clear();
unbound_impls_.clear();
}
bool empty() const { return receivers_.empty(); }
size_t size() const { return receivers_.size(); }
size_t unbound_size() const { return unbound_impls_.size(); }
private:
void OnReceiverRemoved(std::unique_ptr<Interface> ptr) {
DVLOG(1) << __func__;
id_++;
// The cast is safe since AddReceiver() takes DeferredDestroy<Interface>.
auto* impl_ptr = static_cast<DeferredDestroy<Interface>*>(ptr.get());
// Put the |ptr| in the map before calling OnDestroyPending() because the
// callback could be called synchronously.
unbound_impls_[id_] = std::move(ptr);
// Use base::BindPostTaskToCurrentDefault() to force post the destroy
// callback. This is needed because the callback may be called directly in
// the same stack where the implementation is being destroyed.
impl_ptr->OnDestroyPending(base::BindPostTaskToCurrentDefault(
base::BindOnce(&DeferredDestroyUniqueReceiverSet::OnDestroyable,
weak_factory_.GetWeakPtr(), id_)));
}
void OnDestroyable(int id) {
DVLOG(1) << __func__;
unbound_impls_.erase(id);
}
uint32_t id_ = 0;
std::map<uint32_t, std::unique_ptr<Interface>> unbound_impls_;
mojo::UniqueReceiverSet<Interface, void, Deleter> receivers_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<DeferredDestroyUniqueReceiverSet> weak_factory_{this};
};
} // namespace media
#endif // MEDIA_MOJO_SERVICES_DEFERRED_DESTROY_UNIQUE_RECEIVER_SET_H_