1*6777b538SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_THREADING_SEQUENCE_BOUND_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_THREADING_SEQUENCE_BOUND_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <concepts> 9*6777b538SAndroid Build Coastguard Worker #include <new> 10*6777b538SAndroid Build Coastguard Worker #include <tuple> 11*6777b538SAndroid Build Coastguard Worker #include <type_traits> 12*6777b538SAndroid Build Coastguard Worker #include <utility> 13*6777b538SAndroid Build Coastguard Worker 14*6777b538SAndroid Build Coastguard Worker #include "base/check.h" 15*6777b538SAndroid Build Coastguard Worker #include "base/location.h" 16*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h" 17*6777b538SAndroid Build Coastguard Worker #include "base/memory/scoped_refptr.h" 18*6777b538SAndroid Build Coastguard Worker #include "base/run_loop.h" 19*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h" 20*6777b538SAndroid Build Coastguard Worker #include "base/task/sequenced_task_runner.h" 21*6777b538SAndroid Build Coastguard Worker #include "base/threading/sequence_bound_internal.h" 22*6777b538SAndroid Build Coastguard Worker 23*6777b538SAndroid Build Coastguard Worker namespace base { 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard Worker // Performing blocking work on a different task runner is a common pattern for 26*6777b538SAndroid Build Coastguard Worker // improving responsiveness of foreground task runners. `SequenceBound<T>` 27*6777b538SAndroid Build Coastguard Worker // provides an abstraction for an owner object living on the owner sequence, to 28*6777b538SAndroid Build Coastguard Worker // construct, call methods on, and destroy an object of type T that lives on a 29*6777b538SAndroid Build Coastguard Worker // different sequence (the bound sequence). 30*6777b538SAndroid Build Coastguard Worker // 31*6777b538SAndroid Build Coastguard Worker // This makes it natural for code running on different sequences to be 32*6777b538SAndroid Build Coastguard Worker // partitioned along class boundaries, e.g.: 33*6777b538SAndroid Build Coastguard Worker // 34*6777b538SAndroid Build Coastguard Worker // class Tab { 35*6777b538SAndroid Build Coastguard Worker // private: 36*6777b538SAndroid Build Coastguard Worker // void OnScroll() { 37*6777b538SAndroid Build Coastguard Worker // // ... 38*6777b538SAndroid Build Coastguard Worker // io_helper_.AsyncCall(&IOHelper::SaveScrollPosition); 39*6777b538SAndroid Build Coastguard Worker // } 40*6777b538SAndroid Build Coastguard Worker // base::SequenceBound<IOHelper> io_helper_{GetBackgroundTaskRunner()}; 41*6777b538SAndroid Build Coastguard Worker // }; 42*6777b538SAndroid Build Coastguard Worker // 43*6777b538SAndroid Build Coastguard Worker // Note: `SequenceBound<T>` intentionally does not expose a raw pointer to the 44*6777b538SAndroid Build Coastguard Worker // managed `T` to ensure its internal sequence-safety invariants are not 45*6777b538SAndroid Build Coastguard Worker // violated. As a result, `AsyncCall()` cannot simply use `base::OnceCallback` 46*6777b538SAndroid Build Coastguard Worker // 47*6777b538SAndroid Build Coastguard Worker // SequenceBound also supports replies: 48*6777b538SAndroid Build Coastguard Worker // 49*6777b538SAndroid Build Coastguard Worker // class Database { 50*6777b538SAndroid Build Coastguard Worker // public: 51*6777b538SAndroid Build Coastguard Worker // int Query(int value) { 52*6777b538SAndroid Build Coastguard Worker // return value * value; 53*6777b538SAndroid Build Coastguard Worker // } 54*6777b538SAndroid Build Coastguard Worker // }; 55*6777b538SAndroid Build Coastguard Worker // 56*6777b538SAndroid Build Coastguard Worker // // SequenceBound itself is owned on 57*6777b538SAndroid Build Coastguard Worker // // `SequencedTaskRunner::GetCurrentDefault()`. The managed Database 58*6777b538SAndroid Build Coastguard Worker // // instance managed by it is constructed and owned on `GetDBTaskRunner()`. 59*6777b538SAndroid Build Coastguard Worker // base::SequenceBound<Database> db(GetDBTaskRunner()); 60*6777b538SAndroid Build Coastguard Worker // 61*6777b538SAndroid Build Coastguard Worker // // `Database::Query()` runs on `GetDBTaskRunner()`, but 62*6777b538SAndroid Build Coastguard Worker // // `reply_callback` will run on the owner task runner. 63*6777b538SAndroid Build Coastguard Worker // auto reply_callback = [] (int result) { 64*6777b538SAndroid Build Coastguard Worker // LOG(ERROR) << result; // Prints 25. 65*6777b538SAndroid Build Coastguard Worker // }; 66*6777b538SAndroid Build Coastguard Worker // db.AsyncCall(&Database::Query).WithArgs(5) 67*6777b538SAndroid Build Coastguard Worker // .Then(base::BindOnce(reply_callback)); 68*6777b538SAndroid Build Coastguard Worker // 69*6777b538SAndroid Build Coastguard Worker // // When `db` goes out of scope, the Database instance will also be 70*6777b538SAndroid Build Coastguard Worker // // destroyed via a task posted to `GetDBTaskRunner()`. 71*6777b538SAndroid Build Coastguard Worker // 72*6777b538SAndroid Build Coastguard Worker // Sequence safety: 73*6777b538SAndroid Build Coastguard Worker // 74*6777b538SAndroid Build Coastguard Worker // Const-qualified methods may be used concurrently from multiple sequences, 75*6777b538SAndroid Build Coastguard Worker // e.g. `AsyncCall()` or `is_null()`. Calls that are forwarded to the 76*6777b538SAndroid Build Coastguard Worker // managed `T` will be posted to the bound sequence and executed serially 77*6777b538SAndroid Build Coastguard Worker // there. 78*6777b538SAndroid Build Coastguard Worker // 79*6777b538SAndroid Build Coastguard Worker // Mutable methods (e.g. `Reset()`, destruction, or move assignment) require 80*6777b538SAndroid Build Coastguard Worker // external synchronization if used concurrently with any other methods, 81*6777b538SAndroid Build Coastguard Worker // including const-qualified methods. 82*6777b538SAndroid Build Coastguard Worker // 83*6777b538SAndroid Build Coastguard Worker // Advanced usage: 84*6777b538SAndroid Build Coastguard Worker // 85*6777b538SAndroid Build Coastguard Worker // Using `SequenceBound<std::unique_ptr<T>>` allows transferring ownership of an 86*6777b538SAndroid Build Coastguard Worker // already-constructed `T` to `SequenceBound`. This can be helpful for more 87*6777b538SAndroid Build Coastguard Worker // complex situations, where `T` needs to be constructed on a specific sequence 88*6777b538SAndroid Build Coastguard Worker // that is different from where `T` will ultimately live. 89*6777b538SAndroid Build Coastguard Worker // 90*6777b538SAndroid Build Coastguard Worker // Construction (via the constructor or emplace) takes a `std::unique_ptr<T>` 91*6777b538SAndroid Build Coastguard Worker // instead of forwarding the arguments to `T`'s constructor: 92*6777b538SAndroid Build Coastguard Worker // 93*6777b538SAndroid Build Coastguard Worker // std::unique_ptr<Database> db_impl = MakeDatabaseOnMainThread(); 94*6777b538SAndroid Build Coastguard Worker // base::SequenceBound<std::unique_ptr<Database>> db(GetDbTaskRunner(), 95*6777b538SAndroid Build Coastguard Worker // std::move(db_impl)); 96*6777b538SAndroid Build Coastguard Worker // 97*6777b538SAndroid Build Coastguard Worker // All other usage (e.g. `AsyncCall()`, `Reset()`) functions identically to a 98*6777b538SAndroid Build Coastguard Worker // regular `SequenceBound<T>`: 99*6777b538SAndroid Build Coastguard Worker // 100*6777b538SAndroid Build Coastguard Worker // // No need to dereference the `std::unique_ptr` explicitly: 101*6777b538SAndroid Build Coastguard Worker // db.AsyncCall(&Database::Query).WithArgs(5).Then(base::BindOnce(...)); 102*6777b538SAndroid Build Coastguard Worker template <typename T, 103*6777b538SAndroid Build Coastguard Worker typename CrossThreadTraits = 104*6777b538SAndroid Build Coastguard Worker sequence_bound_internal::CrossThreadTraits> 105*6777b538SAndroid Build Coastguard Worker class SequenceBound { 106*6777b538SAndroid Build Coastguard Worker private: 107*6777b538SAndroid Build Coastguard Worker using Storage = sequence_bound_internal::Storage<T, CrossThreadTraits>; 108*6777b538SAndroid Build Coastguard Worker using UnwrappedT = typename Storage::element_type; 109*6777b538SAndroid Build Coastguard Worker 110*6777b538SAndroid Build Coastguard Worker public: 111*6777b538SAndroid Build Coastguard Worker template <typename Signature> 112*6777b538SAndroid Build Coastguard Worker using CrossThreadTask = 113*6777b538SAndroid Build Coastguard Worker typename CrossThreadTraits::template CrossThreadTask<Signature>; 114*6777b538SAndroid Build Coastguard Worker 115*6777b538SAndroid Build Coastguard Worker // Note: on construction, SequenceBound binds to the current sequence. Any 116*6777b538SAndroid Build Coastguard Worker // subsequent SequenceBound calls (including destruction) must run on that 117*6777b538SAndroid Build Coastguard Worker // same sequence. 118*6777b538SAndroid Build Coastguard Worker 119*6777b538SAndroid Build Coastguard Worker // Constructs a null SequenceBound with no managed `T`. 120*6777b538SAndroid Build Coastguard Worker SequenceBound() = default; 121*6777b538SAndroid Build Coastguard Worker 122*6777b538SAndroid Build Coastguard Worker // Constructs a SequenceBound that manages a new instance of `T` on 123*6777b538SAndroid Build Coastguard Worker // `task_runner`. `T` will be constructed on `task_runner`. 124*6777b538SAndroid Build Coastguard Worker // 125*6777b538SAndroid Build Coastguard Worker // Once this constructor returns, it is safe to immediately use `AsyncCall()`, 126*6777b538SAndroid Build Coastguard Worker // et cetera; these calls will be sequenced after the construction of the 127*6777b538SAndroid Build Coastguard Worker // managed `T`. 128*6777b538SAndroid Build Coastguard Worker template <typename... Args> SequenceBound(scoped_refptr<SequencedTaskRunner> task_runner,Args &&...args)129*6777b538SAndroid Build Coastguard Worker explicit SequenceBound(scoped_refptr<SequencedTaskRunner> task_runner, 130*6777b538SAndroid Build Coastguard Worker Args&&... args) 131*6777b538SAndroid Build Coastguard Worker : impl_task_runner_(std::move(task_runner)) { 132*6777b538SAndroid Build Coastguard Worker storage_.Construct(*impl_task_runner_, std::forward<Args>(args)...); 133*6777b538SAndroid Build Coastguard Worker } 134*6777b538SAndroid Build Coastguard Worker 135*6777b538SAndroid Build Coastguard Worker // If non-null, the managed `T` will be destroyed on `impl_task_runner_`.` ~SequenceBound()136*6777b538SAndroid Build Coastguard Worker ~SequenceBound() { Reset(); } 137*6777b538SAndroid Build Coastguard Worker 138*6777b538SAndroid Build Coastguard Worker // Disallow copy or assignment. SequenceBound has single ownership of the 139*6777b538SAndroid Build Coastguard Worker // managed `T`. 140*6777b538SAndroid Build Coastguard Worker SequenceBound(const SequenceBound&) = delete; 141*6777b538SAndroid Build Coastguard Worker SequenceBound& operator=(const SequenceBound&) = delete; 142*6777b538SAndroid Build Coastguard Worker 143*6777b538SAndroid Build Coastguard Worker // Move construction and assignment. SequenceBound(SequenceBound && other)144*6777b538SAndroid Build Coastguard Worker SequenceBound(SequenceBound&& other) { MoveRecordFrom(other); } 145*6777b538SAndroid Build Coastguard Worker 146*6777b538SAndroid Build Coastguard Worker SequenceBound& operator=(SequenceBound&& other) { 147*6777b538SAndroid Build Coastguard Worker Reset(); 148*6777b538SAndroid Build Coastguard Worker MoveRecordFrom(other); 149*6777b538SAndroid Build Coastguard Worker return *this; 150*6777b538SAndroid Build Coastguard Worker } 151*6777b538SAndroid Build Coastguard Worker 152*6777b538SAndroid Build Coastguard Worker // Move conversion helpers: allows upcasting from SequenceBound<Derived> to 153*6777b538SAndroid Build Coastguard Worker // SequenceBound<Base>. 154*6777b538SAndroid Build Coastguard Worker template <typename U> 155*6777b538SAndroid Build Coastguard Worker // NOLINTNEXTLINE(google-explicit-constructor): Intentionally implicit. SequenceBound(SequenceBound<U,CrossThreadTraits> && other)156*6777b538SAndroid Build Coastguard Worker SequenceBound(SequenceBound<U, CrossThreadTraits>&& other) { 157*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/1382549): static_assert that U* is convertible to 158*6777b538SAndroid Build Coastguard Worker // T*. 159*6777b538SAndroid Build Coastguard Worker MoveRecordFrom(other); 160*6777b538SAndroid Build Coastguard Worker } 161*6777b538SAndroid Build Coastguard Worker 162*6777b538SAndroid Build Coastguard Worker template <typename U> 163*6777b538SAndroid Build Coastguard Worker SequenceBound& operator=(SequenceBound<U, CrossThreadTraits>&& other) { 164*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/1382549): static_assert that U* is convertible to 165*6777b538SAndroid Build Coastguard Worker // T*. 166*6777b538SAndroid Build Coastguard Worker Reset(); 167*6777b538SAndroid Build Coastguard Worker MoveRecordFrom(other); 168*6777b538SAndroid Build Coastguard Worker return *this; 169*6777b538SAndroid Build Coastguard Worker } 170*6777b538SAndroid Build Coastguard Worker 171*6777b538SAndroid Build Coastguard Worker // Constructs a new managed instance of `T` on `task_runner`. If `this` is 172*6777b538SAndroid Build Coastguard Worker // already managing another instance of `T`, that pre-existing instance will 173*6777b538SAndroid Build Coastguard Worker // first be destroyed by calling `Reset()`. 174*6777b538SAndroid Build Coastguard Worker // 175*6777b538SAndroid Build Coastguard Worker // Once `emplace()` returns, it is safe to immediately use `AsyncCall()`, 176*6777b538SAndroid Build Coastguard Worker // et cetera; these calls will be sequenced after the construction of the 177*6777b538SAndroid Build Coastguard Worker // managed `T`. 178*6777b538SAndroid Build Coastguard Worker template <typename... Args> emplace(scoped_refptr<SequencedTaskRunner> task_runner,Args &&...args)179*6777b538SAndroid Build Coastguard Worker SequenceBound& emplace(scoped_refptr<SequencedTaskRunner> task_runner, 180*6777b538SAndroid Build Coastguard Worker Args&&... args) { 181*6777b538SAndroid Build Coastguard Worker Reset(); 182*6777b538SAndroid Build Coastguard Worker impl_task_runner_ = std::move(task_runner); 183*6777b538SAndroid Build Coastguard Worker storage_.Construct(*impl_task_runner_, std::forward<Args>(args)...); 184*6777b538SAndroid Build Coastguard Worker return *this; 185*6777b538SAndroid Build Coastguard Worker } 186*6777b538SAndroid Build Coastguard Worker 187*6777b538SAndroid Build Coastguard Worker // Invokes `method` of the managed `T` on `impl_task_runner_`. May only be 188*6777b538SAndroid Build Coastguard Worker // used when `is_null()` is false. 189*6777b538SAndroid Build Coastguard Worker // 190*6777b538SAndroid Build Coastguard Worker // Basic usage: 191*6777b538SAndroid Build Coastguard Worker // 192*6777b538SAndroid Build Coastguard Worker // helper.AsyncCall(&IOHelper::DoWork); 193*6777b538SAndroid Build Coastguard Worker // 194*6777b538SAndroid Build Coastguard Worker // If `method` accepts arguments, use `WithArgs()` to bind them: 195*6777b538SAndroid Build Coastguard Worker // 196*6777b538SAndroid Build Coastguard Worker // helper.AsyncCall(&IOHelper::DoWorkWithArgs) 197*6777b538SAndroid Build Coastguard Worker // .WithArgs(args); 198*6777b538SAndroid Build Coastguard Worker // 199*6777b538SAndroid Build Coastguard Worker // Use `Then()` to run a callback on the owner sequence after `method` 200*6777b538SAndroid Build Coastguard Worker // completes: 201*6777b538SAndroid Build Coastguard Worker // 202*6777b538SAndroid Build Coastguard Worker // helper.AsyncCall(&IOHelper::GetValue) 203*6777b538SAndroid Build Coastguard Worker // .Then(std::move(process_result_callback)); 204*6777b538SAndroid Build Coastguard Worker // 205*6777b538SAndroid Build Coastguard Worker // If a method returns a non-void type, use of `Then()` is required, and the 206*6777b538SAndroid Build Coastguard Worker // method's return value will be passed to the `Then()` callback. To ignore 207*6777b538SAndroid Build Coastguard Worker // the method's return value instead, wrap `method` in `base::IgnoreResult()`: 208*6777b538SAndroid Build Coastguard Worker // 209*6777b538SAndroid Build Coastguard Worker // // Calling `GetPrefs` to force-initialize prefs. 210*6777b538SAndroid Build Coastguard Worker // helper.AsyncCall(base::IgnoreResult(&IOHelper::GetPrefs)); 211*6777b538SAndroid Build Coastguard Worker // 212*6777b538SAndroid Build Coastguard Worker // `WithArgs()` and `Then()` may also be combined: 213*6777b538SAndroid Build Coastguard Worker // 214*6777b538SAndroid Build Coastguard Worker // // Ordering is important: `Then()` must come last. 215*6777b538SAndroid Build Coastguard Worker // helper.AsyncCall(&IOHelper::GetValueWithArgs) 216*6777b538SAndroid Build Coastguard Worker // .WithArgs(args) 217*6777b538SAndroid Build Coastguard Worker // .Then(std::move(process_result_callback)); 218*6777b538SAndroid Build Coastguard Worker // 219*6777b538SAndroid Build Coastguard Worker // Note: internally, `AsyncCall()` is implemented using a series of helper 220*6777b538SAndroid Build Coastguard Worker // classes that build the callback chain and post it on destruction. Capturing 221*6777b538SAndroid Build Coastguard Worker // the return value and passing it elsewhere or triggering lifetime extension 222*6777b538SAndroid Build Coastguard Worker // (e.g. by binding the return value to a reference) are both unsupported. 223*6777b538SAndroid Build Coastguard Worker template <typename R, typename C, typename... Args> requires(std::derived_from<UnwrappedT,C>)224*6777b538SAndroid Build Coastguard Worker requires(std::derived_from<UnwrappedT, C>) 225*6777b538SAndroid Build Coastguard Worker auto AsyncCall(R (C::*method)(Args...), 226*6777b538SAndroid Build Coastguard Worker const Location& location = Location::Current()) const { 227*6777b538SAndroid Build Coastguard Worker return AsyncCallBuilder<R (C::*)(Args...), R, std::tuple<Args...>>( 228*6777b538SAndroid Build Coastguard Worker this, &location, method); 229*6777b538SAndroid Build Coastguard Worker } 230*6777b538SAndroid Build Coastguard Worker 231*6777b538SAndroid Build Coastguard Worker template <typename R, typename C, typename... Args> requires(std::derived_from<UnwrappedT,C>)232*6777b538SAndroid Build Coastguard Worker requires(std::derived_from<UnwrappedT, C>) 233*6777b538SAndroid Build Coastguard Worker auto AsyncCall(R (C::*method)(Args...) const, 234*6777b538SAndroid Build Coastguard Worker const Location& location = Location::Current()) const { 235*6777b538SAndroid Build Coastguard Worker return AsyncCallBuilder<R (C::*)(Args...) const, R, std::tuple<Args...>>( 236*6777b538SAndroid Build Coastguard Worker this, &location, method); 237*6777b538SAndroid Build Coastguard Worker } 238*6777b538SAndroid Build Coastguard Worker 239*6777b538SAndroid Build Coastguard Worker template <typename R, typename C, typename... Args> requires(std::derived_from<UnwrappedT,C>)240*6777b538SAndroid Build Coastguard Worker requires(std::derived_from<UnwrappedT, C>) 241*6777b538SAndroid Build Coastguard Worker auto AsyncCall(internal::IgnoreResultHelper<R (C::*)(Args...) const> method, 242*6777b538SAndroid Build Coastguard Worker const Location& location = Location::Current()) const { 243*6777b538SAndroid Build Coastguard Worker return AsyncCallBuilder< 244*6777b538SAndroid Build Coastguard Worker internal::IgnoreResultHelper<R (C::*)(Args...) const>, void, 245*6777b538SAndroid Build Coastguard Worker std::tuple<Args...>>(this, &location, method); 246*6777b538SAndroid Build Coastguard Worker } 247*6777b538SAndroid Build Coastguard Worker 248*6777b538SAndroid Build Coastguard Worker template <typename R, typename C, typename... Args> requires(std::derived_from<UnwrappedT,C>)249*6777b538SAndroid Build Coastguard Worker requires(std::derived_from<UnwrappedT, C>) 250*6777b538SAndroid Build Coastguard Worker auto AsyncCall(internal::IgnoreResultHelper<R (C::*)(Args...)> method, 251*6777b538SAndroid Build Coastguard Worker const Location& location = Location::Current()) const { 252*6777b538SAndroid Build Coastguard Worker return AsyncCallBuilder<internal::IgnoreResultHelper<R (C::*)(Args...)>, 253*6777b538SAndroid Build Coastguard Worker void, std::tuple<Args...>>(this, &location, method); 254*6777b538SAndroid Build Coastguard Worker } 255*6777b538SAndroid Build Coastguard Worker 256*6777b538SAndroid Build Coastguard Worker // Posts `task` to `impl_task_runner_`, passing it a reference to the wrapped 257*6777b538SAndroid Build Coastguard Worker // object. This allows arbitrary logic to be safely executed on the object's 258*6777b538SAndroid Build Coastguard Worker // task runner. The object is guaranteed to remain alive for the duration of 259*6777b538SAndroid Build Coastguard Worker // the task. 260*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1182140): Consider checking whether the task runner can run 261*6777b538SAndroid Build Coastguard Worker // tasks in current sequence, and using "plain" binds and task posting (here 262*6777b538SAndroid Build Coastguard Worker // and other places that `CrossThreadTraits::PostTask`). 263*6777b538SAndroid Build Coastguard Worker using ConstPostTaskCallback = CrossThreadTask<void(const UnwrappedT&)>; 264*6777b538SAndroid Build Coastguard Worker void PostTaskWithThisObject( 265*6777b538SAndroid Build Coastguard Worker ConstPostTaskCallback callback, 266*6777b538SAndroid Build Coastguard Worker const Location& location = Location::Current()) const { 267*6777b538SAndroid Build Coastguard Worker DCHECK(!is_null()); 268*6777b538SAndroid Build Coastguard Worker // Even though the lifetime of the object managed by `storage_` may not 269*6777b538SAndroid Build Coastguard Worker // have begun yet, the storage has been allocated. Per [basic.life/6] and 270*6777b538SAndroid Build Coastguard Worker // [basic.life/7], "Indirection through such a pointer is permitted but the 271*6777b538SAndroid Build Coastguard Worker // resulting lvalue may only be used in limited ways, as described below." 272*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask( 273*6777b538SAndroid Build Coastguard Worker *impl_task_runner_, location, 274*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce(std::move(callback), 275*6777b538SAndroid Build Coastguard Worker storage_.GetRefForBind())); 276*6777b538SAndroid Build Coastguard Worker } 277*6777b538SAndroid Build Coastguard Worker 278*6777b538SAndroid Build Coastguard Worker // Same as above, but for non-const operations. The callback takes a pointer 279*6777b538SAndroid Build Coastguard Worker // to the wrapped object rather than a const ref. 280*6777b538SAndroid Build Coastguard Worker using PostTaskCallback = CrossThreadTask<void(UnwrappedT*)>; 281*6777b538SAndroid Build Coastguard Worker void PostTaskWithThisObject( 282*6777b538SAndroid Build Coastguard Worker PostTaskCallback callback, 283*6777b538SAndroid Build Coastguard Worker const Location& location = Location::Current()) const { 284*6777b538SAndroid Build Coastguard Worker DCHECK(!is_null()); 285*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask( 286*6777b538SAndroid Build Coastguard Worker *impl_task_runner_, location, 287*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce(std::move(callback), 288*6777b538SAndroid Build Coastguard Worker storage_.GetPtrForBind())); 289*6777b538SAndroid Build Coastguard Worker } 290*6777b538SAndroid Build Coastguard Worker FlushPostedTasksForTesting()291*6777b538SAndroid Build Coastguard Worker void FlushPostedTasksForTesting() const { 292*6777b538SAndroid Build Coastguard Worker DCHECK(!is_null()); 293*6777b538SAndroid Build Coastguard Worker RunLoop run_loop; 294*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask(*impl_task_runner_, FROM_HERE, 295*6777b538SAndroid Build Coastguard Worker run_loop.QuitClosure()); 296*6777b538SAndroid Build Coastguard Worker run_loop.Run(); 297*6777b538SAndroid Build Coastguard Worker } 298*6777b538SAndroid Build Coastguard Worker 299*6777b538SAndroid Build Coastguard Worker // TODO(liberato): Add PostOrCall(), to support cases where synchronous calls 300*6777b538SAndroid Build Coastguard Worker // are okay if it's the same task runner. 301*6777b538SAndroid Build Coastguard Worker 302*6777b538SAndroid Build Coastguard Worker // Resets `this` to null. If `this` is not currently null, posts destruction 303*6777b538SAndroid Build Coastguard Worker // of the managed `T` to `impl_task_runner_`. Reset()304*6777b538SAndroid Build Coastguard Worker void Reset() { 305*6777b538SAndroid Build Coastguard Worker if (is_null()) 306*6777b538SAndroid Build Coastguard Worker return; 307*6777b538SAndroid Build Coastguard Worker 308*6777b538SAndroid Build Coastguard Worker storage_.Destruct(*impl_task_runner_); 309*6777b538SAndroid Build Coastguard Worker impl_task_runner_ = nullptr; 310*6777b538SAndroid Build Coastguard Worker } 311*6777b538SAndroid Build Coastguard Worker 312*6777b538SAndroid Build Coastguard Worker // Resets `this` to null. If `this` is not currently null, posts destruction 313*6777b538SAndroid Build Coastguard Worker // of the managed `T` to `impl_task_runner_`. Blocks until the destructor has 314*6777b538SAndroid Build Coastguard Worker // run. SynchronouslyResetForTest()315*6777b538SAndroid Build Coastguard Worker void SynchronouslyResetForTest() { 316*6777b538SAndroid Build Coastguard Worker if (is_null()) 317*6777b538SAndroid Build Coastguard Worker return; 318*6777b538SAndroid Build Coastguard Worker 319*6777b538SAndroid Build Coastguard Worker scoped_refptr<SequencedTaskRunner> task_runner = impl_task_runner_; 320*6777b538SAndroid Build Coastguard Worker Reset(); 321*6777b538SAndroid Build Coastguard Worker // `Reset()` posts a task to destroy the managed `T`; synchronously wait for 322*6777b538SAndroid Build Coastguard Worker // that posted task to complete. 323*6777b538SAndroid Build Coastguard Worker RunLoop run_loop; 324*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask(*task_runner, FROM_HERE, 325*6777b538SAndroid Build Coastguard Worker run_loop.QuitClosure()); 326*6777b538SAndroid Build Coastguard Worker run_loop.Run(); 327*6777b538SAndroid Build Coastguard Worker } 328*6777b538SAndroid Build Coastguard Worker 329*6777b538SAndroid Build Coastguard Worker // Return true if `this` is logically null; otherwise, returns false. 330*6777b538SAndroid Build Coastguard Worker // 331*6777b538SAndroid Build Coastguard Worker // A SequenceBound is logically null if there is no managed `T`; it is only 332*6777b538SAndroid Build Coastguard Worker // valid to call `AsyncCall()` on a non-null SequenceBound. 333*6777b538SAndroid Build Coastguard Worker // 334*6777b538SAndroid Build Coastguard Worker // Note that the concept of 'logically null' here does not exactly match the 335*6777b538SAndroid Build Coastguard Worker // lifetime of `T`, which lives on `impl_task_runner_`. In particular, when 336*6777b538SAndroid Build Coastguard Worker // SequenceBound is first constructed, `is_null()` may return false, even 337*6777b538SAndroid Build Coastguard Worker // though the lifetime of `T` may not have begun yet on `impl_task_runner_`. 338*6777b538SAndroid Build Coastguard Worker // Similarly, after `SequenceBound::Reset()`, `is_null()` may return true, 339*6777b538SAndroid Build Coastguard Worker // even though the lifetime of `T` may not have ended yet on 340*6777b538SAndroid Build Coastguard Worker // `impl_task_runner_`. is_null()341*6777b538SAndroid Build Coastguard Worker bool is_null() const { return storage_.is_null(); } 342*6777b538SAndroid Build Coastguard Worker 343*6777b538SAndroid Build Coastguard Worker // True if `this` is not logically null. See `is_null()`. 344*6777b538SAndroid Build Coastguard Worker explicit operator bool() const { return !is_null(); } 345*6777b538SAndroid Build Coastguard Worker 346*6777b538SAndroid Build Coastguard Worker private: 347*6777b538SAndroid Build Coastguard Worker // For move conversion. 348*6777b538SAndroid Build Coastguard Worker template <typename U, typename V> 349*6777b538SAndroid Build Coastguard Worker friend class SequenceBound; 350*6777b538SAndroid Build Coastguard Worker 351*6777b538SAndroid Build Coastguard Worker template <template <typename> class CallbackType> 352*6777b538SAndroid Build Coastguard Worker static constexpr bool IsCrossThreadTask = 353*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::template IsCrossThreadTask<CallbackType>; 354*6777b538SAndroid Build Coastguard Worker 355*6777b538SAndroid Build Coastguard Worker // Support helpers for `AsyncCall()` implementation. 356*6777b538SAndroid Build Coastguard Worker // 357*6777b538SAndroid Build Coastguard Worker // Several implementation notes: 358*6777b538SAndroid Build Coastguard Worker // 1. Tasks are posted via destroying the builder or an explicit call to 359*6777b538SAndroid Build Coastguard Worker // `Then()`. 360*6777b538SAndroid Build Coastguard Worker // 361*6777b538SAndroid Build Coastguard Worker // 2. A builder may be consumed by: 362*6777b538SAndroid Build Coastguard Worker // 363*6777b538SAndroid Build Coastguard Worker // - calling `Then()`, which immediately posts the task chain 364*6777b538SAndroid Build Coastguard Worker // - calling `WithArgs()`, which returns a new builder with the captured 365*6777b538SAndroid Build Coastguard Worker // arguments 366*6777b538SAndroid Build Coastguard Worker // 367*6777b538SAndroid Build Coastguard Worker // Builders that are consumed have the internal `sequence_bound_` field 368*6777b538SAndroid Build Coastguard Worker // nulled out; the hope is the compiler can see this and use it to 369*6777b538SAndroid Build Coastguard Worker // eliminate dead branches (e.g. correctness checks that aren't needed 370*6777b538SAndroid Build Coastguard Worker // since the code can be statically proved correct). 371*6777b538SAndroid Build Coastguard Worker // 372*6777b538SAndroid Build Coastguard Worker // 3. Builder methods are rvalue-qualified to try to enforce that the builder 373*6777b538SAndroid Build Coastguard Worker // is only used as a temporary. Note that this only helps so much; nothing 374*6777b538SAndroid Build Coastguard Worker // prevents a determined caller from using `std::move()` to force calls to 375*6777b538SAndroid Build Coastguard Worker // a non-temporary instance. 376*6777b538SAndroid Build Coastguard Worker // 377*6777b538SAndroid Build Coastguard Worker // TODO(dcheng): It might also be possible to use Gmock-style matcher 378*6777b538SAndroid Build Coastguard Worker // composition, e.g. something like: 379*6777b538SAndroid Build Coastguard Worker // 380*6777b538SAndroid Build Coastguard Worker // sb.AsyncCall(&Helper::DoWork, WithArgs(args), 381*6777b538SAndroid Build Coastguard Worker // Then(std::move(process_result)); 382*6777b538SAndroid Build Coastguard Worker // 383*6777b538SAndroid Build Coastguard Worker // In theory, this might allow the elimination of magic destructors and 384*6777b538SAndroid Build Coastguard Worker // better static checking by the compiler. 385*6777b538SAndroid Build Coastguard Worker template <typename MethodRef> 386*6777b538SAndroid Build Coastguard Worker class AsyncCallBuilderBase { 387*6777b538SAndroid Build Coastguard Worker protected: AsyncCallBuilderBase(const SequenceBound * sequence_bound,const Location * location,MethodRef method)388*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderBase(const SequenceBound* sequence_bound, 389*6777b538SAndroid Build Coastguard Worker const Location* location, 390*6777b538SAndroid Build Coastguard Worker MethodRef method) 391*6777b538SAndroid Build Coastguard Worker : sequence_bound_(sequence_bound), 392*6777b538SAndroid Build Coastguard Worker location_(location), 393*6777b538SAndroid Build Coastguard Worker method_(method) { 394*6777b538SAndroid Build Coastguard Worker // Common entry point for `AsyncCall()`, so check preconditions here. 395*6777b538SAndroid Build Coastguard Worker DCHECK(sequence_bound_); 396*6777b538SAndroid Build Coastguard Worker DCHECK(!sequence_bound_->storage_.is_null()); 397*6777b538SAndroid Build Coastguard Worker } 398*6777b538SAndroid Build Coastguard Worker 399*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderBase(AsyncCallBuilderBase&&) = default; 400*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderBase& operator=(AsyncCallBuilderBase&&) = default; 401*6777b538SAndroid Build Coastguard Worker 402*6777b538SAndroid Build Coastguard Worker // `sequence_bound_` is consumed and set to `nullptr` when `Then()` is 403*6777b538SAndroid Build Coastguard Worker // invoked. This is used as a flag for two potential states 404*6777b538SAndroid Build Coastguard Worker // 405*6777b538SAndroid Build Coastguard Worker // - if a method returns void, invoking `Then()` is optional. The destructor 406*6777b538SAndroid Build Coastguard Worker // will check if `sequence_bound_` is null; if it is, `Then()` was 407*6777b538SAndroid Build Coastguard Worker // already invoked and the task chain has already been posted, so the 408*6777b538SAndroid Build Coastguard Worker // destructor does not need to do anything. Otherwise, the destructor 409*6777b538SAndroid Build Coastguard Worker // needs to post the task to make the async call. In theory, the compiler 410*6777b538SAndroid Build Coastguard Worker // should be able to eliminate this branch based on the presence or 411*6777b538SAndroid Build Coastguard Worker // absence of a call to `Then()`. 412*6777b538SAndroid Build Coastguard Worker // 413*6777b538SAndroid Build Coastguard Worker // - if a method returns a non-void type, `Then()` *must* be invoked. The 414*6777b538SAndroid Build Coastguard Worker // destructor will `CHECK()` if `sequence_bound_` is non-null, since that 415*6777b538SAndroid Build Coastguard Worker // indicates `Then()` was not invoked. Similarly, note this branch should 416*6777b538SAndroid Build Coastguard Worker // be eliminated by the optimizer if the code is free of bugs. :) 417*6777b538SAndroid Build Coastguard Worker raw_ptr<const SequenceBound<T, CrossThreadTraits>, DanglingUntriaged> 418*6777b538SAndroid Build Coastguard Worker sequence_bound_; 419*6777b538SAndroid Build Coastguard Worker // Subtle: this typically points at a Location *temporary*. This is used to 420*6777b538SAndroid Build Coastguard Worker // try to detect errors resulting from lifetime extension of the async call 421*6777b538SAndroid Build Coastguard Worker // factory temporaries, since the factory destructors can perform work. If 422*6777b538SAndroid Build Coastguard Worker // the lifetime of the factory is incorrectly extended, dereferencing 423*6777b538SAndroid Build Coastguard Worker // `location_` will trigger a stack-use-after-scope when running with ASan. 424*6777b538SAndroid Build Coastguard Worker const raw_ptr<const Location> location_; 425*6777b538SAndroid Build Coastguard Worker MethodRef method_; 426*6777b538SAndroid Build Coastguard Worker }; 427*6777b538SAndroid Build Coastguard Worker 428*6777b538SAndroid Build Coastguard Worker template <typename MethodRef, typename ReturnType, typename ArgsTuple> 429*6777b538SAndroid Build Coastguard Worker class AsyncCallBuilderImpl; 430*6777b538SAndroid Build Coastguard Worker 431*6777b538SAndroid Build Coastguard Worker // Selected method has no arguments and returns void. 432*6777b538SAndroid Build Coastguard Worker template <typename MethodRef> 433*6777b538SAndroid Build Coastguard Worker class AsyncCallBuilderImpl<MethodRef, void, std::tuple<>> 434*6777b538SAndroid Build Coastguard Worker : public AsyncCallBuilderBase<MethodRef> { 435*6777b538SAndroid Build Coastguard Worker public: 436*6777b538SAndroid Build Coastguard Worker // Note: despite being here, this is actually still protected, since it is 437*6777b538SAndroid Build Coastguard Worker // protected on the base class. 438*6777b538SAndroid Build Coastguard Worker using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase; 439*6777b538SAndroid Build Coastguard Worker ~AsyncCallBuilderImpl()440*6777b538SAndroid Build Coastguard Worker ~AsyncCallBuilderImpl() { 441*6777b538SAndroid Build Coastguard Worker if (this->sequence_bound_) { 442*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask( 443*6777b538SAndroid Build Coastguard Worker *this->sequence_bound_->impl_task_runner_, *this->location_, 444*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce( 445*6777b538SAndroid Build Coastguard Worker this->method_, 446*6777b538SAndroid Build Coastguard Worker this->sequence_bound_->storage_.GetPtrForBind())); 447*6777b538SAndroid Build Coastguard Worker } 448*6777b538SAndroid Build Coastguard Worker } 449*6777b538SAndroid Build Coastguard Worker Then(CrossThreadTask<void ()> then_callback)450*6777b538SAndroid Build Coastguard Worker void Then(CrossThreadTask<void()> then_callback) && { 451*6777b538SAndroid Build Coastguard Worker this->sequence_bound_->PostTaskAndThenHelper( 452*6777b538SAndroid Build Coastguard Worker *this->location_, 453*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce( 454*6777b538SAndroid Build Coastguard Worker this->method_, this->sequence_bound_->storage_.GetPtrForBind()), 455*6777b538SAndroid Build Coastguard Worker std::move(then_callback)); 456*6777b538SAndroid Build Coastguard Worker this->sequence_bound_ = nullptr; 457*6777b538SAndroid Build Coastguard Worker } 458*6777b538SAndroid Build Coastguard Worker 459*6777b538SAndroid Build Coastguard Worker private: 460*6777b538SAndroid Build Coastguard Worker friend SequenceBound; 461*6777b538SAndroid Build Coastguard Worker 462*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default; 463*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default; 464*6777b538SAndroid Build Coastguard Worker }; 465*6777b538SAndroid Build Coastguard Worker 466*6777b538SAndroid Build Coastguard Worker // Selected method has no arguments and returns non-void. 467*6777b538SAndroid Build Coastguard Worker template <typename MethodRef, typename ReturnType> 468*6777b538SAndroid Build Coastguard Worker class AsyncCallBuilderImpl<MethodRef, ReturnType, std::tuple<>> 469*6777b538SAndroid Build Coastguard Worker : public AsyncCallBuilderBase<MethodRef> { 470*6777b538SAndroid Build Coastguard Worker public: 471*6777b538SAndroid Build Coastguard Worker // Note: despite being here, this is actually still protected, since it is 472*6777b538SAndroid Build Coastguard Worker // protected on the base class. 473*6777b538SAndroid Build Coastguard Worker using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase; 474*6777b538SAndroid Build Coastguard Worker ~AsyncCallBuilderImpl()475*6777b538SAndroid Build Coastguard Worker ~AsyncCallBuilderImpl() { 476*6777b538SAndroid Build Coastguard Worker // Must use Then() since the method's return type is not void. 477*6777b538SAndroid Build Coastguard Worker // Should be optimized out if the code is bug-free. 478*6777b538SAndroid Build Coastguard Worker CHECK(!this->sequence_bound_) 479*6777b538SAndroid Build Coastguard Worker << "Then() not invoked for a method that returns a non-void type; " 480*6777b538SAndroid Build Coastguard Worker << "make sure to invoke Then() or use base::IgnoreResult()"; 481*6777b538SAndroid Build Coastguard Worker } 482*6777b538SAndroid Build Coastguard Worker 483*6777b538SAndroid Build Coastguard Worker template <template <typename> class CallbackType, typename ThenArg> requires(IsCrossThreadTask<CallbackType>)484*6777b538SAndroid Build Coastguard Worker requires(IsCrossThreadTask<CallbackType>) 485*6777b538SAndroid Build Coastguard Worker void Then(CallbackType<void(ThenArg)> then_callback) && { 486*6777b538SAndroid Build Coastguard Worker this->sequence_bound_->PostTaskAndThenHelper( 487*6777b538SAndroid Build Coastguard Worker *this->location_, 488*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce( 489*6777b538SAndroid Build Coastguard Worker this->method_, this->sequence_bound_->storage_.GetPtrForBind()), 490*6777b538SAndroid Build Coastguard Worker std::move(then_callback)); 491*6777b538SAndroid Build Coastguard Worker this->sequence_bound_ = nullptr; 492*6777b538SAndroid Build Coastguard Worker } 493*6777b538SAndroid Build Coastguard Worker 494*6777b538SAndroid Build Coastguard Worker private: 495*6777b538SAndroid Build Coastguard Worker friend SequenceBound; 496*6777b538SAndroid Build Coastguard Worker 497*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default; 498*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default; 499*6777b538SAndroid Build Coastguard Worker }; 500*6777b538SAndroid Build Coastguard Worker 501*6777b538SAndroid Build Coastguard Worker // Selected method has arguments. Return type can be void or non-void. 502*6777b538SAndroid Build Coastguard Worker template <typename MethodRef, typename ReturnType, typename... Args> 503*6777b538SAndroid Build Coastguard Worker class AsyncCallBuilderImpl<MethodRef, ReturnType, std::tuple<Args...>> 504*6777b538SAndroid Build Coastguard Worker : public AsyncCallBuilderBase<MethodRef> { 505*6777b538SAndroid Build Coastguard Worker public: 506*6777b538SAndroid Build Coastguard Worker // Note: despite being here, this is actually still protected, since it is 507*6777b538SAndroid Build Coastguard Worker // protected on the base class. 508*6777b538SAndroid Build Coastguard Worker using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase; 509*6777b538SAndroid Build Coastguard Worker ~AsyncCallBuilderImpl()510*6777b538SAndroid Build Coastguard Worker ~AsyncCallBuilderImpl() { 511*6777b538SAndroid Build Coastguard Worker // Must use WithArgs() since the method takes arguments. 512*6777b538SAndroid Build Coastguard Worker // Should be optimized out if the code is bug-free. 513*6777b538SAndroid Build Coastguard Worker CHECK(!this->sequence_bound_); 514*6777b538SAndroid Build Coastguard Worker } 515*6777b538SAndroid Build Coastguard Worker 516*6777b538SAndroid Build Coastguard Worker template <typename... BoundArgs> WithArgs(BoundArgs &&...bound_args)517*6777b538SAndroid Build Coastguard Worker auto WithArgs(BoundArgs&&... bound_args) { 518*6777b538SAndroid Build Coastguard Worker const SequenceBound* const sequence_bound = 519*6777b538SAndroid Build Coastguard Worker std::exchange(this->sequence_bound_, nullptr); 520*6777b538SAndroid Build Coastguard Worker return AsyncCallWithBoundArgsBuilder<ReturnType>( 521*6777b538SAndroid Build Coastguard Worker sequence_bound, this->location_, 522*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce(this->method_, 523*6777b538SAndroid Build Coastguard Worker sequence_bound->storage_.GetPtrForBind(), 524*6777b538SAndroid Build Coastguard Worker std::forward<BoundArgs>(bound_args)...)); 525*6777b538SAndroid Build Coastguard Worker } 526*6777b538SAndroid Build Coastguard Worker 527*6777b538SAndroid Build Coastguard Worker private: 528*6777b538SAndroid Build Coastguard Worker friend SequenceBound; 529*6777b538SAndroid Build Coastguard Worker 530*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default; 531*6777b538SAndroid Build Coastguard Worker AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default; 532*6777b538SAndroid Build Coastguard Worker }; 533*6777b538SAndroid Build Coastguard Worker 534*6777b538SAndroid Build Coastguard Worker // `MethodRef` is either a member function pointer type or a member function 535*6777b538SAndroid Build Coastguard Worker // pointer type wrapped with `internal::IgnoreResultHelper`. 536*6777b538SAndroid Build Coastguard Worker // `R` is the return type of `MethodRef`. This is always `void` if 537*6777b538SAndroid Build Coastguard Worker // `MethodRef` is an `internal::IgnoreResultHelper` wrapper. 538*6777b538SAndroid Build Coastguard Worker // `ArgsTuple` is a `std::tuple` with template type arguments corresponding to 539*6777b538SAndroid Build Coastguard Worker // the types of the method's parameters. 540*6777b538SAndroid Build Coastguard Worker template <typename MethodRef, typename R, typename ArgsTuple> 541*6777b538SAndroid Build Coastguard Worker using AsyncCallBuilder = AsyncCallBuilderImpl<MethodRef, R, ArgsTuple>; 542*6777b538SAndroid Build Coastguard Worker 543*6777b538SAndroid Build Coastguard Worker // Support factories when arguments are bound using `WithArgs()`. These 544*6777b538SAndroid Build Coastguard Worker // factories don't need to handle raw method pointers, since everything has 545*6777b538SAndroid Build Coastguard Worker // already been packaged into a base::OnceCallback. 546*6777b538SAndroid Build Coastguard Worker template <typename ReturnType> 547*6777b538SAndroid Build Coastguard Worker class AsyncCallWithBoundArgsBuilderBase { 548*6777b538SAndroid Build Coastguard Worker protected: AsyncCallWithBoundArgsBuilderBase(const SequenceBound * sequence_bound,const Location * location,CrossThreadTask<ReturnType ()> callback)549*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderBase(const SequenceBound* sequence_bound, 550*6777b538SAndroid Build Coastguard Worker const Location* location, 551*6777b538SAndroid Build Coastguard Worker CrossThreadTask<ReturnType()> callback) 552*6777b538SAndroid Build Coastguard Worker : sequence_bound_(sequence_bound), 553*6777b538SAndroid Build Coastguard Worker location_(location), 554*6777b538SAndroid Build Coastguard Worker callback_(std::move(callback)) { 555*6777b538SAndroid Build Coastguard Worker DCHECK(sequence_bound_); 556*6777b538SAndroid Build Coastguard Worker DCHECK(!sequence_bound_->storage_.is_null()); 557*6777b538SAndroid Build Coastguard Worker } 558*6777b538SAndroid Build Coastguard Worker 559*6777b538SAndroid Build Coastguard Worker // Subtle: the internal helpers rely on move elision. Preventing move 560*6777b538SAndroid Build Coastguard Worker // elision (e.g. using `std::move()` when returning the temporary) will 561*6777b538SAndroid Build Coastguard Worker // trigger a `CHECK()` since `sequence_bound_` is not reset to nullptr on 562*6777b538SAndroid Build Coastguard Worker // move. 563*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderBase( 564*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderBase&&) noexcept = default; 565*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderBase& operator=( 566*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderBase&&) noexcept = default; 567*6777b538SAndroid Build Coastguard Worker 568*6777b538SAndroid Build Coastguard Worker raw_ptr<const SequenceBound<T, CrossThreadTraits>> sequence_bound_; 569*6777b538SAndroid Build Coastguard Worker const raw_ptr<const Location> location_; 570*6777b538SAndroid Build Coastguard Worker CrossThreadTask<ReturnType()> callback_; 571*6777b538SAndroid Build Coastguard Worker }; 572*6777b538SAndroid Build Coastguard Worker 573*6777b538SAndroid Build Coastguard Worker // Note: this doesn't handle a void return type, which has an explicit 574*6777b538SAndroid Build Coastguard Worker // specialization below. 575*6777b538SAndroid Build Coastguard Worker template <typename ReturnType> 576*6777b538SAndroid Build Coastguard Worker class AsyncCallWithBoundArgsBuilderDefault 577*6777b538SAndroid Build Coastguard Worker : public AsyncCallWithBoundArgsBuilderBase<ReturnType> { 578*6777b538SAndroid Build Coastguard Worker public: ~AsyncCallWithBoundArgsBuilderDefault()579*6777b538SAndroid Build Coastguard Worker ~AsyncCallWithBoundArgsBuilderDefault() { 580*6777b538SAndroid Build Coastguard Worker // Must use Then() since the method's return type is not void. 581*6777b538SAndroid Build Coastguard Worker // Should be optimized out if the code is bug-free. 582*6777b538SAndroid Build Coastguard Worker CHECK(!this->sequence_bound_); 583*6777b538SAndroid Build Coastguard Worker } 584*6777b538SAndroid Build Coastguard Worker 585*6777b538SAndroid Build Coastguard Worker template <template <typename> class CallbackType, typename ThenArg> requires(IsCrossThreadTask<CallbackType>)586*6777b538SAndroid Build Coastguard Worker requires(IsCrossThreadTask<CallbackType>) 587*6777b538SAndroid Build Coastguard Worker void Then(CallbackType<void(ThenArg)> then_callback) && { 588*6777b538SAndroid Build Coastguard Worker this->sequence_bound_->PostTaskAndThenHelper(*this->location_, 589*6777b538SAndroid Build Coastguard Worker std::move(this->callback_), 590*6777b538SAndroid Build Coastguard Worker std::move(then_callback)); 591*6777b538SAndroid Build Coastguard Worker this->sequence_bound_ = nullptr; 592*6777b538SAndroid Build Coastguard Worker } 593*6777b538SAndroid Build Coastguard Worker 594*6777b538SAndroid Build Coastguard Worker protected: 595*6777b538SAndroid Build Coastguard Worker using AsyncCallWithBoundArgsBuilderBase< 596*6777b538SAndroid Build Coastguard Worker ReturnType>::AsyncCallWithBoundArgsBuilderBase; 597*6777b538SAndroid Build Coastguard Worker 598*6777b538SAndroid Build Coastguard Worker private: 599*6777b538SAndroid Build Coastguard Worker friend SequenceBound; 600*6777b538SAndroid Build Coastguard Worker 601*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderDefault( 602*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderDefault&&) = default; 603*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderDefault& operator=( 604*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderDefault&&) = default; 605*6777b538SAndroid Build Coastguard Worker }; 606*6777b538SAndroid Build Coastguard Worker 607*6777b538SAndroid Build Coastguard Worker class AsyncCallWithBoundArgsBuilderVoid 608*6777b538SAndroid Build Coastguard Worker : public AsyncCallWithBoundArgsBuilderBase<void> { 609*6777b538SAndroid Build Coastguard Worker public: 610*6777b538SAndroid Build Coastguard Worker // Note: despite being here, this is actually still protected, since it is 611*6777b538SAndroid Build Coastguard Worker // protected on the base class. 612*6777b538SAndroid Build Coastguard Worker using AsyncCallWithBoundArgsBuilderBase< 613*6777b538SAndroid Build Coastguard Worker void>::AsyncCallWithBoundArgsBuilderBase; 614*6777b538SAndroid Build Coastguard Worker ~AsyncCallWithBoundArgsBuilderVoid()615*6777b538SAndroid Build Coastguard Worker ~AsyncCallWithBoundArgsBuilderVoid() { 616*6777b538SAndroid Build Coastguard Worker if (this->sequence_bound_) { 617*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask(*this->sequence_bound_->impl_task_runner_, 618*6777b538SAndroid Build Coastguard Worker *this->location_, 619*6777b538SAndroid Build Coastguard Worker std::move(this->callback_)); 620*6777b538SAndroid Build Coastguard Worker } 621*6777b538SAndroid Build Coastguard Worker } 622*6777b538SAndroid Build Coastguard Worker Then(CrossThreadTask<void ()> then_callback)623*6777b538SAndroid Build Coastguard Worker void Then(CrossThreadTask<void()> then_callback) && { 624*6777b538SAndroid Build Coastguard Worker this->sequence_bound_->PostTaskAndThenHelper(*this->location_, 625*6777b538SAndroid Build Coastguard Worker std::move(this->callback_), 626*6777b538SAndroid Build Coastguard Worker std::move(then_callback)); 627*6777b538SAndroid Build Coastguard Worker this->sequence_bound_ = nullptr; 628*6777b538SAndroid Build Coastguard Worker } 629*6777b538SAndroid Build Coastguard Worker 630*6777b538SAndroid Build Coastguard Worker private: 631*6777b538SAndroid Build Coastguard Worker friend SequenceBound; 632*6777b538SAndroid Build Coastguard Worker 633*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderVoid(AsyncCallWithBoundArgsBuilderVoid&&) = 634*6777b538SAndroid Build Coastguard Worker default; 635*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderVoid& operator=( 636*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderVoid&&) = default; 637*6777b538SAndroid Build Coastguard Worker }; 638*6777b538SAndroid Build Coastguard Worker 639*6777b538SAndroid Build Coastguard Worker template <typename ReturnType> 640*6777b538SAndroid Build Coastguard Worker using AsyncCallWithBoundArgsBuilder = typename std::conditional< 641*6777b538SAndroid Build Coastguard Worker std::is_void_v<ReturnType>, 642*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderVoid, 643*6777b538SAndroid Build Coastguard Worker AsyncCallWithBoundArgsBuilderDefault<ReturnType>>::type; 644*6777b538SAndroid Build Coastguard Worker PostTaskAndThenHelper(const Location & location,CrossThreadTask<void ()> callback,CrossThreadTask<void ()> then_callback)645*6777b538SAndroid Build Coastguard Worker void PostTaskAndThenHelper(const Location& location, 646*6777b538SAndroid Build Coastguard Worker CrossThreadTask<void()> callback, 647*6777b538SAndroid Build Coastguard Worker CrossThreadTask<void()> then_callback) const { 648*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTaskAndReply(*impl_task_runner_, location, 649*6777b538SAndroid Build Coastguard Worker std::move(callback), 650*6777b538SAndroid Build Coastguard Worker std::move(then_callback)); 651*6777b538SAndroid Build Coastguard Worker } 652*6777b538SAndroid Build Coastguard Worker 653*6777b538SAndroid Build Coastguard Worker template <typename ReturnType, 654*6777b538SAndroid Build Coastguard Worker template <typename> 655*6777b538SAndroid Build Coastguard Worker class CallbackType, 656*6777b538SAndroid Build Coastguard Worker typename ThenArg> requires(IsCrossThreadTask<CallbackType>)657*6777b538SAndroid Build Coastguard Worker requires(IsCrossThreadTask<CallbackType>) 658*6777b538SAndroid Build Coastguard Worker void PostTaskAndThenHelper(const Location& location, 659*6777b538SAndroid Build Coastguard Worker CrossThreadTask<ReturnType()> callback, 660*6777b538SAndroid Build Coastguard Worker CallbackType<void(ThenArg)> then_callback) const { 661*6777b538SAndroid Build Coastguard Worker CrossThreadTask<void(ThenArg)>&& once_then_callback = 662*6777b538SAndroid Build Coastguard Worker std::move(then_callback); 663*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTaskAndReplyWithResult( 664*6777b538SAndroid Build Coastguard Worker *impl_task_runner_, location, std::move(callback), 665*6777b538SAndroid Build Coastguard Worker std::move(once_then_callback)); 666*6777b538SAndroid Build Coastguard Worker } 667*6777b538SAndroid Build Coastguard Worker 668*6777b538SAndroid Build Coastguard Worker // Helper to support move construction and move assignment. 669*6777b538SAndroid Build Coastguard Worker // 670*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/1382549): Constrain this so converting between 671*6777b538SAndroid Build Coastguard Worker // std::unique_ptr<T> and T are explicitly forbidden (rather than simply 672*6777b538SAndroid Build Coastguard Worker // failing to build in spectacular ways). 673*6777b538SAndroid Build Coastguard Worker template <typename From> MoveRecordFrom(From && other)674*6777b538SAndroid Build Coastguard Worker void MoveRecordFrom(From&& other) { 675*6777b538SAndroid Build Coastguard Worker impl_task_runner_ = std::move(other.impl_task_runner_); 676*6777b538SAndroid Build Coastguard Worker 677*6777b538SAndroid Build Coastguard Worker storage_.TakeFrom(std::move(other.storage_)); 678*6777b538SAndroid Build Coastguard Worker } 679*6777b538SAndroid Build Coastguard Worker 680*6777b538SAndroid Build Coastguard Worker Storage storage_; 681*6777b538SAndroid Build Coastguard Worker 682*6777b538SAndroid Build Coastguard Worker // Task runner which manages `storage_`. An object owned by `storage_` (if 683*6777b538SAndroid Build Coastguard Worker // any) will be constructed, destroyed, and otherwise used only on this task 684*6777b538SAndroid Build Coastguard Worker // runner. 685*6777b538SAndroid Build Coastguard Worker scoped_refptr<SequencedTaskRunner> impl_task_runner_; 686*6777b538SAndroid Build Coastguard Worker }; 687*6777b538SAndroid Build Coastguard Worker 688*6777b538SAndroid Build Coastguard Worker } // namespace base 689*6777b538SAndroid Build Coastguard Worker 690*6777b538SAndroid Build Coastguard Worker #endif // BASE_THREADING_SEQUENCE_BOUND_H_ 691