callback_list.h 13 KB

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