1/*
2 * Copyright 2016-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <typeinfo>
20
21#include <boost/intrusive/list.hpp>
22
23#include <folly/ScopeGuard.h>
24#include <folly/ThreadLocal.h>
25#include <folly/detail/Iterators.h>
26#include <folly/detail/Singleton.h>
27#include <folly/functional/Invoke.h>
28
29namespace folly {
30
31namespace detail {
32
33class SingletonThreadLocalBase {
34 public:
35 class UniqueBase {
36 public:
37 using Ptr = std::type_info const*;
38 using Ref = std::type_info const&;
39 struct Value {
40 bool init;
41 Ptr make;
42 Ptr tltag;
43 };
44
45 template <typename T, typename Tag, typename Make, typename TLTag>
46 explicit UniqueBase(TypeTuple<T, Tag, Make, TLTag>)
47 : UniqueBase(
48 typeid(T),
49 typeid(Tag),
50 typeid(Make),
51 typeid(TLTag),
52 detail::createGlobal<Value, TypeTuple<T, Tag, UniqueBase>>()) {}
53
54 UniqueBase(Ref type, Ref tag, Ref make, Ref tltag, Value& value);
55 };
56};
57
58} // namespace detail
59
60/// SingletonThreadLocal
61///
62/// Useful for a per-thread leaky-singleton model in libraries and applications.
63///
64/// By "leaky" it is meant that the T instances held by the instantiation
65/// SingletonThreadLocal<T> will survive until their owning thread exits.
66/// Therefore, they can safely be used before main() begins and after main()
67/// ends, and they can also safely be used in an application that spawns many
68/// temporary threads throughout its life.
69///
70/// Example:
71///
72/// struct UsefulButHasExpensiveCtor {
73/// UsefulButHasExpensiveCtor(); // this is expensive
74/// Result operator()(Arg arg);
75/// };
76///
77/// Result useful(Arg arg) {
78/// using Useful = UsefulButHasExpensiveCtor;
79/// auto& useful = folly::SingletonThreadLocal<Useful>::get();
80/// return useful(arg);
81/// }
82///
83/// As an example use-case, the random generators in <random> are expensive to
84/// construct. And their constructors are deterministic, but many cases require
85/// that they be randomly seeded. So folly::Random makes good canonical uses of
86/// folly::SingletonThreadLocal so that a seed is computed from the secure
87/// random device once per thread, and the random generator is constructed with
88/// the seed once per thread.
89///
90/// Keywords to help people find this class in search:
91/// Thread Local Singleton ThreadLocalSingleton
92template <
93 typename T,
94 typename Tag = detail::DefaultTag,
95 typename Make = detail::DefaultMake<T>,
96 typename TLTag = std::
97 conditional_t<std::is_same<Tag, detail::DefaultTag>::value, void, Tag>>
98class SingletonThreadLocal : private detail::SingletonThreadLocalBase {
99 private:
100 struct Unique final : UniqueBase {
101 Unique() : UniqueBase(detail::TypeTuple<T, Tag, Make, TLTag>{}) {}
102 };
103 static Unique unique;
104
105 struct Wrapper;
106
107 using NodeBase = boost::intrusive::list_base_hook<
108 boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
109
110 struct Node : NodeBase {
111 Wrapper*& cache;
112 bool& stale;
113
114 Node(Wrapper*& cache_, bool& stale_) : cache(cache_), stale(stale_) {
115 auto& wrapper = getWrapper();
116 wrapper.caches.push_front(*this);
117 cache = &wrapper;
118 }
119 ~Node() {
120 clear();
121 }
122
123 void clear() {
124 cache = nullptr;
125 stale = true;
126 }
127 };
128
129 using List =
130 boost::intrusive::list<Node, boost::intrusive::constant_time_size<false>>;
131
132 struct Wrapper {
133 using Object = invoke_result_t<Make>;
134 static_assert(std::is_convertible<Object&, T&>::value, "inconvertible");
135
136 // keep as first field, to save 1 instr in the fast path
137 Object object{Make{}()};
138 List caches;
139
140 /* implicit */ operator T&() {
141 return object;
142 }
143
144 ~Wrapper() {
145 for (auto& node : caches) {
146 node.clear();
147 }
148 caches.clear();
149 }
150 };
151
152 using WrapperTL = ThreadLocal<Wrapper, TLTag>;
153
154 SingletonThreadLocal() = delete;
155
156 FOLLY_ALWAYS_INLINE static WrapperTL& getWrapperTL() {
157 return detail::createGlobal<WrapperTL, Tag>();
158 }
159
160 FOLLY_NOINLINE static Wrapper& getWrapper() {
161 return *getWrapperTL();
162 }
163
164#ifdef FOLLY_TLS
165 FOLLY_NOINLINE static T& getSlow(Wrapper*& cache) {
166 (void)unique; // force the object not to be thrown out as unused
167 static thread_local Wrapper** check = &cache;
168 CHECK_EQ(check, &cache) << "inline function static thread_local merging";
169 static thread_local bool stale;
170 static thread_local Node node(cache, stale);
171 return !stale && node.cache ? *node.cache : getWrapper();
172 }
173#endif
174
175 public:
176 FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T& get() {
177#ifdef FOLLY_TLS
178 static thread_local Wrapper* cache;
179 return FOLLY_LIKELY(!!cache) ? *cache : getSlow(cache);
180#else
181 return getWrapper();
182#endif
183 }
184
185 class Accessor {
186 private:
187 using Inner = typename WrapperTL::Accessor;
188 using IteratorBase = typename Inner::Iterator;
189 using IteratorTag = std::bidirectional_iterator_tag;
190
191 Inner inner_;
192
193 explicit Accessor(Inner inner) noexcept : inner_(std::move(inner)) {}
194
195 public:
196 friend class SingletonThreadLocal<T, Tag, Make, TLTag>;
197
198 class Iterator
199 : public detail::
200 IteratorAdaptor<Iterator, IteratorBase, T, IteratorTag> {
201 private:
202 using Super =
203 detail::IteratorAdaptor<Iterator, IteratorBase, T, IteratorTag>;
204 using Super::Super;
205
206 public:
207 friend class Accessor;
208
209 T& dereference() const {
210 return const_cast<Iterator*>(this)->base()->object;
211 }
212 };
213
214 Accessor(const Accessor&) = delete;
215 Accessor& operator=(const Accessor&) = delete;
216 Accessor(Accessor&&) = default;
217 Accessor& operator=(Accessor&&) = default;
218
219 Iterator begin() const {
220 return Iterator(inner_.begin());
221 }
222
223 Iterator end() const {
224 return Iterator(inner_.end());
225 }
226 };
227
228 // Must use a unique Tag, takes a lock that is one per Tag
229 static Accessor accessAllThreads() {
230 return Accessor(getWrapperTL().accessAllThreads());
231 }
232};
233
234template <typename T, typename Tag, typename Make, typename TLTag>
235typename SingletonThreadLocal<T, Tag, Make, TLTag>::Unique
236 SingletonThreadLocal<T, Tag, Make, TLTag>::unique;
237
238} // namespace folly
239
240/// FOLLY_DECLARE_REUSED
241///
242/// Useful for local variables of container types, where it is desired to avoid
243/// the overhead associated with the local variable entering and leaving scope.
244/// Rather, where it is desired that the memory be reused between invocations
245/// of the same scope in the same thread rather than deallocated and reallocated
246/// between invocations of the same scope in the same thread. Note that the
247/// container will always be cleared between invocations; it is only the backing
248/// memory allocation which is reused.
249///
250/// Example:
251///
252/// void traverse_perform(int root);
253/// template <typename F>
254/// void traverse_each_child_r(int root, F const&);
255/// void traverse_depthwise(int root) {
256/// // preserves some of the memory backing these per-thread data structures
257/// FOLLY_DECLARE_REUSED(seen, std::unordered_set<int>);
258/// FOLLY_DECLARE_REUSED(work, std::vector<int>);
259/// // example algorithm that uses these per-thread data structures
260/// work.push_back(root);
261/// while (!work.empty()) {
262/// root = work.back();
263/// work.pop_back();
264/// seen.insert(root);
265/// traverse_perform(root);
266/// traverse_each_child_r(root, [&](int item) {
267/// if (!seen.count(item)) {
268/// work.push_back(item);
269/// }
270/// });
271/// }
272/// }
273#define FOLLY_DECLARE_REUSED(name, ...) \
274 struct __folly_reused_type_##name { \
275 __VA_ARGS__ object; \
276 }; \
277 auto& name = \
278 ::folly::SingletonThreadLocal<__folly_reused_type_##name>::get().object; \
279 auto __folly_reused_g_##name = ::folly::makeGuard([&] { name.clear(); })
280