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