• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "base/threading/sequence_local_storage_map.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/compiler_specific.h"
11 #include "base/memory/raw_ptr.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace base {
15 namespace internal {
16 
17 namespace {
18 
19 constexpr int kSlotId = 1;
20 
21 class TRIVIAL_ABI SetOnDestroy {
22  public:
SetOnDestroy(bool * was_destroyed_ptr)23   SetOnDestroy(bool* was_destroyed_ptr)
24       : was_destroyed_ptr_(was_destroyed_ptr) {
25     DCHECK(was_destroyed_ptr_);
26     DCHECK(!(*was_destroyed_ptr_));
27   }
28 
29   SetOnDestroy(const SetOnDestroy&) = delete;
30   SetOnDestroy& operator=(const SetOnDestroy&) = delete;
31 
SetOnDestroy(SetOnDestroy && other)32   SetOnDestroy(SetOnDestroy&& other) {
33     swap(was_destroyed_ptr_, other.was_destroyed_ptr_);
34   }
operator =(SetOnDestroy && other)35   SetOnDestroy& operator=(SetOnDestroy&& other) {
36     swap(was_destroyed_ptr_, other.was_destroyed_ptr_);
37     return *this;
38   }
39 
~SetOnDestroy()40   ~SetOnDestroy() {
41     if (!was_destroyed_ptr_) {
42       return;
43     }
44     DCHECK(!(*was_destroyed_ptr_));
45     *was_destroyed_ptr_ = true;
46   }
47 
48  private:
49   raw_ptr<bool> was_destroyed_ptr_;
50 };
51 
52 template <typename T, typename... Args>
CreateExternalValueDestructorPair(Args...args)53 SequenceLocalStorageMap::ValueDestructorPair CreateExternalValueDestructorPair(
54     Args... args) {
55   internal::SequenceLocalStorageMap::ExternalValue value;
56   value.emplace(new T(args...));
57   auto* destructor =
58       SequenceLocalStorageMap::MakeExternalDestructor<T,
59                                                       std::default_delete<T>>();
60 
61   SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair{
62       std::move(value), destructor};
63 
64   return value_destructor_pair;
65 }
66 
67 template <typename T, typename... Args>
CreateInlineValueDestructorPair(Args...args)68 SequenceLocalStorageMap::ValueDestructorPair CreateInlineValueDestructorPair(
69     Args... args) {
70   internal::SequenceLocalStorageMap::InlineValue value;
71   value.emplace<T>(args...);
72   auto* destructor = SequenceLocalStorageMap::MakeInlineDestructor<T>();
73 
74   SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair{
75       std::move(value), destructor};
76 
77   return value_destructor_pair;
78 }
79 
80 }  // namespace
81 
82 // Verify that setting a value in the SequenceLocalStorageMap, then getting
83 // it will yield the same value.
TEST(SequenceLocalStorageMapTest,SetGetExternal)84 TEST(SequenceLocalStorageMapTest, SetGetExternal) {
85   SequenceLocalStorageMap sequence_local_storage_map;
86   ScopedSetSequenceLocalStorageMapForCurrentThread
87       scoped_sequence_local_storage_map(&sequence_local_storage_map);
88 
89   SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
90       CreateExternalValueDestructorPair<int>(5);
91 
92   sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
93 
94   EXPECT_EQ(
95       sequence_local_storage_map.Get(kSlotId)->external_value.value_as<int>(),
96       5);
97 }
98 
TEST(SequenceLocalStorageMapTest,SetGetInline)99 TEST(SequenceLocalStorageMapTest, SetGetInline) {
100   SequenceLocalStorageMap sequence_local_storage_map;
101   ScopedSetSequenceLocalStorageMapForCurrentThread
102       scoped_sequence_local_storage_map(&sequence_local_storage_map);
103 
104   SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
105       CreateInlineValueDestructorPair<int>(5);
106 
107   sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
108 
109   EXPECT_EQ(
110       sequence_local_storage_map.Get(kSlotId)->inline_value.value_as<int>(), 5);
111 }
112 
113 // Verify that the destructor is called on a value stored in the
114 // SequenceLocalStorageMap when SequenceLocalStorageMap is destroyed.
TEST(SequenceLocalStorageMapTest,DestructorExternal)115 TEST(SequenceLocalStorageMapTest, DestructorExternal) {
116   bool set_on_destruction = false;
117 
118   {
119     SequenceLocalStorageMap sequence_local_storage_map;
120     ScopedSetSequenceLocalStorageMapForCurrentThread
121         scoped_sequence_local_storage_map(&sequence_local_storage_map);
122 
123     SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
124         CreateExternalValueDestructorPair<SetOnDestroy>(&set_on_destruction);
125 
126     sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
127   }
128 
129   EXPECT_TRUE(set_on_destruction);
130 }
131 
132 // Verify that overwriting a value already in the SequenceLocalStorageMap
133 // calls value's destructor.
TEST(SequenceLocalStorageMapTest,DestructorCalledOnSetOverwriteExternal)134 TEST(SequenceLocalStorageMapTest, DestructorCalledOnSetOverwriteExternal) {
135   bool set_on_destruction = false;
136   bool set_on_destruction2 = false;
137   {
138     SequenceLocalStorageMap sequence_local_storage_map;
139     ScopedSetSequenceLocalStorageMapForCurrentThread
140         scoped_sequence_local_storage_map(&sequence_local_storage_map);
141 
142     SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
143         CreateExternalValueDestructorPair<SetOnDestroy>(&set_on_destruction);
144     SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair2 =
145         CreateExternalValueDestructorPair<SetOnDestroy>(&set_on_destruction2);
146 
147     sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
148 
149     ASSERT_FALSE(set_on_destruction);
150 
151     // Overwrites the old value in the slot.
152     sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair2));
153 
154     // Destructor should've been called for the old value in the slot, and not
155     // yet called for the new value.
156     EXPECT_TRUE(set_on_destruction);
157     EXPECT_FALSE(set_on_destruction2);
158   }
159   EXPECT_TRUE(set_on_destruction2);
160 }
161 
162 #if defined(__clang__) && HAS_ATTRIBUTE(trivial_abi)
163 #if !BUILDFLAG(IS_WIN)
164 // Test disabled on Windows due to
165 // https://github.com/llvm/llvm-project/issues/69394
166 
TEST(SequenceLocalStorageMapTest,DestructorInline)167 TEST(SequenceLocalStorageMapTest, DestructorInline) {
168   bool set_on_destruction = false;
169 
170   {
171     SequenceLocalStorageMap sequence_local_storage_map;
172     ScopedSetSequenceLocalStorageMapForCurrentThread
173         scoped_sequence_local_storage_map(&sequence_local_storage_map);
174 
175     SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
176         CreateInlineValueDestructorPair<SetOnDestroy>(&set_on_destruction);
177 
178     sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
179   }
180 
181   EXPECT_TRUE(set_on_destruction);
182 }
183 
TEST(SequenceLocalStorageMapTest,DestructorCalledOnSetOverwriteInline)184 TEST(SequenceLocalStorageMapTest, DestructorCalledOnSetOverwriteInline) {
185   bool set_on_destruction = false;
186   bool set_on_destruction2 = false;
187   {
188     SequenceLocalStorageMap sequence_local_storage_map;
189     ScopedSetSequenceLocalStorageMapForCurrentThread
190         scoped_sequence_local_storage_map(&sequence_local_storage_map);
191 
192     SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair =
193         CreateInlineValueDestructorPair<SetOnDestroy>(&set_on_destruction);
194     SequenceLocalStorageMap::ValueDestructorPair value_destructor_pair2 =
195         CreateInlineValueDestructorPair<SetOnDestroy>(&set_on_destruction2);
196 
197     sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair));
198 
199     ASSERT_FALSE(set_on_destruction);
200 
201     // Overwrites the old value in the slot.
202     sequence_local_storage_map.Set(kSlotId, std::move(value_destructor_pair2));
203 
204     // Destructor should've been called for the old value in the slot, and not
205     // yet called for the new value.
206     EXPECT_TRUE(set_on_destruction);
207     EXPECT_FALSE(set_on_destruction2);
208   }
209   EXPECT_TRUE(set_on_destruction2);
210 }
211 
212 #else  // !BUILDFLAG(IS_WIN)
213 
214 static_assert(!absl::is_trivially_relocatable<SetOnDestroy>(),
215               "A compiler change on Windows indicates the preprocessor "
216               "guarding the test above needs to be updated.");
217 
218 #endif  // !BUILDFLAG(IS_WIN)
219 #endif  //  defined(__clang__) && HAS_ATTRIBUTE(trivial_abi)
220 
221 }  // namespace internal
222 }  // namespace base
223