sequence_bound.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  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 <tuple>
  8. #include <type_traits>
  9. #include <utility>
  10. #include "base/bind.h"
  11. #include "base/callback.h"
  12. #include "base/callback_helpers.h"
  13. #include "base/compiler_specific.h"
  14. #include "base/location.h"
  15. #include "base/memory/aligned_memory.h"
  16. #include "base/memory/ptr_util.h"
  17. #include "base/sequence_checker.h"
  18. #include "base/sequenced_task_runner.h"
  19. #include "base/threading/sequence_bound_internal.h"
  20. #include "base/threading/sequenced_task_runner_handle.h"
  21. namespace base {
  22. // Performing blocking work on a different task runner is a common pattern for
  23. // improving responsiveness of foreground task runners. `SequenceBound<T>`
  24. // provides an abstraction for an owner object living on the owner sequence, to
  25. // construct, call methods on, and destroy an object of type T that lives on a
  26. // different sequence (the bound sequence).
  27. //
  28. // This makes it natural for code running on different sequences to be
  29. // partitioned along class boundaries, e.g.:
  30. //
  31. // class Tab {
  32. // private:
  33. // void OnScroll() {
  34. // // ...
  35. // io_helper_.AsyncCall(&IOHelper::SaveScrollPosition);
  36. // }
  37. // SequenceBound<IOHelper> io_helper_{GetBackgroundTaskRunner()};
  38. // };
  39. //
  40. // Note: `SequenceBound<T>` intentionally does not expose a raw pointer to the
  41. // managed `T` to ensure its internal sequence-safety invariants are not
  42. // violated. As a result, `AsyncCall()` cannot simply use `base::OnceCallback`
  43. //
  44. // SequenceBound also supports replies:
  45. //
  46. // class Database {
  47. // public:
  48. // int Query(int value) {
  49. // return value * value;
  50. // }
  51. // };
  52. //
  53. // // SequenceBound itself is owned on `SequencedTaskRunnerHandle::Get()`.
  54. // // The managed Database instance managed by it is constructed and owned on
  55. // // `GetDBTaskRunner()`.
  56. // SequenceBound<Database> db(GetDBTaskRunner());
  57. //
  58. // // `Database::Query()` runs on `GetDBTaskRunner()`, but
  59. // // `reply_callback` will run on the owner task runner.
  60. // auto reply_callback = [] (int result) {
  61. // LOG(ERROR) << result; // Prints 25.
  62. // };
  63. // db.AsyncCall(&Database::Query).WithArgs(5)
  64. // .Then(base::BindOnce(reply_callback));
  65. //
  66. // // When `db` goes out of scope, the Database instance will also be
  67. // // destroyed via a task posted to `GetDBTaskRunner()`.
  68. //
  69. // TODO(dcheng): SequenceBound should only be constructed, used, and destroyed
  70. // on a single sequence. This enforcement will gradually be enabled over time.
  71. template <typename T>
  72. class SequenceBound {
  73. public:
  74. // Note: on construction, SequenceBound binds to the current sequence. Any
  75. // subsequent SequenceBound calls (including destruction) must run on that
  76. // same sequence.
  77. // Constructs a null SequenceBound with no managed `T`.
  78. // TODO(dcheng): Add an `Emplace()` method to go with `Reset()`.
  79. SequenceBound() = default;
  80. // Schedules asynchronous construction of a new instance of `T` on
  81. // `task_runner`.
  82. //
  83. // Once the SequenceBound constructor completes, the caller can immediately
  84. // use `AsyncCall()`, et cetera, to schedule work after the construction of
  85. // `T` on `task_runner`.
  86. //
  87. // Marked NO_SANITIZE because cfi doesn't like casting uninitialized memory to
  88. // `T*`. However, this is safe here because:
  89. //
  90. // 1. The cast is well-defined (see https://eel.is/c++draft/basic.life#6) and
  91. // 2. The resulting pointer is only ever dereferenced on `impl_task_runner_`.
  92. // By the time SequenceBound's constructor returns, the task to construct
  93. // `T` will already be posted; thus, subsequent dereference of `t_` on
  94. // `impl_task_runner_` are safe.
  95. template <typename... Args>
  96. NO_SANITIZE("cfi-unrelated-cast")
  97. SequenceBound(scoped_refptr<base::SequencedTaskRunner> task_runner,
  98. Args&&... args)
  99. : impl_task_runner_(std::move(task_runner)) {
  100. // Allocate space for but do not construct an instance of `T`.
  101. // AlignedAlloc() requires alignment be a multiple of sizeof(void*).
  102. storage_ = AlignedAlloc(
  103. sizeof(T), sizeof(void*) > alignof(T) ? sizeof(void*) : alignof(T));
  104. t_ = reinterpret_cast<T*>(storage_);
  105. // Ensure that `t_` will be initialized
  106. impl_task_runner_->PostTask(
  107. FROM_HERE,
  108. base::BindOnce(&ConstructOwnerRecord<Args...>, base::Unretained(t_),
  109. std::forward<Args>(args)...));
  110. }
  111. // If non-null, destruction of the managed `T` is posted to
  112. // `impl_task_runner_`.`
  113. ~SequenceBound() { Reset(); }
  114. // Disallow copy or assignment. SequenceBound has single ownership of the
  115. // managed `T`.
  116. SequenceBound(const SequenceBound&) = delete;
  117. SequenceBound& operator=(const SequenceBound&) = delete;
  118. // Move construction and assignment.
  119. SequenceBound(SequenceBound&& other) { MoveRecordFrom(other); }
  120. SequenceBound& operator=(SequenceBound&& other) {
  121. Reset();
  122. MoveRecordFrom(other);
  123. return *this;
  124. }
  125. // Move conversion helpers: allows upcasting from SequenceBound<Derived> to
  126. // SequenceBound<Base>.
  127. template <typename From>
  128. SequenceBound(SequenceBound<From>&& other) {
  129. MoveRecordFrom(other);
  130. }
  131. template <typename From>
  132. SequenceBound<T>& operator=(SequenceBound<From>&& other) {
  133. Reset();
  134. MoveRecordFrom(other);
  135. return *this;
  136. }
  137. // Invokes `method` of the managed `T` on `impl_task_runner_`. May only be
  138. // used when `is_null()` is false.
  139. //
  140. // Basic usage:
  141. //
  142. // helper.AsyncCall(&IOHelper::DoWork);
  143. //
  144. // If `method` accepts arguments, use of `WithArgs()` to bind them is
  145. // mandatory:
  146. //
  147. // helper.AsyncCall(&IOHelper::DoWorkWithArgs).WithArgs(args);
  148. //
  149. // Optionally, use `Then()` to chain to a callback on the owner sequence after
  150. // `method` completes. If `method` returns a non-void type, the return value
  151. // will be passed to the chained callback.
  152. //
  153. // helper.AsyncCall(&IOHelper::GetValue).Then(std::move(process_result));
  154. //
  155. // `WithArgs()` and `Then()` may also be combined:
  156. //
  157. // helper.AsyncCall(&IOHelper::GetValueWithArgs).WithArgs(args)
  158. // .Then(std::move(process_result));
  159. //
  160. // but note that ordering is strict: `Then()` must always be last.
  161. //
  162. // Note: internally, this is implemented using a series of templated builders.
  163. // Destruction of the builder may trigger task posting; as a result, using the
  164. // builder as anything other than a temporary is not allowed.
  165. //
  166. // Similarly, triggering lifetime extension of the temporary (e.g. by binding
  167. // to a const lvalue reference) is not allowed.
  168. template <typename R, typename... Args>
  169. auto AsyncCall(R (T::*method)(Args...),
  170. const Location& location = Location::Current()) {
  171. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  172. return AsyncCallBuilder<R (T::*)(Args...)>(this, &location, method);
  173. }
  174. template <typename R, typename... Args>
  175. auto AsyncCall(R (T::*method)(Args...) const,
  176. const Location& location = Location::Current()) {
  177. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  178. return AsyncCallBuilder<R (T::*)(Args...) const>(this, &location, method);
  179. }
  180. // Post a call to `method` to `impl_task_runner_`.
  181. // TODO(dcheng): Deprecate this in favor of `AsyncCall()`.
  182. template <typename... MethodArgs, typename... Args>
  183. void Post(const base::Location& from_here,
  184. void (T::*method)(MethodArgs...),
  185. Args&&... args) const {
  186. DCHECK(t_);
  187. impl_task_runner_->PostTask(from_here,
  188. base::BindOnce(method, base::Unretained(t_),
  189. std::forward<Args>(args)...));
  190. }
  191. // Posts `task` to `impl_task_runner_`, passing it a reference to the wrapped
  192. // object. This allows arbitrary logic to be safely executed on the object's
  193. // task runner. The object is guaranteed to remain alive for the duration of
  194. // the task.
  195. using ConstPostTaskCallback = base::OnceCallback<void(const T&)>;
  196. void PostTaskWithThisObject(const base::Location& from_here,
  197. ConstPostTaskCallback callback) const {
  198. DCHECK(t_);
  199. impl_task_runner_->PostTask(
  200. from_here,
  201. base::BindOnce([](ConstPostTaskCallback callback,
  202. const T* t) { std::move(callback).Run(*t); },
  203. std::move(callback), t_));
  204. }
  205. // Same as above, but for non-const operations. The callback takes a pointer
  206. // to the wrapped object rather than a const ref.
  207. using PostTaskCallback = base::OnceCallback<void(T*)>;
  208. void PostTaskWithThisObject(const base::Location& from_here,
  209. PostTaskCallback callback) const {
  210. DCHECK(t_);
  211. impl_task_runner_->PostTask(from_here,
  212. base::BindOnce(std::move(callback), t_));
  213. }
  214. // TODO(liberato): Add PostOrCall(), to support cases where synchronous calls
  215. // are okay if it's the same task runner.
  216. // Resets `this` to null. If `this` is not currently null, posts destruction
  217. // of the managed `T` to `impl_task_runner_`.
  218. void Reset() {
  219. if (is_null())
  220. return;
  221. impl_task_runner_->PostTask(
  222. FROM_HERE, base::BindOnce(&DeleteOwnerRecord, base::Unretained(t_),
  223. base::Unretained(storage_)));
  224. impl_task_runner_ = nullptr;
  225. t_ = nullptr;
  226. storage_ = nullptr;
  227. }
  228. // Same as above, but allows the caller to provide a closure to be invoked
  229. // immediately after destruction. The Closure is invoked on
  230. // `impl_task_runner_`, iff the owned object was non-null.
  231. //
  232. // TODO(dcheng): Consider removing this; this appears to be used for test
  233. // synchronization, but that could be achieved by posting
  234. // `run_loop.QuitClosure()` to the destination sequence after calling
  235. // `Reset()`.
  236. void ResetWithCallbackAfterDestruction(base::OnceClosure callback) {
  237. if (is_null())
  238. return;
  239. impl_task_runner_->PostTask(
  240. FROM_HERE, base::BindOnce(
  241. [](base::OnceClosure callback, T* t, void* storage) {
  242. DeleteOwnerRecord(t, storage);
  243. std::move(callback).Run();
  244. },
  245. std::move(callback), t_, storage_));
  246. impl_task_runner_ = nullptr;
  247. t_ = nullptr;
  248. storage_ = nullptr;
  249. }
  250. // Return true if `this` is logically null; otherwise, returns false.
  251. //
  252. // A SequenceBound is logically null if there is no managed `T`; it is only
  253. // valid to call `AsyncCall()` on a non-null SequenceBound.
  254. //
  255. // Note that the concept of 'logically null' here does not exactly match the
  256. // lifetime of `T`, which lives on `impl_task_runner_`. In particular, when
  257. // SequenceBound is first constructed, `is_null()` may return false, even
  258. // though the lifetime of `T` may not have begun yet on `impl_task_runner_`.
  259. // Similarly, after `SequenceBound::Reset()`, `is_null()` may return true,
  260. // even though the lifetime of `T` may not have ended yet on
  261. // `impl_task_runner_`.
  262. bool is_null() const { return !t_; }
  263. // True if `this` is not logically null. See `is_null()`.
  264. explicit operator bool() const { return !is_null(); }
  265. private:
  266. // For move conversion.
  267. template <typename U>
  268. friend class SequenceBound;
  269. // Support helpers for `AsyncCall()` implementation.
  270. //
  271. // Several implementation notes:
  272. // 1. Tasks are posted via destroying the builder or an explicit call to
  273. // `Then()`.
  274. //
  275. // 2. A builder may be consumed by:
  276. //
  277. // - calling `Then()`, which immediately posts the task chain
  278. // - calling `WithArgs()`, which returns a new builder with the captured
  279. // arguments
  280. //
  281. // Builders that are consumed have the internal `sequence_bound_` field
  282. // nulled out; the hope is the compiler can see this and use it to
  283. // eliminate dead branches (e.g. correctness checks that aren't needed
  284. // since the code can be statically proved correct).
  285. //
  286. // 3. Builder methods are rvalue-qualified to try to enforce that the builder
  287. // is only used as a temporary. Note that this only helps so much; nothing
  288. // prevents a determined caller from using `std::move()` to force calls to
  289. // a non-temporary instance.
  290. //
  291. // TODO(dcheng): It might also be possible to use Gmock-style matcher
  292. // composition, e.g. something like:
  293. //
  294. // sb.AsyncCall(&Helper::DoWork, WithArgs(args),
  295. // Then(std::move(process_result));
  296. //
  297. // In theory, this might allow the elimination of magic destructors and
  298. // better static checking by the compiler.
  299. template <typename MethodPtrType>
  300. class AsyncCallBuilderBase {
  301. protected:
  302. AsyncCallBuilderBase(SequenceBound* sequence_bound,
  303. const Location* location,
  304. MethodPtrType method)
  305. : sequence_bound_(sequence_bound),
  306. location_(location),
  307. method_(method) {
  308. // Common entry point for `AsyncCall()`, so check preconditions here.
  309. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_bound_->sequence_checker_);
  310. DCHECK(sequence_bound_->t_);
  311. }
  312. AsyncCallBuilderBase(AsyncCallBuilderBase&&) = default;
  313. AsyncCallBuilderBase& operator=(AsyncCallBuilderBase&&) = default;
  314. // `sequence_bound_` is consumed and set to `nullptr` when `Then()` is
  315. // invoked. This is used as a flag for two potential states
  316. //
  317. // - if a method returns void, invoking `Then()` is optional. The destructor
  318. // will check if `sequence_bound_` is null; if it is, `Then()` was
  319. // already invoked and the task chain has already been posted, so the
  320. // destructor does not need to do anything. Otherwise, the destructor
  321. // needs to post the task to make the async call. In theory, the compiler
  322. // should be able to eliminate this branch based on the presence or
  323. // absence of a call to `Then()`.
  324. //
  325. // - if a method returns a non-void type, `Then()` *must* be invoked. The
  326. // destructor will `CHECK()` if `sequence_bound_` is non-null, since that
  327. // indicates `Then()` was not invoked. Similarly, note this branch should
  328. // be eliminated by the optimizer if the code is free of bugs. :)
  329. SequenceBound* sequence_bound_;
  330. // Subtle: this typically points at a Location *temporary*. This is used to
  331. // try to detect errors resulting from lifetime extension of the async call
  332. // factory temporaries, since the factory destructors can perform work. If
  333. // the lifetime of the factory is incorrectly extended, dereferencing
  334. // `location_` will trigger a stack-use-after-scope when running with ASan.
  335. const Location* const location_;
  336. MethodPtrType method_;
  337. };
  338. template <typename MethodPtrType, typename ReturnType, typename... Args>
  339. class AsyncCallBuilderImpl;
  340. // Selected method has no arguments and returns void.
  341. template <typename MethodPtrType>
  342. class AsyncCallBuilderImpl<MethodPtrType, void, std::tuple<>>
  343. : public AsyncCallBuilderBase<MethodPtrType> {
  344. public:
  345. // Note: despite being here, this is actually still protected, since it is
  346. // protected on the base class.
  347. using AsyncCallBuilderBase<MethodPtrType>::AsyncCallBuilderBase;
  348. ~AsyncCallBuilderImpl() {
  349. if (this->sequence_bound_) {
  350. this->sequence_bound_->impl_task_runner_->PostTask(
  351. *this->location_,
  352. BindOnce(this->method_, Unretained(this->sequence_bound_->t_)));
  353. }
  354. }
  355. void Then(OnceClosure then_callback) && {
  356. this->sequence_bound_->PostTaskAndThenHelper(
  357. *this->location_,
  358. BindOnce(this->method_, Unretained(this->sequence_bound_->t_)),
  359. std::move(then_callback));
  360. this->sequence_bound_ = nullptr;
  361. }
  362. private:
  363. friend SequenceBound;
  364. AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
  365. AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
  366. };
  367. // Selected method has no arguments and returns non-void.
  368. template <typename MethodPtrType, typename ReturnType>
  369. class AsyncCallBuilderImpl<MethodPtrType, ReturnType, std::tuple<>>
  370. : public AsyncCallBuilderBase<MethodPtrType> {
  371. public:
  372. // Note: despite being here, this is actually still protected, since it is
  373. // protected on the base class.
  374. using AsyncCallBuilderBase<MethodPtrType>::AsyncCallBuilderBase;
  375. ~AsyncCallBuilderImpl() {
  376. // Must use Then() since the method's return type is not void.
  377. // Should be optimized out if the code is bug-free.
  378. CHECK(!this->sequence_bound_)
  379. << "Then() not invoked for a method that returns a non-void type; "
  380. << "make sure to invoke Then() or use base::IgnoreResult()";
  381. }
  382. template <template <typename> class CallbackType,
  383. typename ThenArg,
  384. typename = EnableIfIsBaseCallback<CallbackType>>
  385. void Then(CallbackType<void(ThenArg)> then_callback) && {
  386. this->sequence_bound_->PostTaskAndThenHelper(
  387. *this->location_,
  388. BindOnce(this->method_, Unretained(this->sequence_bound_->t_)),
  389. std::move(then_callback));
  390. this->sequence_bound_ = nullptr;
  391. }
  392. private:
  393. friend SequenceBound;
  394. AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
  395. AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
  396. };
  397. // Selected method has arguments. Return type can be void or non-void.
  398. template <typename MethodPtrType, typename ReturnType, typename... Args>
  399. class AsyncCallBuilderImpl<MethodPtrType, ReturnType, std::tuple<Args...>>
  400. : public AsyncCallBuilderBase<MethodPtrType> {
  401. public:
  402. // Note: despite being here, this is actually still protected, since it is
  403. // protected on the base class.
  404. using AsyncCallBuilderBase<MethodPtrType>::AsyncCallBuilderBase;
  405. ~AsyncCallBuilderImpl() {
  406. // Must use WithArgs() since the method takes arguments.
  407. // Should be optimized out if the code is bug-free.
  408. CHECK(!this->sequence_bound_);
  409. }
  410. template <typename... BoundArgs>
  411. auto WithArgs(BoundArgs&&... bound_args) {
  412. SequenceBound* const sequence_bound =
  413. std::exchange(this->sequence_bound_, nullptr);
  414. return AsyncCallWithBoundArgsBuilder<ReturnType>(
  415. sequence_bound, this->location_,
  416. BindOnce(this->method_, Unretained(sequence_bound->t_),
  417. std::forward<BoundArgs>(bound_args)...));
  418. }
  419. private:
  420. friend SequenceBound;
  421. AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
  422. AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
  423. };
  424. template <typename MethodPtrType,
  425. typename R = internal::ExtractMethodReturnType<MethodPtrType>,
  426. typename ArgsTuple =
  427. internal::ExtractMethodArgsTuple<MethodPtrType>>
  428. using AsyncCallBuilder = AsyncCallBuilderImpl<MethodPtrType, R, ArgsTuple>;
  429. // Support factories when arguments are bound using `WithArgs()`. These
  430. // factories don't need to handle raw method pointers, since everything has
  431. // already been packaged into a base::OnceCallback.
  432. template <typename ReturnType>
  433. class AsyncCallWithBoundArgsBuilderBase {
  434. protected:
  435. AsyncCallWithBoundArgsBuilderBase(SequenceBound* sequence_bound,
  436. const Location* location,
  437. base::OnceCallback<ReturnType()> callback)
  438. : sequence_bound_(sequence_bound),
  439. location_(location),
  440. callback_(std::move(callback)) {
  441. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_bound_->sequence_checker_);
  442. DCHECK(sequence_bound_->t_);
  443. }
  444. // Subtle: the internal helpers rely on move elision. Preventing move
  445. // elision (e.g. using `std::move()` when returning the temporary) will
  446. // trigger a `CHECK()` since `sequence_bound_` is not reset to nullptr on
  447. // move.
  448. AsyncCallWithBoundArgsBuilderBase(
  449. AsyncCallWithBoundArgsBuilderBase&&) noexcept = default;
  450. AsyncCallWithBoundArgsBuilderBase& operator=(
  451. AsyncCallWithBoundArgsBuilderBase&&) noexcept = default;
  452. SequenceBound* sequence_bound_;
  453. const Location* const location_;
  454. base::OnceCallback<ReturnType()> callback_;
  455. };
  456. // Note: this doesn't handle a void return type, which has an explicit
  457. // specialization below.
  458. template <typename ReturnType>
  459. class AsyncCallWithBoundArgsBuilderDefault
  460. : public AsyncCallWithBoundArgsBuilderBase<ReturnType> {
  461. public:
  462. ~AsyncCallWithBoundArgsBuilderDefault() {
  463. // Must use Then() since the method's return type is not void.
  464. // Should be optimized out if the code is bug-free.
  465. CHECK(!this->sequence_bound_);
  466. }
  467. template <template <typename> class CallbackType,
  468. typename ThenArg,
  469. typename = EnableIfIsBaseCallback<CallbackType>>
  470. void Then(CallbackType<void(ThenArg)> then_callback) && {
  471. this->sequence_bound_->PostTaskAndThenHelper(*this->location_,
  472. std::move(this->callback_),
  473. std::move(then_callback));
  474. this->sequence_bound_ = nullptr;
  475. }
  476. protected:
  477. using AsyncCallWithBoundArgsBuilderBase<
  478. ReturnType>::AsyncCallWithBoundArgsBuilderBase;
  479. private:
  480. friend SequenceBound;
  481. AsyncCallWithBoundArgsBuilderDefault(
  482. AsyncCallWithBoundArgsBuilderDefault&&) = default;
  483. AsyncCallWithBoundArgsBuilderDefault& operator=(
  484. AsyncCallWithBoundArgsBuilderDefault&&) = default;
  485. };
  486. class AsyncCallWithBoundArgsBuilderVoid
  487. : public AsyncCallWithBoundArgsBuilderBase<void> {
  488. public:
  489. // Note: despite being here, this is actually still protected, since it is
  490. // protected on the base class.
  491. using AsyncCallWithBoundArgsBuilderBase<
  492. void>::AsyncCallWithBoundArgsBuilderBase;
  493. ~AsyncCallWithBoundArgsBuilderVoid() {
  494. if (this->sequence_bound_) {
  495. this->sequence_bound_->impl_task_runner_->PostTask(
  496. *this->location_, std::move(this->callback_));
  497. }
  498. }
  499. void Then(OnceClosure then_callback) && {
  500. this->sequence_bound_->PostTaskAndThenHelper(*this->location_,
  501. std::move(this->callback_),
  502. std::move(then_callback));
  503. this->sequence_bound_ = nullptr;
  504. }
  505. private:
  506. friend SequenceBound;
  507. AsyncCallWithBoundArgsBuilderVoid(AsyncCallWithBoundArgsBuilderVoid&&) =
  508. default;
  509. AsyncCallWithBoundArgsBuilderVoid& operator=(
  510. AsyncCallWithBoundArgsBuilderVoid&&) = default;
  511. };
  512. template <typename ReturnType>
  513. using AsyncCallWithBoundArgsBuilder = typename std::conditional<
  514. std::is_void<ReturnType>::value,
  515. AsyncCallWithBoundArgsBuilderVoid,
  516. AsyncCallWithBoundArgsBuilderDefault<ReturnType>>::type;
  517. void PostTaskAndThenHelper(const Location& location,
  518. OnceCallback<void()> callback,
  519. OnceClosure then_callback) {
  520. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  521. impl_task_runner_->PostTaskAndReply(location, std::move(callback),
  522. std::move(then_callback));
  523. }
  524. template <typename ReturnType,
  525. template <typename>
  526. class CallbackType,
  527. typename ThenArg,
  528. typename = EnableIfIsBaseCallback<CallbackType>>
  529. void PostTaskAndThenHelper(const Location& location,
  530. OnceCallback<ReturnType()> callback,
  531. CallbackType<void(ThenArg)> then_callback) {
  532. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  533. OnceCallback<void(ThenArg)>&& once_then_callback = std::move(then_callback);
  534. impl_task_runner_->PostTaskAndReplyWithResult(
  535. location, std::move(callback), std::move(once_then_callback));
  536. }
  537. // Helper to support move construction and move assignment.
  538. //
  539. // Marked NO_SANITIZE since:
  540. // 1. SequenceBound can be moved before `t_` is constructed on
  541. // `impl_task_runner_` but
  542. // 2. Implicit conversions to non-virtual base classes are allowed before the
  543. // lifetime of `t_` has started (see https://eel.is/c++draft/basic.life#6).
  544. template <typename From>
  545. void NO_SANITIZE("cfi-unrelated-cast") MoveRecordFrom(From&& other) {
  546. // TODO(dcheng): Consider adding a static_assert to provide a friendlier
  547. // error message.
  548. impl_task_runner_ = std::move(other.impl_task_runner_);
  549. // Subtle: this must not use static_cast<>, since the lifetime of the
  550. // managed `T` may not have begun yet. However, the standard explicitly
  551. // still allows implicit conversion to a non-virtual base class.
  552. t_ = std::exchange(other.t_, nullptr);
  553. storage_ = std::exchange(other.storage_, nullptr);
  554. }
  555. // Pointer to the managed `T`. This field is only read and written on
  556. // the sequence associated with `sequence_checker_`.
  557. T* t_ = nullptr;
  558. // Storage originally allocated by `AlignedAlloc()`. Maintained separately
  559. // from `t_` since the original, unadjusted pointer needs to be passed to
  560. // `AlignedFree()`.
  561. void* storage_ = nullptr;
  562. SEQUENCE_CHECKER(sequence_checker_);
  563. // Task runner which manages `t_`. `t_` is constructed, destroyed, and
  564. // dereferenced only on this task runner.
  565. scoped_refptr<base::SequencedTaskRunner> impl_task_runner_;
  566. // Helpers for constructing and destroying `T` on `impl_task_runner_`.
  567. template <typename... Args>
  568. static void ConstructOwnerRecord(T* t, std::decay_t<Args>&&... args) {
  569. new (t) T(std::move(args)...);
  570. }
  571. static void DeleteOwnerRecord(T* t, void* storage) {
  572. t->~T();
  573. AlignedFree(storage);
  574. }
  575. };
  576. } // namespace base
  577. #endif // BASE_THREADING_SEQUENCE_BOUND_H_