xref: /aosp_15_r20/external/cronet/base/threading/sequence_local_storage_slot.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_
6 #define BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_
7 
8 #include <memory>
9 #include <type_traits>
10 #include <utility>
11 
12 #include "base/base_export.h"
13 #include "base/template_util.h"
14 #include "base/threading/sequence_local_storage_map.h"
15 #include "third_party/abseil-cpp/absl/meta/type_traits.h"
16 
17 namespace base {
18 
19 namespace internal {
20 BASE_EXPORT int GetNextSequenceLocalStorageSlotNumber();
21 }
22 
23 // SequenceLocalStorageSlot allows arbitrary values to be stored and retrieved
24 // from a sequence. Values are deleted when the sequence is deleted.
25 //
26 // Example usage:
27 //
28 // int& GetSequenceLocalStorage()
29 //     static SequenceLocalStorageSlot<int> sls_value;
30 //     return sls_value->GetOrCreateValue();
31 // }
32 //
33 // void Read() {
34 //   int value = GetSequenceLocalStorage();
35 //   ...
36 // }
37 //
38 // void Write() {
39 //   GetSequenceLocalStorage() = 42;
40 // }
41 //
42 // void PostTasks() {
43 //   // Since Read() runs on the same sequence as Write(), it
44 //   // will read the value "42". A Read() running on a different
45 //   // sequence would not see that value.
46 //   scoped_refptr<base::SequencedTaskRunner> task_runner = ...;
47 //   task_runner->PostTask(FROM_HERE, base::BindOnce(&Write));
48 //   task_runner->PostTask(FROM_HERE, base::BindOnce(&Read));
49 // }
50 //
51 // SequenceLocalStorageSlot must be used within the scope of a
52 // ScopedSetSequenceLocalStorageMapForCurrentThread object.
53 // Note: this is true on all ThreadPool workers and on threads bound to a
54 // MessageLoop.
55 // SequenceLocalStorageSlot is implemented by either [Generic/Small]
56 // variants depending on the type. SequenceLocalStorageSlot itself
57 // doesn't support forward declared types and thus the variant
58 // [Generic/Small] needs to be specified explicitly.
59 
60 // Generic implementation for SequenceLocalStorageSlot.
61 template <typename T, typename Deleter = std::default_delete<T>>
62 class GenericSequenceLocalStorageSlot {
63  public:
GenericSequenceLocalStorageSlot()64   GenericSequenceLocalStorageSlot()
65       : slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {}
66 
67   GenericSequenceLocalStorageSlot(const GenericSequenceLocalStorageSlot&) =
68       delete;
69   GenericSequenceLocalStorageSlot& operator=(
70       const GenericSequenceLocalStorageSlot&) = delete;
71 
72   ~GenericSequenceLocalStorageSlot() = default;
73 
74   explicit operator bool() const {
75     return internal::SequenceLocalStorageMap::GetForCurrentThread().Has(
76         slot_id_);
77   }
78 
79   // Default-constructs the value for the current sequence if not
80   // already constructed. Then, returns the value.
GetOrCreateValue()81   T& GetOrCreateValue() {
82     auto* slot =
83         internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
84     if (!slot) {
85       return emplace();
86     }
87     return slot->external_value.value_as<T>();
88   }
89 
90   // Returns a pointer to the value for the current sequence. May be
91   // nullptr if the value was not constructed on the current sequence.
GetValuePointer()92   T* GetValuePointer() {
93     auto* value =
94         internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
95     if (value) {
96       return std::addressof(value->external_value.value_as<T>());
97     }
98     return nullptr;
99   }
GetValuePointer()100   const T* GetValuePointer() const {
101     return const_cast<GenericSequenceLocalStorageSlot*>(this)
102         ->GetValuePointer();
103   }
104 
105   T* operator->() { return GetValuePointer(); }
106   const T* operator->() const { return GetValuePointer(); }
107 
108   T& operator*() { return *GetValuePointer(); }
109   const T& operator*() const { return *GetValuePointer(); }
110 
reset()111   void reset() {
112     internal::SequenceLocalStorageMap::GetForCurrentThread().Reset(slot_id_);
113   }
114 
115   // Constructs this slot's sequence-local value with |args...| and returns a
116   // pointer to the created object.
117   template <class... Args>
emplace(Args &&...args)118   T& emplace(Args&&... args) {
119     T* value_ptr = new T(std::forward<Args>(args)...);
120     Adopt(value_ptr);
121     return *value_ptr;
122   }
123 
124  private:
125   // Takes ownership of |value_ptr|.
Adopt(T * value_ptr)126   void Adopt(T* value_ptr) {
127     // Since SequenceLocalStorageMap needs to store values of various types
128     // within the same map, the type of value_destructor_pair.value is void*
129     // (std::unique_ptr<void> is invalid). Memory is freed by calling
130     // |value_destructor_pair.destructor| in the destructor of
131     // ValueDestructorPair which is invoked when the value is overwritten by
132     // another call to SequenceLocalStorageMap::Set or when the
133     // SequenceLocalStorageMap is deleted.
134     internal::SequenceLocalStorageMap::ExternalValue value;
135     value.emplace(value_ptr);
136     internal::SequenceLocalStorageMap::ValueDestructorPair
137         value_destructor_pair(
138             std::move(value),
139             internal::SequenceLocalStorageMap::MakeExternalDestructor<
140                 T, Deleter>());
141 
142     internal::SequenceLocalStorageMap::GetForCurrentThread().Set(
143         slot_id_, std::move(value_destructor_pair));
144   }
145 
146   // |slot_id_| is used as a key in SequenceLocalStorageMap
147   const int slot_id_;
148 };
149 
150 // Implementation for SequenceLocalStorageSlot optimized for small and trivial
151 // objects.
152 template <class T>
153 class SmallSequenceLocalStorageSlot {
154  public:
SmallSequenceLocalStorageSlot()155   SmallSequenceLocalStorageSlot()
156       : slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {}
157 
158   SmallSequenceLocalStorageSlot(const SmallSequenceLocalStorageSlot&) = delete;
159   SmallSequenceLocalStorageSlot& operator=(
160       const SmallSequenceLocalStorageSlot&) = delete;
161 
162   ~SmallSequenceLocalStorageSlot() = default;
163 
164   explicit operator bool() const {
165     return internal::SequenceLocalStorageMap::GetForCurrentThread().Has(
166         slot_id_);
167   }
168 
169   // Default-constructs the value for the current sequence if not
170   // already constructed. Then, returns the value.
GetOrCreateValue()171   T& GetOrCreateValue() {
172     auto* slot =
173         internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
174     if (!slot) {
175       return emplace();
176     }
177     return slot->inline_value.value_as<T>();
178   }
179 
180   // Returns a pointer to the value for the current sequence. May be
181   // nullptr if the value was not constructed on the current sequence.
GetValuePointer()182   T* GetValuePointer() {
183     auto* slot =
184         internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
185     if (!slot) {
186       return nullptr;
187     }
188     return &slot->inline_value.value_as<T>();
189   }
GetValuePointer()190   const T* GetValuePointer() const {
191     return const_cast<SmallSequenceLocalStorageSlot*>(this)->GetValuePointer();
192   }
193 
194   T* operator->() { return GetValuePointer(); }
195   const T* operator->() const { return GetValuePointer(); }
196 
197   T& operator*() { return *GetValuePointer(); }
198   const T& operator*() const { return *GetValuePointer(); }
199 
reset()200   void reset() {
201     internal::SequenceLocalStorageMap::GetForCurrentThread().Reset(slot_id_);
202   }
203 
204   // Constructs this slot's sequence-local value with |args...| and returns a
205   // pointer to the created object.
206   template <class... Args>
emplace(Args &&...args)207   T& emplace(Args&&... args) {
208     internal::SequenceLocalStorageMap::InlineValue value;
209     value.emplace<T>(std::forward<Args>(args)...);
210     internal::SequenceLocalStorageMap::ValueDestructorPair
211         value_destructor_pair(
212             std::move(value),
213             internal::SequenceLocalStorageMap::MakeInlineDestructor<T>());
214 
215     return internal::SequenceLocalStorageMap::GetForCurrentThread()
216         .Set(slot_id_, std::move(value_destructor_pair))
217         ->inline_value.value_as<T>();
218   }
219 
220  private:
221   // |slot_id_| is used as a key in SequenceLocalStorageMap
222   const int slot_id_;
223 };
224 
225 template <typename T,
226           typename Deleter = std::default_delete<T>,
227           bool IsSmall =
228               sizeof(T) <= sizeof(void*) && absl::is_trivially_relocatable<T>()>
229 struct SequenceLocalStorageSlot;
230 
231 template <typename T, typename Deleter>
232 struct SequenceLocalStorageSlot<T, Deleter, false>
233     : GenericSequenceLocalStorageSlot<T, Deleter> {};
234 
235 template <typename T>
236 struct SequenceLocalStorageSlot<T, std::default_delete<T>, true>
237     : SmallSequenceLocalStorageSlot<T> {};
238 
239 }  // namespace base
240 #endif  // BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_
241