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 <utility> 10 11 #include "base/base_export.h" 12 #include "base/template_util.h" 13 #include "base/threading/sequence_local_storage_map.h" 14 15 namespace base { 16 17 namespace internal { 18 BASE_EXPORT int GetNextSequenceLocalStorageSlotNumber(); 19 } 20 21 // SequenceLocalStorageSlot allows arbitrary values to be stored and retrieved 22 // from a sequence. Values are deleted when the sequence is deleted. 23 // 24 // Example usage: 25 // 26 // int& GetSequenceLocalStorage() 27 // static base::NoDestructor<SequenceLocalStorageSlot<int>> sls_value; 28 // return sls_value->GetOrCreateValue(); 29 // } 30 // 31 // void Read() { 32 // int value = GetSequenceLocalStorage(); 33 // ... 34 // } 35 // 36 // void Write() { 37 // GetSequenceLocalStorage() = 42; 38 // } 39 // 40 // void PostTasks() { 41 // // Since Read() runs on the same sequence as Write(), it 42 // // will read the value "42". A Read() running on a different 43 // // sequence would not see that value. 44 // scoped_refptr<base::SequencedTaskRunner> task_runner = ...; 45 // task_runner->PostTask(FROM_HERE, base::BindOnce(&Write)); 46 // task_runner->PostTask(FROM_HERE, base::BindOnce(&Read)); 47 // } 48 // 49 // SequenceLocalStorageSlot must be used within the scope of a 50 // ScopedSetSequenceLocalStorageMapForCurrentThread object. 51 // Note: this is true on all ThreadPool workers and on threads bound to a 52 // MessageLoop. 53 template <typename T, typename Deleter = std::default_delete<T>> 54 class SequenceLocalStorageSlot { 55 public: SequenceLocalStorageSlot()56 SequenceLocalStorageSlot() 57 : slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {} 58 59 SequenceLocalStorageSlot(const SequenceLocalStorageSlot&) = delete; 60 SequenceLocalStorageSlot& operator=(const SequenceLocalStorageSlot&) = delete; 61 62 ~SequenceLocalStorageSlot() = default; 63 64 operator bool() const { return GetValuePointer() != nullptr; } 65 66 // Default-constructs the value for the current sequence if not 67 // already constructed. Then, returns the value. GetOrCreateValue()68 T& GetOrCreateValue() { 69 T* ptr = GetValuePointer(); 70 if (!ptr) 71 ptr = emplace(); 72 return *ptr; 73 } 74 75 // Returns a pointer to the value for the current sequence. May be 76 // nullptr if the value was not constructed on the current sequence. GetValuePointer()77 T* GetValuePointer() { 78 void* ptr = 79 internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_); 80 return static_cast<T*>(ptr); 81 } GetValuePointer()82 const T* GetValuePointer() const { 83 return const_cast<SequenceLocalStorageSlot*>(this)->GetValuePointer(); 84 } 85 86 T* operator->() { return GetValuePointer(); } 87 const T* operator->() const { return GetValuePointer(); } 88 89 T& operator*() { return *GetValuePointer(); } 90 const T& operator*() const { return *GetValuePointer(); } 91 reset()92 void reset() { Adopt(nullptr); } 93 94 // Constructs this slot's sequence-local value with |args...| and returns a 95 // pointer to the created object. 96 template <class... Args> emplace(Args &&...args)97 T* emplace(Args&&... args) { 98 T* value_ptr = new T(std::forward<Args>(args)...); 99 Adopt(value_ptr); 100 return value_ptr; 101 } 102 103 private: 104 // Takes ownership of |value_ptr|. Adopt(T * value_ptr)105 void Adopt(T* value_ptr) { 106 // Since SequenceLocalStorageMap needs to store values of various types 107 // within the same map, the type of value_destructor_pair.value is void* 108 // (std::unique_ptr<void> is invalid). Memory is freed by calling 109 // |value_destructor_pair.destructor| in the destructor of 110 // ValueDestructorPair which is invoked when the value is overwritten by 111 // another call to SequenceLocalStorageMap::Set or when the 112 // SequenceLocalStorageMap is deleted. 113 internal::SequenceLocalStorageMap::ValueDestructorPair::DestructorFunc* 114 destructor = [](void* ptr) { Deleter()(static_cast<T*>(ptr)); }; 115 116 internal::SequenceLocalStorageMap::ValueDestructorPair 117 value_destructor_pair(value_ptr, destructor); 118 119 internal::SequenceLocalStorageMap::GetForCurrentThread().Set( 120 slot_id_, std::move(value_destructor_pair)); 121 } 122 123 // |slot_id_| is used as a key in SequenceLocalStorageMap 124 const int slot_id_; 125 }; 126 127 } // namespace base 128 #endif // BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_ 129