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