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 #include "base/threading/sequence_local_storage_map.h"
6 
7 #include <utility>
8 
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/threading/thread_local.h"
12 
13 namespace base {
14 namespace internal {
15 
16 namespace {
17 LazyInstance<ThreadLocalPointer<SequenceLocalStorageMap>>::Leaky
18     tls_current_sequence_local_storage = LAZY_INSTANCE_INITIALIZER;
19 }  // namespace
20 
21 SequenceLocalStorageMap::SequenceLocalStorageMap() = default;
22 
23 SequenceLocalStorageMap::~SequenceLocalStorageMap() = default;
24 
25 ScopedSetSequenceLocalStorageMapForCurrentThread::
ScopedSetSequenceLocalStorageMapForCurrentThread(SequenceLocalStorageMap * sequence_local_storage)26     ScopedSetSequenceLocalStorageMapForCurrentThread(
27         SequenceLocalStorageMap* sequence_local_storage) {
28   DCHECK(!tls_current_sequence_local_storage.Get().Get());
29   tls_current_sequence_local_storage.Get().Set(sequence_local_storage);
30 }
31 
32 ScopedSetSequenceLocalStorageMapForCurrentThread::
~ScopedSetSequenceLocalStorageMapForCurrentThread()33     ~ScopedSetSequenceLocalStorageMapForCurrentThread() {
34   tls_current_sequence_local_storage.Get().Set(nullptr);
35 }
36 
GetForCurrentThread()37 SequenceLocalStorageMap& SequenceLocalStorageMap::GetForCurrentThread() {
38   SequenceLocalStorageMap* current_sequence_local_storage =
39       tls_current_sequence_local_storage.Get().Get();
40 
41   DCHECK(current_sequence_local_storage)
42       << "SequenceLocalStorageSlot cannot be used because no "
43          "SequenceLocalStorageMap was stored in TLS. Use "
44          "ScopedSetSequenceLocalStorageMapForCurrentThread to store a "
45          "SequenceLocalStorageMap object in TLS.";
46 
47   return *current_sequence_local_storage;
48 }
49 
Get(int slot_id)50 void* SequenceLocalStorageMap::Get(int slot_id) {
51   const auto it = sls_map_.find(slot_id);
52   if (it == sls_map_.end())
53     return nullptr;
54   return it->second.value();
55 }
56 
Set(int slot_id,SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair)57 void SequenceLocalStorageMap::Set(
58     int slot_id,
59     SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair) {
60   auto it = sls_map_.find(slot_id);
61 
62   if (it == sls_map_.end())
63     sls_map_.emplace(slot_id, std::move(value_destructor_pair));
64   else
65     it->second = std::move(value_destructor_pair);
66 
67   // The maximum number of entries in the map is 256. This can be adjusted, but
68   // will require reviewing the choice of data structure for the map.
69   DCHECK_LE(sls_map_.size(), 256U);
70 }
71 
ValueDestructorPair(void * value,DestructorFunc * destructor)72 SequenceLocalStorageMap::ValueDestructorPair::ValueDestructorPair(
73     void* value,
74     DestructorFunc* destructor)
75     : value_(value), destructor_(destructor) {}
76 
~ValueDestructorPair()77 SequenceLocalStorageMap::ValueDestructorPair::~ValueDestructorPair() {
78   if (value_)
79     destructor_(value_);
80 }
81 
ValueDestructorPair(ValueDestructorPair && value_destructor_pair)82 SequenceLocalStorageMap::ValueDestructorPair::ValueDestructorPair(
83     ValueDestructorPair&& value_destructor_pair)
84     : value_(value_destructor_pair.value_),
85       destructor_(value_destructor_pair.destructor_) {
86   value_destructor_pair.value_ = nullptr;
87 }
88 
89 SequenceLocalStorageMap::ValueDestructorPair&
operator =(ValueDestructorPair && value_destructor_pair)90 SequenceLocalStorageMap::ValueDestructorPair::operator=(
91     ValueDestructorPair&& value_destructor_pair) {
92   // Destroy |value_| before overwriting it with a new value.
93   if (value_)
94     destructor_(value_);
95 
96   value_ = value_destructor_pair.value_;
97   destructor_ = value_destructor_pair.destructor_;
98 
99   value_destructor_pair.value_ = nullptr;
100 
101   return *this;
102 }
103 
104 }  // namespace internal
105 }  // namespace base
106