callback_list.h 13 KB

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