callback_list.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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/compiler_specific.h"
  15. #include "base/logging.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()).
  55. // std::unique_ptr<MyWidget::CallbackList::Subscription> foo_subscription_ =
  56. // MyWidget::Get()->RegisterCallback(
  57. // base::BindRepeating(&MyWidgetListener::OnFoo, this));
  58. // };
  59. //
  60. // UNSUPPORTED:
  61. //
  62. // * Calling Notify() reentrantly during callback notification.
  63. // * Destroying the CallbackList during callback notification.
  64. //
  65. // Both of these are possible to support, but not currently necessary.
  66. namespace base {
  67. template <typename Signature>
  68. class OnceCallbackList;
  69. template <typename Signature>
  70. class RepeatingCallbackList;
  71. namespace internal {
  72. // A traits class to break circular type dependencies between CallbackListBase
  73. // and its subclasses.
  74. template <typename CallbackList>
  75. struct CallbackListTraits;
  76. template <typename Signature>
  77. struct CallbackListTraits<OnceCallbackList<Signature>> {
  78. using CallbackType = OnceCallback<Signature>;
  79. using Callbacks = std::list<CallbackType>;
  80. };
  81. template <typename Signature>
  82. struct CallbackListTraits<RepeatingCallbackList<Signature>> {
  83. using CallbackType = RepeatingCallback<Signature>;
  84. using Callbacks = std::list<CallbackType>;
  85. };
  86. template <typename CallbackListImpl>
  87. class CallbackListBase {
  88. public:
  89. using CallbackType =
  90. typename CallbackListTraits<CallbackListImpl>::CallbackType;
  91. static_assert(IsBaseCallback<CallbackType>::value, "");
  92. // A cancellation handle for callers who register callbacks. Subscription
  93. // destruction cancels the associated callback and is legal any time,
  94. // including after the destruction of the CallbackList that vends it.
  95. class Subscription {
  96. public:
  97. explicit Subscription(base::OnceClosure destruction_closure)
  98. : destruction_closure_(std::move(destruction_closure)) {}
  99. Subscription(const Subscription&) = delete;
  100. Subscription& operator=(const Subscription&) = delete;
  101. ~Subscription() { std::move(destruction_closure_).Run(); }
  102. private:
  103. // Run when |this| is destroyed to notify the CallbackList the associated
  104. // callback should be canceled. Since this is bound using a WeakPtr to the
  105. // CallbackList, it will automatically no-op if the CallbackList no longer
  106. // exists.
  107. base::OnceClosure destruction_closure_;
  108. };
  109. CallbackListBase() = default;
  110. CallbackListBase(const CallbackListBase&) = delete;
  111. CallbackListBase& operator=(const CallbackListBase&) = delete;
  112. ~CallbackListBase() {
  113. // Destroying the list during iteration is unsupported and will cause a UAF.
  114. CHECK(!iterating_);
  115. }
  116. // Registers |cb| for future notifications. Returns a Subscription that can be
  117. // used to cancel |cb|.
  118. std::unique_ptr<Subscription> Add(CallbackType cb) WARN_UNUSED_RESULT {
  119. DCHECK(!cb.is_null());
  120. return std::make_unique<Subscription>(base::BindOnce(
  121. &CallbackListBase::CancelCallback, weak_ptr_factory_.GetWeakPtr(),
  122. callbacks_.insert(callbacks_.end(), std::move(cb))));
  123. }
  124. // Registers |removal_callback| to be run after elements are removed from the
  125. // list of registered callbacks.
  126. void set_removal_callback(const RepeatingClosure& removal_callback) {
  127. removal_callback_ = removal_callback;
  128. }
  129. // Returns whether the list of registered callbacks is empty. This may not be
  130. // called while Notify() is traversing the list (since the results could be
  131. // inaccurate).
  132. bool empty() const {
  133. DCHECK(!iterating_);
  134. return callbacks_.empty();
  135. }
  136. // Calls all registered callbacks that are not canceled beforehand. If any
  137. // callbacks are unregistered, notifies any registered removal callback at the
  138. // end.
  139. template <typename... RunArgs>
  140. void Notify(RunArgs&&... args) {
  141. // Calling Notify() reentrantly is currently unsupported.
  142. DCHECK(!iterating_);
  143. if (empty())
  144. return; // Nothing to do.
  145. // Canceled callbacks should be removed from the list whenever notification
  146. // isn't in progress, so right now all callbacks should be valid.
  147. const auto callback_valid = [](const auto& cb) { return !cb.is_null(); };
  148. DCHECK(std::all_of(callbacks_.cbegin(), callbacks_.cend(), callback_valid));
  149. {
  150. AutoReset<bool> iterating(&iterating_, true);
  151. // Skip any callbacks that are canceled during iteration.
  152. for (auto it = callbacks_.begin(); it != callbacks_.end();
  153. it = std::find_if(it, callbacks_.end(), callback_valid))
  154. static_cast<CallbackListImpl*>(this)->RunCallback(it++, args...);
  155. }
  156. // Any null callbacks remaining in the list were canceled due to
  157. // Subscription destruction during iteration, and can safely be erased now.
  158. const size_t erased_callbacks =
  159. EraseIf(callbacks_, [](const auto& cb) { return cb.is_null(); });
  160. // Run |removal_callback_| if any callbacks were canceled. Note that we
  161. // cannot simply compare list sizes before and after iterating, since
  162. // notification may result in Add()ing new callbacks as well as canceling
  163. // them. Also note that if this is a OnceCallbackList, the OnceCallbacks
  164. // that were executed above have all been removed regardless of whether
  165. // they're counted in |erased_callbacks_|.
  166. if (removal_callback_ &&
  167. (erased_callbacks || IsOnceCallback<CallbackType>::value))
  168. removal_callback_.Run(); // May delete |this|!
  169. }
  170. protected:
  171. using Callbacks = typename CallbackListTraits<CallbackListImpl>::Callbacks;
  172. // Holds non-null callbacks, which will be called during Notify().
  173. Callbacks callbacks_;
  174. private:
  175. // Cancels the callback pointed to by |it|, which is guaranteed to be valid.
  176. void CancelCallback(const typename Callbacks::iterator& it) {
  177. if (static_cast<CallbackListImpl*>(this)->CancelNullCallback(it))
  178. return;
  179. if (iterating_) {
  180. // Calling erase() here is unsafe, since the loop in Notify() may be
  181. // referencing this same iterator, e.g. if adjacent callbacks'
  182. // Subscriptions are both destroyed when the first one is Run(). Just
  183. // reset the callback and let Notify() clean it up at the end.
  184. it->Reset();
  185. } else {
  186. callbacks_.erase(it);
  187. if (removal_callback_)
  188. removal_callback_.Run(); // May delete |this|!
  189. }
  190. }
  191. // Set while Notify() is traversing |callbacks_|. Used primarily to avoid
  192. // invalidating iterators that may be in use.
  193. bool iterating_ = false;
  194. // Called after elements are removed from |callbacks_|.
  195. RepeatingClosure removal_callback_;
  196. WeakPtrFactory<CallbackListBase> weak_ptr_factory_{this};
  197. };
  198. } // namespace internal
  199. template <typename Signature>
  200. class OnceCallbackList
  201. : public internal::CallbackListBase<OnceCallbackList<Signature>> {
  202. private:
  203. friend internal::CallbackListBase<OnceCallbackList>;
  204. using Traits = internal::CallbackListTraits<OnceCallbackList>;
  205. // Runs the current callback, which may cancel it or any other callbacks.
  206. template <typename... RunArgs>
  207. void RunCallback(typename Traits::Callbacks::iterator it, RunArgs&&... args) {
  208. // OnceCallbacks still have Subscriptions with outstanding iterators;
  209. // splice() removes them from |callbacks_| without invalidating those.
  210. null_callbacks_.splice(null_callbacks_.end(), this->callbacks_, it);
  211. std::move(*it).Run(args...);
  212. }
  213. // If |it| refers to an already-canceled callback, does any necessary cleanup
  214. // and returns true. Otherwise returns false.
  215. bool CancelNullCallback(const typename Traits::Callbacks::iterator& it) {
  216. if (it->is_null()) {
  217. null_callbacks_.erase(it);
  218. return true;
  219. }
  220. return false;
  221. }
  222. // Holds null callbacks whose Subscriptions are still alive, so the
  223. // Subscriptions will still contain valid iterators. Only needed for
  224. // OnceCallbacks, since RepeatingCallbacks are not canceled except by
  225. // Subscription destruction.
  226. typename Traits::Callbacks null_callbacks_;
  227. };
  228. template <typename Signature>
  229. class RepeatingCallbackList
  230. : public internal::CallbackListBase<RepeatingCallbackList<Signature>> {
  231. private:
  232. friend internal::CallbackListBase<RepeatingCallbackList>;
  233. using Traits = internal::CallbackListTraits<RepeatingCallbackList>;
  234. // Runs the current callback, which may cancel it or any other callbacks.
  235. template <typename... RunArgs>
  236. void RunCallback(typename Traits::Callbacks::iterator it, RunArgs&&... args) {
  237. it->Run(args...);
  238. }
  239. // If |it| refers to an already-canceled callback, does any necessary cleanup
  240. // and returns true. Otherwise returns false.
  241. bool CancelNullCallback(const typename Traits::Callbacks::iterator& it) {
  242. // Because at most one Subscription can point to a given callback, and
  243. // RepeatingCallbacks are only reset by CancelCallback(), no one should be
  244. // able to request cancellation of a canceled RepeatingCallback.
  245. DCHECK(!it->is_null());
  246. return false;
  247. }
  248. };
  249. template <typename Signature>
  250. using CallbackList = RepeatingCallbackList<Signature>;
  251. // Syntactic sugar to parallel that used for Callbacks.
  252. using OnceClosureList = OnceCallbackList<void()>;
  253. using RepeatingClosureList = RepeatingCallbackList<void()>;
  254. using ClosureList = CallbackList<void()>;
  255. } // namespace base
  256. #endif // BASE_CALLBACK_LIST_H_