sequence_bound.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // Copyright 2018 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_THREADING_SEQUENCE_BOUND_H_
  5. #define BASE_THREADING_SEQUENCE_BOUND_H_
  6. #include <new>
  7. #include <type_traits>
  8. #include "base/bind.h"
  9. #include "base/callback.h"
  10. #include "base/compiler_specific.h"
  11. #include "base/location.h"
  12. #include "base/memory/aligned_memory.h"
  13. #include "base/memory/ptr_util.h"
  14. #include "base/sequenced_task_runner.h"
  15. namespace base {
  16. // SequenceBound facilitates owning objects that live on a specified sequence,
  17. // which is potentially different than the owner's sequence. It encapsulates
  18. // the work of posting tasks to the specified sequence to construct T, call
  19. // methods on T, and destroy T.
  20. //
  21. // It does not provide explicit access to the underlying object directly, to
  22. // prevent accidentally using it from the wrong sequence.
  23. //
  24. // Like std::unique_ptr<T>, a SequenceBound<T> may be moved between owners,
  25. // and posted across threads. It may also be up-casted (only), to permit
  26. // SequenceBound to be used with interfaces.
  27. //
  28. // Basic usage looks like this:
  29. //
  30. // // Some class that lives on |main_task_runner|.
  31. // class MyClass {
  32. // public:
  33. // explicit MyClass(const char* widget_title) {}
  34. // virtual ~MyClass() { ... }
  35. // virtual void DoSomething(int arg) { ... }
  36. // };
  37. //
  38. // // On any thread...
  39. // scoped_refptr<SequencedTaskRunner> main_task_runner = ...;
  40. // auto widget = SequenceBound<MyClass>(main_task_runner, "My Title");
  41. //
  42. // // Execute a single method on the object, on |main_task_runner|.
  43. // widget.Post(FROM_HERE, &MyClass::DoSomething, 1234);
  44. //
  45. // // Execute an arbitrary task on |main_task_runner| with a non-const pointer
  46. // // to the object.
  47. // widget.PostTaskWithThisObject(
  48. // FROM_HERE,
  49. // base::BindOnce([](MyClass* widget) {
  50. // // Unlike with Post, we can issue multiple calls on |widget| within
  51. // // the same stack frame.
  52. // widget->DoSomething(42);
  53. // widget->DoSomething(13);
  54. // }));
  55. //
  56. // // Execute an arbitrary task on |main_task_runner| with a const reference
  57. // // to the object.
  58. // widget.PostTaskWithThisObject(
  59. // FROM_HERE,
  60. // base::BindOnce([](const MyClass& widget) { ... }));
  61. //
  62. // Note that |widget| is constructed asynchronously on |main_task_runner|,
  63. // but calling Post() immediately is safe, since the actual call is posted
  64. // to |main_task_runner| as well.
  65. //
  66. // |widget| will be deleted on |main_task_runner| asynchronously when it goes
  67. // out of scope, or when Reset() is called.
  68. //
  69. // Here is a more complicated example that shows injection and upcasting:
  70. //
  71. // // Some unrelated class that uses a |MyClass| to do something.
  72. // class SomeConsumer {
  73. // public:
  74. // // Note that ownership of |widget| is given to us!
  75. // explicit SomeConsumer(SequenceBound<MyClass> widget)
  76. // : widget_(std::move(widget)) { ... }
  77. //
  78. // ~SomeConsumer() {
  79. // // |widget_| will be destroyed on the associated task runner.
  80. // }
  81. //
  82. // SequenceBound<MyClass> widget_;
  83. // };
  84. //
  85. // // Implementation of MyClass.
  86. // class MyDerivedClass : public MyClass { ... };
  87. //
  88. // auto widget =
  89. // SequenceBound<MyDerivedClass>(main_task_runner, ctor args);
  90. // auto c = new SomeConsumer(std::move(widget)); // upcasts to MyClass
  91. namespace internal {
  92. // If we can't cast |Base*| into |Derived*|, then it's a virtual base if and
  93. // only if |Base| is actually a base class of |Derived|. Otherwise (including
  94. // unrelated types), it isn't. We default to Derived* so that the
  95. // specialization below will apply when the cast to |Derived*| is valid.
  96. template <typename Base, typename Derived, typename = Derived*>
  97. struct is_virtual_base_of : public std::is_base_of<Base, Derived> {};
  98. // If we can cast |Base*| into |Derived*|, then it's definitely not a virtual
  99. // base. When this happens, we'll match the default third template argument.
  100. template <typename Base, typename Derived>
  101. struct is_virtual_base_of<Base,
  102. Derived,
  103. decltype(static_cast<Derived*>(
  104. static_cast<Base*>(nullptr)))> : std::false_type {
  105. };
  106. } // namespace internal
  107. template <typename T>
  108. class SequenceBound {
  109. public:
  110. // Allow explicit null.
  111. SequenceBound() = default;
  112. // Construct a new instance of |T| that will be accessed only on
  113. // |task_runner|. One may post calls to it immediately upon return.
  114. // This is marked as NO_SANITIZE because cfi doesn't like that we're casting
  115. // uninitialized memory to a |T*|. However, it's safe since (a) the cast is
  116. // defined (see http://eel.is/c++draft/basic.life#6 for details), and (b) we
  117. // don't use the resulting pointer in any way that requries it to be
  118. // constructed, except by posting such a access to |impl_task_runner_| after
  119. // posting construction there as well.
  120. template <typename... Args>
  121. NO_SANITIZE("cfi-unrelated-cast")
  122. SequenceBound(scoped_refptr<base::SequencedTaskRunner> task_runner,
  123. Args&&... args)
  124. : impl_task_runner_(std::move(task_runner)) {
  125. // Allocate space for but do not construct an instance of |T|.
  126. storage_ = AlignedAlloc(sizeof(T), alignof(T));
  127. t_ = reinterpret_cast<T*>(storage_);
  128. // Post construction to the impl thread.
  129. impl_task_runner_->PostTask(
  130. FROM_HERE,
  131. base::BindOnce(&ConstructOwnerRecord<Args...>, base::Unretained(t_),
  132. std::forward<Args>(args)...));
  133. }
  134. ~SequenceBound() { Reset(); }
  135. // Move construction from the same type can just take the pointer without
  136. // adjusting anything. This is required in addition to the move conversion
  137. // constructor below.
  138. SequenceBound(SequenceBound&& other) { MoveRecordFrom(other); }
  139. // Move construction is supported from any type that's compatible with |T|.
  140. // This case handles |From| != |T|, so we must adjust the pointer offset.
  141. template <typename From>
  142. SequenceBound(SequenceBound<From>&& other) {
  143. MoveRecordFrom(other);
  144. }
  145. SequenceBound& operator=(SequenceBound&& other) {
  146. // Clean up any object we currently own.
  147. Reset();
  148. MoveRecordFrom(other);
  149. return *this;
  150. }
  151. template <typename From>
  152. SequenceBound<T>& operator=(SequenceBound<From>&& other) {
  153. // Clean up any object that we currently own.
  154. Reset();
  155. MoveRecordFrom(other);
  156. return *this;
  157. }
  158. // Post a call to |method| to |impl_task_runner_|.
  159. template <typename... MethodArgs, typename... Args>
  160. void Post(const base::Location& from_here,
  161. void (T::*method)(MethodArgs...),
  162. Args&&... args) const {
  163. DCHECK(t_);
  164. impl_task_runner_->PostTask(from_here,
  165. base::BindOnce(method, base::Unretained(t_),
  166. std::forward<Args>(args)...));
  167. }
  168. // Posts |task| to |impl_task_runner_|, passing it a reference to the wrapped
  169. // object. This allows arbitrary logic to be safely executed on the object's
  170. // task runner. The object is guaranteed to remain alive for the duration of
  171. // the task.
  172. using ConstPostTaskCallback = base::OnceCallback<void(const T&)>;
  173. void PostTaskWithThisObject(const base::Location& from_here,
  174. ConstPostTaskCallback callback) const {
  175. DCHECK(t_);
  176. impl_task_runner_->PostTask(
  177. from_here,
  178. base::BindOnce([](ConstPostTaskCallback callback,
  179. const T* t) { std::move(callback).Run(*t); },
  180. std::move(callback), t_));
  181. }
  182. // Same as above, but for non-const operations. The callback takes a pointer
  183. // to the wrapped object rather than a const ref.
  184. using PostTaskCallback = base::OnceCallback<void(T*)>;
  185. void PostTaskWithThisObject(const base::Location& from_here,
  186. PostTaskCallback callback) const {
  187. DCHECK(t_);
  188. impl_task_runner_->PostTask(from_here,
  189. base::BindOnce(std::move(callback), t_));
  190. }
  191. // TODO(liberato): Add PostOrCall(), to support cases where synchronous calls
  192. // are okay if it's the same task runner.
  193. // TODO(liberato): Add PostAndReply()
  194. // TODO(liberato): Allow creation of callbacks that bind to a weak pointer,
  195. // and thread-hop to |impl_task_runner_| if needed.
  196. // Post destruction of any object we own, and return to the null state.
  197. void Reset() {
  198. if (is_null())
  199. return;
  200. // Destruct the object on the impl thread.
  201. impl_task_runner_->PostTask(
  202. FROM_HERE, base::BindOnce(&DeleteOwnerRecord, base::Unretained(t_),
  203. base::Unretained(storage_)));
  204. impl_task_runner_ = nullptr;
  205. t_ = nullptr;
  206. storage_ = nullptr;
  207. }
  208. // Same as above, but allows the caller to provide a closure to be invoked
  209. // immediately after destruction. The Closure is invoked on
  210. // |impl_task_runner_|, iff the owned object was non-null.
  211. void ResetWithCallbackAfterDestruction(base::OnceClosure callback) {
  212. if (is_null())
  213. return;
  214. impl_task_runner_->PostTask(
  215. FROM_HERE, base::BindOnce(
  216. [](base::OnceClosure callback, T* t, void* storage) {
  217. DeleteOwnerRecord(t, storage);
  218. std::move(callback).Run();
  219. },
  220. std::move(callback), t_, storage_));
  221. impl_task_runner_ = nullptr;
  222. t_ = nullptr;
  223. storage_ = nullptr;
  224. }
  225. // Return whether we own anything. Note that this does not guarantee that any
  226. // previously owned object has been destroyed. In particular, it will return
  227. // true immediately after a call to Reset(), though the underlying object
  228. // might still be pending destruction on the impl thread.
  229. bool is_null() const { return !t_; }
  230. // True if and only if we have an object, with the same caveats as is_null().
  231. explicit operator bool() const { return !is_null(); }
  232. private:
  233. // Move everything from |other|, doing pointer adjustment as needed.
  234. // This method is marked as NO_SANITIZE since (a) it might run before the
  235. // posted ctor runs on |impl_task_runner_|, and (b) implicit conversions to
  236. // non-virtual base classes are allowed before construction by the standard.
  237. // See http://eel.is/c++draft/basic.life#6 for more information.
  238. template <typename From>
  239. void NO_SANITIZE("cfi-unrelated-cast") MoveRecordFrom(From&& other) {
  240. // |other| might be is_null(), but that's okay.
  241. impl_task_runner_ = std::move(other.impl_task_runner_);
  242. // Note that static_cast<> isn't, in general, safe, since |other| might not
  243. // be constructed yet. Implicit conversion is supported, as long as it
  244. // doesn't convert to a virtual base. Of course, it allows only upcasts.
  245. t_ = other.t_;
  246. // The original storage is kept unmodified, so we can free it later.
  247. storage_ = other.storage_;
  248. other.storage_ = nullptr;
  249. other.t_ = nullptr;
  250. }
  251. // Pointer to the object, Pointer may be modified on the owning thread.
  252. T* t_ = nullptr;
  253. // Original allocated storage for the object.
  254. void* storage_ = nullptr;
  255. // The task runner on which all access to |t_| should happen.
  256. scoped_refptr<base::SequencedTaskRunner> impl_task_runner_;
  257. // For move conversion.
  258. template <typename U>
  259. friend class SequenceBound;
  260. // Run on impl thread to construct |t|'s storage.
  261. template <typename... Args>
  262. static void ConstructOwnerRecord(T* t, std::decay_t<Args>&&... args) {
  263. new (t) T(std::move(args)...);
  264. }
  265. // Destruct the object associated with |t|, and delete |storage|.
  266. static void DeleteOwnerRecord(T* t, void* storage) {
  267. t->~T();
  268. AlignedFree(storage);
  269. }
  270. // To preserve ownership semantics, we disallow copy construction / copy
  271. // assignment. Move construction / assignment is fine.
  272. DISALLOW_COPY_AND_ASSIGN(SequenceBound);
  273. };
  274. } // namespace base
  275. #endif // BASE_THREADING_SEQUENCE_BOUND_H_