Home | History | Annotate | Download | only in threading
      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:
     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.
     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.
     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