1 // Copyright 2017 The Chromium Authors. All rights reserved. 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/threading/sequence_local_storage_map.h" 13 14 namespace base { 15 16 namespace internal { 17 BASE_EXPORT int GetNextSequenceLocalStorageSlotNumber(); 18 } 19 20 // SequenceLocalStorageSlot allows arbitrary values to be stored and retrieved 21 // from a sequence. Values are deleted when the sequence is deleted. 22 // 23 // Example usage: 24 // 25 // namespace { 26 // base::LazyInstance<SequenceLocalStorageSlot<int>> sls_value; 27 // } 28 // 29 // void Read() { 30 // int value = sls_value.Get().Get(); 31 // ... 32 // } 33 // 34 // void Write() { 35 // sls_value.Get().Set(42); 36 // } 37 // 38 // void PostTasks() { 39 // // Since Read() runs on the same sequence as Write(), it 40 // // will read the value "42". A Read() running on a different 41 // // sequence would not see that value. 42 // scoped_refptr<base::SequencedTaskRunner> task_runner = ...; 43 // task_runner->PostTask(FROM_HERE, base::BindOnce(&Write)); 44 // task_runner->PostTask(FROM_HERE, base::BindOnce(&Read)); 45 // } 46 // 47 // SequenceLocalStorageSlot must be used within the scope of a 48 // ScopedSetSequenceLocalStorageMapForCurrentThread object. 49 // Note: this is true on all TaskScheduler workers and on threads bound to a 50 // MessageLoop. 51 template <typename T, typename Deleter = std::default_delete<T>> 52 class SequenceLocalStorageSlot { 53 public: SequenceLocalStorageSlot()54 SequenceLocalStorageSlot() 55 : slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {} 56 ~SequenceLocalStorageSlot() = default; 57 58 // Get the sequence-local value stored in this slot. Returns a 59 // default-constructed value if no value was previously set. Get()60 T& Get() { 61 void* value = 62 internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_); 63 64 // Sets and returns a default-constructed value if no value was previously 65 // set. 66 if (!value) { 67 Set(T()); 68 return Get(); 69 } 70 return *(static_cast<T*>(value)); 71 } 72 73 // Set this slot's sequence-local value to |value|. 74 // Note that if T is expensive to copy, it may be more appropriate to instead 75 // store a std::unique_ptr<T>. This is enforced by the 76 // DISALLOW_COPY_AND_ASSIGN style rather than directly by this class however. Set(T value)77 void Set(T value) { 78 // Allocates the |value| with new rather than std::make_unique. 79 // Since SequenceLocalStorageMap needs to store values of various types 80 // within the same map, the type of value_destructor_pair.value is void* 81 // (std::unique_ptr<void> is invalid). Memory is freed by calling 82 // |value_destructor_pair.destructor| in the destructor of 83 // ValueDestructorPair which is invoked when the value is overwritten by 84 // another call to SequenceLocalStorageMap::Set or when the 85 // SequenceLocalStorageMap is deleted. 86 T* value_ptr = new T(std::move(value)); 87 88 internal::SequenceLocalStorageMap::ValueDestructorPair::DestructorFunc* 89 destructor = [](void* ptr) { Deleter()(static_cast<T*>(ptr)); }; 90 91 internal::SequenceLocalStorageMap::ValueDestructorPair 92 value_destructor_pair(value_ptr, destructor); 93 94 internal::SequenceLocalStorageMap::GetForCurrentThread().Set( 95 slot_id_, std::move(value_destructor_pair)); 96 } 97 98 private: 99 // |slot_id_| is used as a key in SequenceLocalStorageMap 100 const int slot_id_; 101 DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageSlot); 102 }; 103 104 } // namespace base 105 #endif // BASE_THREADING_SEQUENCE_LOCAL_STORAGE_SLOT_H_ 106