1*6777b538SAndroid Build Coastguard Worker // Copyright 2022 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_INTERNAL_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_THREADING_SEQUENCE_BOUND_INTERNAL_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <memory> 9*6777b538SAndroid Build Coastguard Worker #include <type_traits> 10*6777b538SAndroid Build Coastguard Worker #include <utility> 11*6777b538SAndroid Build Coastguard Worker 12*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h" 13*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h" 14*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h" 15*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h" 16*6777b538SAndroid Build Coastguard Worker #include "base/location.h" 17*6777b538SAndroid Build Coastguard Worker #include "base/memory/aligned_memory.h" 18*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h" 19*6777b538SAndroid Build Coastguard Worker #include "base/task/sequenced_task_runner.h" 20*6777b538SAndroid Build Coastguard Worker 21*6777b538SAndroid Build Coastguard Worker namespace base::sequence_bound_internal { 22*6777b538SAndroid Build Coastguard Worker 23*6777b538SAndroid Build Coastguard Worker struct CrossThreadTraits { 24*6777b538SAndroid Build Coastguard Worker template <typename Signature> 25*6777b538SAndroid Build Coastguard Worker using CrossThreadTask = OnceCallback<Signature>; 26*6777b538SAndroid Build Coastguard Worker 27*6777b538SAndroid Build Coastguard Worker template <typename Functor, typename... Args> BindOnceCrossThreadTraits28*6777b538SAndroid Build Coastguard Worker static inline auto BindOnce(Functor&& functor, Args&&... args) { 29*6777b538SAndroid Build Coastguard Worker return ::base::BindOnce(std::forward<Functor>(functor), 30*6777b538SAndroid Build Coastguard Worker std::forward<Args>(args)...); 31*6777b538SAndroid Build Coastguard Worker } 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard Worker template <typename T> UnretainedCrossThreadTraits34*6777b538SAndroid Build Coastguard Worker static inline auto Unretained(T ptr) { 35*6777b538SAndroid Build Coastguard Worker return ::base::Unretained(ptr); 36*6777b538SAndroid Build Coastguard Worker } 37*6777b538SAndroid Build Coastguard Worker PostTaskCrossThreadTraits38*6777b538SAndroid Build Coastguard Worker static inline bool PostTask(SequencedTaskRunner& task_runner, 39*6777b538SAndroid Build Coastguard Worker const Location& location, 40*6777b538SAndroid Build Coastguard Worker OnceClosure&& task) { 41*6777b538SAndroid Build Coastguard Worker return task_runner.PostTask(location, std::move(task)); 42*6777b538SAndroid Build Coastguard Worker } 43*6777b538SAndroid Build Coastguard Worker PostTaskAndReplyCrossThreadTraits44*6777b538SAndroid Build Coastguard Worker static inline bool PostTaskAndReply(SequencedTaskRunner& task_runner, 45*6777b538SAndroid Build Coastguard Worker const Location& location, 46*6777b538SAndroid Build Coastguard Worker OnceClosure&& task, 47*6777b538SAndroid Build Coastguard Worker OnceClosure&& reply) { 48*6777b538SAndroid Build Coastguard Worker return task_runner.PostTaskAndReply(location, std::move(task), 49*6777b538SAndroid Build Coastguard Worker std::move(reply)); 50*6777b538SAndroid Build Coastguard Worker } 51*6777b538SAndroid Build Coastguard Worker 52*6777b538SAndroid Build Coastguard Worker template <typename TaskReturnType, typename ReplyArgType> PostTaskAndReplyWithResultCrossThreadTraits53*6777b538SAndroid Build Coastguard Worker static inline bool PostTaskAndReplyWithResult( 54*6777b538SAndroid Build Coastguard Worker SequencedTaskRunner& task_runner, 55*6777b538SAndroid Build Coastguard Worker const Location& location, 56*6777b538SAndroid Build Coastguard Worker OnceCallback<TaskReturnType()>&& task, 57*6777b538SAndroid Build Coastguard Worker OnceCallback<void(ReplyArgType)>&& reply) { 58*6777b538SAndroid Build Coastguard Worker return task_runner.PostTaskAndReplyWithResult(location, std::move(task), 59*6777b538SAndroid Build Coastguard Worker std::move(reply)); 60*6777b538SAndroid Build Coastguard Worker } 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker // Accept RepeatingCallback here since it's convertible to a OnceCallback. 63*6777b538SAndroid Build Coastguard Worker template <template <typename> class CallbackType> 64*6777b538SAndroid Build Coastguard Worker static constexpr bool IsCrossThreadTask = 65*6777b538SAndroid Build Coastguard Worker IsBaseCallback<CallbackType<void()>>; 66*6777b538SAndroid Build Coastguard Worker }; 67*6777b538SAndroid Build Coastguard Worker 68*6777b538SAndroid Build Coastguard Worker template <typename T, typename CrossThreadTraits> 69*6777b538SAndroid Build Coastguard Worker class Storage { 70*6777b538SAndroid Build Coastguard Worker public: 71*6777b538SAndroid Build Coastguard Worker using element_type = T; 72*6777b538SAndroid Build Coastguard Worker is_null()73*6777b538SAndroid Build Coastguard Worker bool is_null() const { return ptr_ == nullptr; } GetPtrForBind()74*6777b538SAndroid Build Coastguard Worker auto GetPtrForBind() const { return CrossThreadTraits::Unretained(ptr_); } GetRefForBind()75*6777b538SAndroid Build Coastguard Worker auto GetRefForBind() const { return std::cref(*ptr_); } 76*6777b538SAndroid Build Coastguard Worker 77*6777b538SAndroid Build Coastguard Worker // Marked NO_SANITIZE because cfi doesn't like casting uninitialized memory to 78*6777b538SAndroid Build Coastguard Worker // `T*`. However, this is safe here because: 79*6777b538SAndroid Build Coastguard Worker // 80*6777b538SAndroid Build Coastguard Worker // 1. The cast is well-defined (see https://eel.is/c++draft/basic.life#6) and 81*6777b538SAndroid Build Coastguard Worker // 2. The resulting pointer is only ever dereferenced on `task_runner`. 82*6777b538SAndroid Build Coastguard Worker // By the time SequenceBound's constructor returns, the task to construct 83*6777b538SAndroid Build Coastguard Worker // `T` will already be posted; thus, subsequent dereference of `ptr_` on 84*6777b538SAndroid Build Coastguard Worker // `task_runner` are safe. 85*6777b538SAndroid Build Coastguard Worker template <typename... Args> 86*6777b538SAndroid Build Coastguard Worker NO_SANITIZE("cfi-unrelated-cast") Construct(SequencedTaskRunner & task_runner,Args &&...args)87*6777b538SAndroid Build Coastguard Worker void Construct(SequencedTaskRunner& task_runner, Args&&... args) { 88*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/1382549): Use universal forwarding and assert that 89*6777b538SAndroid Build Coastguard Worker // T is constructible from args for better error messages. 90*6777b538SAndroid Build Coastguard Worker DCHECK(!alloc_); 91*6777b538SAndroid Build Coastguard Worker DCHECK(!ptr_); 92*6777b538SAndroid Build Coastguard Worker 93*6777b538SAndroid Build Coastguard Worker // Allocate space for but do not construct an instance of `T`. 94*6777b538SAndroid Build Coastguard Worker // AlignedAlloc() requires alignment be a multiple of sizeof(void*). 95*6777b538SAndroid Build Coastguard Worker alloc_ = AlignedAlloc( 96*6777b538SAndroid Build Coastguard Worker sizeof(T), sizeof(void*) > alignof(T) ? sizeof(void*) : alignof(T)); 97*6777b538SAndroid Build Coastguard Worker ptr_ = reinterpret_cast<T*>(alloc_.get()); 98*6777b538SAndroid Build Coastguard Worker 99*6777b538SAndroid Build Coastguard Worker // Ensure that `ptr_` will be initialized. 100*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask( 101*6777b538SAndroid Build Coastguard Worker task_runner, FROM_HERE, 102*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce(&InternalConstruct<Args...>, 103*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::Unretained(ptr_), 104*6777b538SAndroid Build Coastguard Worker std::forward<Args>(args)...)); 105*6777b538SAndroid Build Coastguard Worker } 106*6777b538SAndroid Build Coastguard Worker 107*6777b538SAndroid Build Coastguard Worker // Marked NO_SANITIZE since: 108*6777b538SAndroid Build Coastguard Worker // 1. SequenceBound can be moved before `ptr_` is constructed on its managing 109*6777b538SAndroid Build Coastguard Worker // `SequencedTaskRunner` but 110*6777b538SAndroid Build Coastguard Worker // 2. Implicit conversions to non-virtual base classes are allowed before the 111*6777b538SAndroid Build Coastguard Worker // lifetime of the object that `ptr_` points at has begun (see 112*6777b538SAndroid Build Coastguard Worker // https://eel.is/c++draft/basic.life#6). 113*6777b538SAndroid Build Coastguard Worker template <typename U> 114*6777b538SAndroid Build Coastguard Worker NO_SANITIZE("cfi-unrelated-cast") TakeFrom(Storage<U,CrossThreadTraits> && other)115*6777b538SAndroid Build Coastguard Worker void TakeFrom(Storage<U, CrossThreadTraits>&& other) { 116*6777b538SAndroid Build Coastguard Worker // Subtle: this must not use static_cast<>, since the lifetime of the 117*6777b538SAndroid Build Coastguard Worker // managed `T` may not have begun yet. However, the standard explicitly 118*6777b538SAndroid Build Coastguard Worker // still allows implicit conversion to a non-virtual base class. 119*6777b538SAndroid Build Coastguard Worker ptr_ = std::exchange(other.ptr_, nullptr); 120*6777b538SAndroid Build Coastguard Worker alloc_ = std::exchange(other.alloc_, nullptr); 121*6777b538SAndroid Build Coastguard Worker } 122*6777b538SAndroid Build Coastguard Worker Destruct(SequencedTaskRunner & task_runner)123*6777b538SAndroid Build Coastguard Worker void Destruct(SequencedTaskRunner& task_runner) { 124*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask( 125*6777b538SAndroid Build Coastguard Worker task_runner, FROM_HERE, 126*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce( 127*6777b538SAndroid Build Coastguard Worker &InternalDestruct, 128*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::Unretained(std::exchange(ptr_, nullptr)), 129*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::Unretained(std::exchange(alloc_, nullptr)))); 130*6777b538SAndroid Build Coastguard Worker } 131*6777b538SAndroid Build Coastguard Worker 132*6777b538SAndroid Build Coastguard Worker private: 133*6777b538SAndroid Build Coastguard Worker // Needed to allow conversions from compatible `U`s. 134*6777b538SAndroid Build Coastguard Worker template <typename U, typename V> 135*6777b538SAndroid Build Coastguard Worker friend class Storage; 136*6777b538SAndroid Build Coastguard Worker 137*6777b538SAndroid Build Coastguard Worker // Helpers for constructing and destroying `T` on its managing 138*6777b538SAndroid Build Coastguard Worker // `SequencedTaskRunner`. 139*6777b538SAndroid Build Coastguard Worker template <typename... Args> InternalConstruct(T * ptr,std::decay_t<Args> &&...args)140*6777b538SAndroid Build Coastguard Worker static void InternalConstruct(T* ptr, std::decay_t<Args>&&... args) { 141*6777b538SAndroid Build Coastguard Worker new (ptr) T(std::move(args)...); 142*6777b538SAndroid Build Coastguard Worker } 143*6777b538SAndroid Build Coastguard Worker InternalDestruct(T * ptr,void * alloc)144*6777b538SAndroid Build Coastguard Worker static void InternalDestruct(T* ptr, void* alloc) { 145*6777b538SAndroid Build Coastguard Worker ptr->~T(); 146*6777b538SAndroid Build Coastguard Worker AlignedFree(alloc); 147*6777b538SAndroid Build Coastguard Worker } 148*6777b538SAndroid Build Coastguard Worker 149*6777b538SAndroid Build Coastguard Worker // Pointer to the managed `T`. 150*6777b538SAndroid Build Coastguard Worker raw_ptr<T> ptr_ = nullptr; 151*6777b538SAndroid Build Coastguard Worker 152*6777b538SAndroid Build Coastguard Worker // Storage originally allocated by `AlignedAlloc()`. Maintained separately 153*6777b538SAndroid Build Coastguard Worker // from `ptr_` since the original, unadjusted pointer needs to be passed to 154*6777b538SAndroid Build Coastguard Worker // `AlignedFree()`. 155*6777b538SAndroid Build Coastguard Worker raw_ptr<void> alloc_ = nullptr; 156*6777b538SAndroid Build Coastguard Worker }; 157*6777b538SAndroid Build Coastguard Worker 158*6777b538SAndroid Build Coastguard Worker template <typename T, typename CrossThreadTraits> 159*6777b538SAndroid Build Coastguard Worker struct Storage<std::unique_ptr<T>, CrossThreadTraits> { 160*6777b538SAndroid Build Coastguard Worker public: 161*6777b538SAndroid Build Coastguard Worker using element_type = T; 162*6777b538SAndroid Build Coastguard Worker 163*6777b538SAndroid Build Coastguard Worker bool is_null() const { return ptr_ == nullptr; } 164*6777b538SAndroid Build Coastguard Worker auto GetPtrForBind() const { return CrossThreadTraits::Unretained(ptr_); } 165*6777b538SAndroid Build Coastguard Worker auto GetRefForBind() const { return std::cref(*ptr_); } 166*6777b538SAndroid Build Coastguard Worker 167*6777b538SAndroid Build Coastguard Worker template <typename U> 168*6777b538SAndroid Build Coastguard Worker void Construct(SequencedTaskRunner& task_runner, std::unique_ptr<U> arg) { 169*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/1382549): Use universal forwarding and assert that 170*6777b538SAndroid Build Coastguard Worker // there is one arg that is a unique_ptr for better error messages. 171*6777b538SAndroid Build Coastguard Worker DCHECK(!ptr_); 172*6777b538SAndroid Build Coastguard Worker 173*6777b538SAndroid Build Coastguard Worker ptr_ = arg.release(); 174*6777b538SAndroid Build Coastguard Worker // No additional storage needs to be allocated since `T` is already 175*6777b538SAndroid Build Coastguard Worker // constructed and lives on the heap. 176*6777b538SAndroid Build Coastguard Worker } 177*6777b538SAndroid Build Coastguard Worker 178*6777b538SAndroid Build Coastguard Worker template <typename U> 179*6777b538SAndroid Build Coastguard Worker void TakeFrom(Storage<std::unique_ptr<U>, CrossThreadTraits>&& other) { 180*6777b538SAndroid Build Coastguard Worker ptr_ = std::exchange(other.ptr_, nullptr); 181*6777b538SAndroid Build Coastguard Worker } 182*6777b538SAndroid Build Coastguard Worker 183*6777b538SAndroid Build Coastguard Worker void Destruct(SequencedTaskRunner& task_runner) { 184*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::PostTask( 185*6777b538SAndroid Build Coastguard Worker task_runner, FROM_HERE, 186*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::BindOnce( 187*6777b538SAndroid Build Coastguard Worker &InternalDestruct, 188*6777b538SAndroid Build Coastguard Worker CrossThreadTraits::Unretained(std::exchange(ptr_, nullptr)))); 189*6777b538SAndroid Build Coastguard Worker } 190*6777b538SAndroid Build Coastguard Worker 191*6777b538SAndroid Build Coastguard Worker private: 192*6777b538SAndroid Build Coastguard Worker // Needed to allow conversions from compatible `U`s. 193*6777b538SAndroid Build Coastguard Worker template <typename U, typename V> 194*6777b538SAndroid Build Coastguard Worker friend class Storage; 195*6777b538SAndroid Build Coastguard Worker 196*6777b538SAndroid Build Coastguard Worker static void InternalDestruct(T* ptr) { delete ptr; } 197*6777b538SAndroid Build Coastguard Worker 198*6777b538SAndroid Build Coastguard Worker // Pointer to the heap-allocated `T`. 199*6777b538SAndroid Build Coastguard Worker raw_ptr<T> ptr_ = nullptr; 200*6777b538SAndroid Build Coastguard Worker }; 201*6777b538SAndroid Build Coastguard Worker 202*6777b538SAndroid Build Coastguard Worker } // namespace base::sequence_bound_internal 203*6777b538SAndroid Build Coastguard Worker 204*6777b538SAndroid Build Coastguard Worker #endif // BASE_THREADING_SEQUENCE_BOUND_INTERNAL_H_ 205