1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_CALLBACK_LIST_H_
6 #define BASE_CALLBACK_LIST_H_
7 
8 #include <list>
9 #include <memory>
10 #include <utility>
11 
12 #include "base/auto_reset.h"
13 #include "base/bind.h"
14 #include "base/callback.h"
15 #include "base/callback_helpers.h"
16 #include "base/check.h"
17 #include "base/compiler_specific.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/ranges/algorithm.h"
20 #include "base/stl_util.h"
21 
22 // OVERVIEW:
23 //
24 // A container for a list of callbacks. Provides callers the ability to manually
25 // or automatically unregister callbacks at any time, including during callback
26 // notification.
27 //
28 // TYPICAL USAGE:
29 //
30 // class MyWidget {
31 //  public:
32 //   using CallbackList = base::RepeatingCallbackList<void(const Foo&)>;
33 //
34 //   // Registers |cb| to be called whenever NotifyFoo() is executed.
35 //   std::unique_ptr<CallbackList::Subscription>
36 //   RegisterCallback(CallbackList::CallbackType cb) {
37 //     return callback_list_.Add(std::move(cb));
38 //   }
39 //
40 //  private:
41 //   // Calls all registered callbacks, with |foo| as the supplied arg.
42 //   void NotifyFoo(const Foo& foo) {
43 //     callback_list_.Notify(foo);
44 //   }
45 //
46 //   CallbackList callback_list_;
47 // };
48 //
49 //
50 // class MyWidgetListener {
51 //  private:
52 //   void OnFoo(const Foo& foo) {
53 //     // Called whenever MyWidget::NotifyFoo() is executed, unless
54 //     // |foo_subscription_| has been reset().
55 //   }
56 //
57 //   // Automatically deregisters the callback when deleted (e.g. in
58 //   // ~MyWidgetListener()).  Unretained(this) is safe here since the
59 //   // Subscription does not outlive |this|.
60 //   std::unique_ptr<MyWidget::CallbackList::Subscription> foo_subscription_ =
61 //       MyWidget::Get()->RegisterCallback(
62 //           base::BindRepeating(&MyWidgetListener::OnFoo,
63 //                               base::Unretained(this)));
64 // };
65 //
66 // UNSUPPORTED:
67 //
68 // * Destroying the CallbackList during callback notification.
69 //
70 // This is possible to support, but not currently necessary.
71 
72 namespace base {
73 
74 template <typename Signature>
75 class OnceCallbackList;
76 
77 template <typename Signature>
78 class RepeatingCallbackList;
79 
80 namespace internal {
81 
82 // A traits class to break circular type dependencies between CallbackListBase
83 // and its subclasses.
84 template <typename CallbackList>
85 struct CallbackListTraits;
86 
87 // NOTE: It's important that Callbacks provide iterator stability when items are
88 // added to the end, so e.g. a std::vector<> is not suitable here.
89 template <typename Signature>
90 struct CallbackListTraits<OnceCallbackList<Signature>> {
91   using CallbackType = OnceCallback<Signature>;
92   using Callbacks = std::list<CallbackType>;
93 };
94 template <typename Signature>
95 struct CallbackListTraits<RepeatingCallbackList<Signature>> {
96   using CallbackType = RepeatingCallback<Signature>;
97   using Callbacks = std::list<CallbackType>;
98 };
99 
100 template <typename CallbackListImpl>
101 class CallbackListBase {
102  public:
103   using CallbackType =
104       typename CallbackListTraits<CallbackListImpl>::CallbackType;
105   static_assert(IsBaseCallback<CallbackType>::value, "");
106 
107   // A cancellation handle for callers who register callbacks. Subscription
108   // destruction cancels the associated callback and is legal any time,
109   // including after the destruction of the CallbackList that vends it.
110   class Subscription {
111    public:
112     explicit Subscription(base::OnceClosure destruction_closure)
113         : destruction_closure_(std::move(destruction_closure)) {}
114 
115     Subscription(Subscription&&) = default;
116     Subscription& operator=(Subscription&&) = default;
117 
118     ~Subscription() { std::move(destruction_closure_).Run(); }
119 
120    private:
121     // Run when |this| is destroyed to notify the CallbackList the associated
122     // callback should be canceled. Since this is bound using a WeakPtr to the
123     // CallbackList, it will automatically no-op if the CallbackList no longer
124     // exists.
125     base::OnceClosure destruction_closure_;
126   };
127 
128   CallbackListBase() = default;
129   CallbackListBase(const CallbackListBase&) = delete;
130   CallbackListBase& operator=(const CallbackListBase&) = delete;
131 
132   ~CallbackListBase() {
133     // Destroying the list during iteration is unsupported and will cause a UAF.
134     CHECK(!iterating_);
135   }
136 
137   // Registers |cb| for future notifications. Returns a Subscription that can be
138   // used to cancel |cb|.
139   std::unique_ptr<Subscription> Add(CallbackType cb) WARN_UNUSED_RESULT {
140     DCHECK(!cb.is_null());
141     return std::make_unique<Subscription>(base::BindOnce(
142         &CallbackListBase::CancelCallback, weak_ptr_factory_.GetWeakPtr(),
143         callbacks_.insert(callbacks_.end(), std::move(cb))));
144   }
145 
146   // Registers |cb| for future notifications. Provides no way for the caller to
147   // cancel, so this is only safe for cases where the callback is guaranteed to
148   // live at least as long as this list (e.g. if it's bound on the same object
149   // that owns the list).
150   // TODO(pkasting): Attempt to use Add() instead and see if callers can relax
151   // other lifetime/ordering mechanisms as a result.
152   void AddUnsafe(CallbackType cb) {
153     DCHECK(!cb.is_null());
154     callbacks_.push_back(std::move(cb));
155   }
156 
157   // Registers |removal_callback| to be run after elements are removed from the
158   // list of registered callbacks.
159   void set_removal_callback(const RepeatingClosure& removal_callback) {
160     removal_callback_ = removal_callback;
161   }
162 
163   // Returns whether the list of registered callbacks is empty (from an external
164   // perspective -- meaning no remaining callbacks are live).
165   bool empty() const {
166     return ranges::all_of(
167         callbacks_, [](const auto& callback) { return callback.is_null(); });
168   }
169 
170   // Calls all registered callbacks that are not canceled beforehand. If any
171   // callbacks are unregistered, notifies any registered removal callback at the
172   // end.
173   //
174   // Arguments must be copyable, since they must be supplied to all callbacks.
175   // Move-only types would be destructively modified by passing them to the
176   // first callback and not reach subsequent callbacks as intended.
177   //
178   // Notify() may be called re-entrantly, in which case the nested call
179   // completes before the outer one continues. Callbacks are only ever added at
180   // the end and canceled callbacks are not pruned from the list until the
181   // outermost iteration completes, so existing iterators should never be
182   // invalidated. However, this does mean that a callback added during a nested
183   // call can be notified by outer calls -- meaning it will be notified about
184   // things that happened before it was added -- if its subscription outlives
185   // the reentrant Notify() call.
186   template <typename... RunArgs>
187   void Notify(RunArgs&&... args) {
188     if (empty())
189       return;  // Nothing to do.
190 
191     {
192       AutoReset<bool> iterating(&iterating_, true);
193 
194       // Skip any callbacks that are canceled during iteration.
195       // NOTE: Since RunCallback() may call Add(), it's not safe to cache the
196       // value of callbacks_.end() across loop iterations.
197       const auto next_valid = [this](const auto it) {
198         return std::find_if_not(it, callbacks_.end(), [](const auto& callback) {
199           return callback.is_null();
200         });
201       };
202       for (auto it = next_valid(callbacks_.begin()); it != callbacks_.end();
203            it = next_valid(it))
204         // NOTE: Intentionally does not call std::forward<RunArgs>(args)...,
205         // since that would allow move-only arguments.
206         static_cast<CallbackListImpl*>(this)->RunCallback(it++, args...);
207     }
208 
209     // Re-entrant invocations shouldn't prune anything from the list. This can
210     // invalidate iterators from underneath higher call frames. It's safe to
211     // simply do nothing, since the outermost frame will continue through here
212     // and prune all null callbacks below.
213     if (iterating_)
214       return;
215 
216     // Any null callbacks remaining in the list were canceled due to
217     // Subscription destruction during iteration, and can safely be erased now.
218     const size_t erased_callbacks =
219         EraseIf(callbacks_, [](const auto& cb) { return cb.is_null(); });
220 
221     // Run |removal_callback_| if any callbacks were canceled. Note that we
222     // cannot simply compare list sizes before and after iterating, since
223     // notification may result in Add()ing new callbacks as well as canceling
224     // them. Also note that if this is a OnceCallbackList, the OnceCallbacks
225     // that were executed above have all been removed regardless of whether
226     // they're counted in |erased_callbacks_|.
227     if (removal_callback_ &&
228         (erased_callbacks || IsOnceCallback<CallbackType>::value))
229       removal_callback_.Run();  // May delete |this|!
230   }
231 
232  protected:
233   using Callbacks = typename CallbackListTraits<CallbackListImpl>::Callbacks;
234 
235   // Holds non-null callbacks, which will be called during Notify().
236   Callbacks callbacks_;
237 
238  private:
239   // Cancels the callback pointed to by |it|, which is guaranteed to be valid.
240   void CancelCallback(const typename Callbacks::iterator& it) {
241     if (static_cast<CallbackListImpl*>(this)->CancelNullCallback(it))
242       return;
243 
244     if (iterating_) {
245       // Calling erase() here is unsafe, since the loop in Notify() may be
246       // referencing this same iterator, e.g. if adjacent callbacks'
247       // Subscriptions are both destroyed when the first one is Run().  Just
248       // reset the callback and let Notify() clean it up at the end.
249       it->Reset();
250     } else {
251       callbacks_.erase(it);
252       if (removal_callback_)
253         removal_callback_.Run();  // May delete |this|!
254     }
255   }
256 
257   // Set while Notify() is traversing |callbacks_|.  Used primarily to avoid
258   // invalidating iterators that may be in use.
259   bool iterating_ = false;
260 
261   // Called after elements are removed from |callbacks_|.
262   RepeatingClosure removal_callback_;
263 
264   WeakPtrFactory<CallbackListBase> weak_ptr_factory_{this};
265 };
266 
267 }  // namespace internal
268 
269 template <typename Signature>
270 class OnceCallbackList
271     : public internal::CallbackListBase<OnceCallbackList<Signature>> {
272  private:
273   friend internal::CallbackListBase<OnceCallbackList>;
274   using Traits = internal::CallbackListTraits<OnceCallbackList>;
275 
276   // Runs the current callback, which may cancel it or any other callbacks.
277   template <typename... RunArgs>
278   void RunCallback(typename Traits::Callbacks::iterator it, RunArgs&&... args) {
279     // OnceCallbacks still have Subscriptions with outstanding iterators;
280     // splice() removes them from |callbacks_| without invalidating those.
281     null_callbacks_.splice(null_callbacks_.end(), this->callbacks_, it);
282 
283     // NOTE: Intentionally does not call std::forward<RunArgs>(args)...; see
284     // comments in Notify().
285     std::move(*it).Run(args...);
286   }
287 
288   // If |it| refers to an already-canceled callback, does any necessary cleanup
289   // and returns true.  Otherwise returns false.
290   bool CancelNullCallback(const typename Traits::Callbacks::iterator& it) {
291     if (it->is_null()) {
292       null_callbacks_.erase(it);
293       return true;
294     }
295     return false;
296   }
297 
298   // Holds null callbacks whose Subscriptions are still alive, so the
299   // Subscriptions will still contain valid iterators.  Only needed for
300   // OnceCallbacks, since RepeatingCallbacks are not canceled except by
301   // Subscription destruction.
302   typename Traits::Callbacks null_callbacks_;
303 };
304 
305 template <typename Signature>
306 class RepeatingCallbackList
307     : public internal::CallbackListBase<RepeatingCallbackList<Signature>> {
308  private:
309   friend internal::CallbackListBase<RepeatingCallbackList>;
310   using Traits = internal::CallbackListTraits<RepeatingCallbackList>;
311   // Runs the current callback, which may cancel it or any other callbacks.
312   template <typename... RunArgs>
313   void RunCallback(typename Traits::Callbacks::iterator it, RunArgs&&... args) {
314     // NOTE: Intentionally does not call std::forward<RunArgs>(args)...; see
315     // comments in Notify().
316     it->Run(args...);
317   }
318 
319   // If |it| refers to an already-canceled callback, does any necessary cleanup
320   // and returns true.  Otherwise returns false.
321   bool CancelNullCallback(const typename Traits::Callbacks::iterator& it) {
322     // Because at most one Subscription can point to a given callback, and
323     // RepeatingCallbacks are only reset by CancelCallback(), no one should be
324     // able to request cancellation of a canceled RepeatingCallback.
325     DCHECK(!it->is_null());
326     return false;
327   }
328 };
329 
330 template <typename Signature>
331 using CallbackList = RepeatingCallbackList<Signature>;
332 
333 // Syntactic sugar to parallel that used for Callbacks.
334 using OnceClosureList = OnceCallbackList<void()>;
335 using RepeatingClosureList = RepeatingCallbackList<void()>;
336 using ClosureList = CallbackList<void()>;
337 
338 }  // namespace base
339 
340 #endif  // BASE_CALLBACK_LIST_H_
341