xref: /aosp_15_r20/external/cronet/base/threading/sequence_bound_internal.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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