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 <boost/intrusive/list.hpp>
20 
21 #include <folly/ScopeGuard.h>
22 #include <folly/ThreadLocal.h>
23 #include <folly/detail/Singleton.h>
24 #include <folly/functional/Invoke.h>
25 
26 namespace folly {
27 
28 /// SingletonThreadLocal
29 ///
30 /// Useful for a per-thread leaky-singleton model in libraries and applications.
31 ///
32 /// By "leaky" it is meant that the T instances held by the instantiation
33 /// SingletonThreadLocal<T> will survive until their owning thread exits.
34 /// Therefore, they can safely be used before main() begins and after main()
35 /// ends, and they can also safely be used in an application that spawns many
36 /// temporary threads throughout its life.
37 ///
38 /// Example:
39 ///
40 ///   struct UsefulButHasExpensiveCtor {
41 ///     UsefulButHasExpensiveCtor(); // this is expensive
42 ///     Result operator()(Arg arg);
43 ///   };
44 ///
45 ///   Result useful(Arg arg) {
46 ///     using Useful = UsefulButHasExpensiveCtor;
47 ///     auto& useful = folly::SingletonThreadLocal<Useful>::get();
48 ///     return useful(arg);
49 ///   }
50 ///
51 /// As an example use-case, the random generators in <random> are expensive to
52 /// construct. And their constructors are deterministic, but many cases require
53 /// that they be randomly seeded. So folly::Random makes good canonical uses of
54 /// folly::SingletonThreadLocal so that a seed is computed from the secure
55 /// random device once per thread, and the random generator is constructed with
56 /// the seed once per thread.
57 ///
58 /// Keywords to help people find this class in search:
59 /// Thread Local Singleton ThreadLocalSingleton
60 template <
61     typename T,
62     typename Tag = detail::DefaultTag,
63     typename Make = detail::DefaultMake<T>,
64     typename TLTag = _t<std::conditional<
65         std::is_same<Tag, detail::DefaultTag>::value,
66         void,
67         Tag>>>
68 class SingletonThreadLocal {
69  private:
70   struct Wrapper;
71 
72   using NodeBase = boost::intrusive::list_base_hook<
73       boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
74 
75   struct Node : NodeBase {
76     Wrapper*& cache;
77     bool& stale;
78 
NodeNode79     Node(Wrapper*& cache_, bool& stale_) : cache(cache_), stale(stale_) {
80       auto& wrapper = getWrapper();
81       wrapper.caches.push_front(*this);
82       cache = &wrapper;
83     }
~NodeNode84     ~Node() {
85       clear();
86     }
87 
clearNode88     void clear() {
89       cache = nullptr;
90       stale = true;
91     }
92   };
93 
94   using List =
95       boost::intrusive::list<Node, boost::intrusive::constant_time_size<false>>;
96 
97   struct Wrapper {
98     template <typename S>
99     using MakeRet = is_invocable_r<S, Make>;
100 
101     // keep as first field, to save 1 instr in the fast path
102     union {
103       alignas(alignof(T)) unsigned char storage[sizeof(T)];
104       T object;
105     };
106     List caches;
107 
108     /* implicit */ operator T&() {
109       return object;
110     }
111 
112     // normal make types
113     template <typename S = T, _t<std::enable_if<MakeRet<S>::value, int>> = 0>
WrapperWrapper114     Wrapper() {
115       (void)new (storage) S(Make{}());
116     }
117     // default and special make types for non-move-constructible T, until C++17
118     template <typename S = T, _t<std::enable_if<!MakeRet<S>::value, int>> = 0>
WrapperWrapper119     Wrapper() {
120       (void)Make{}(storage);
121     }
~WrapperWrapper122     ~Wrapper() {
123       for (auto& node : caches) {
124         node.clear();
125       }
126       caches.clear();
127       object.~T();
128     }
129   };
130 
131   using WrapperTL = ThreadLocal<Wrapper, TLTag>;
132 
133   SingletonThreadLocal() = delete;
134 
getWrapperTL()135   FOLLY_EXPORT FOLLY_NOINLINE static WrapperTL& getWrapperTL() {
136     static auto& entry = *detail::createGlobal<WrapperTL, Tag>();
137     return entry;
138   }
139 
getWrapper()140   FOLLY_NOINLINE static Wrapper& getWrapper() {
141     return *getWrapperTL();
142   }
143 
144 #ifdef FOLLY_TLS
getSlow(Wrapper * & cache)145   FOLLY_NOINLINE static T& getSlow(Wrapper*& cache) {
146     static thread_local Wrapper** check = &cache;
147     CHECK_EQ(check, &cache) << "inline function static thread_local merging";
148     static thread_local bool stale;
149     static thread_local Node node(cache, stale);
150     return !stale && node.cache ? *node.cache : getWrapper();
151   }
152 #endif
153 
154  public:
get()155   FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T& get() {
156 #ifdef FOLLY_TLS
157     static thread_local Wrapper* cache;
158     return FOLLY_LIKELY(!!cache) ? *cache : getSlow(cache);
159 #else
160     return getWrapper();
161 #endif
162   }
163 
164   // Must use a unique Tag, takes a lock that is one per Tag
accessAllThreads()165   static typename WrapperTL::Accessor accessAllThreads() {
166     return getWrapperTL().accessAllThreads();
167   }
168 };
169 
170 } // namespace folly
171 
172 /// FOLLY_DECLARE_REUSED
173 ///
174 /// Useful for local variables of container types, where it is desired to avoid
175 /// the overhead associated with the local variable entering and leaving scope.
176 /// Rather, where it is desired that the memory be reused between invocations
177 /// of the same scope in the same thread rather than deallocated and reallocated
178 /// between invocations of the same scope in the same thread. Note that the
179 /// container will always be cleared between invocations; it is only the backing
180 /// memory allocation which is reused.
181 ///
182 /// Example:
183 ///
184 ///   void traverse_perform(int root);
185 ///   template <typename F>
186 ///   void traverse_each_child_r(int root, F const&);
187 ///   void traverse_depthwise(int root) {
188 ///     // preserves some of the memory backing these per-thread data structures
189 ///     FOLLY_DECLARE_REUSED(seen, std::unordered_set<int>);
190 ///     FOLLY_DECLARE_REUSED(work, std::vector<int>);
191 ///     // example algorithm that uses these per-thread data structures
192 ///     work.push_back(root);
193 ///     while (!work.empty()) {
194 ///       root = work.back();
195 ///       work.pop_back();
196 ///       seen.insert(root);
197 ///       traverse_perform(root);
198 ///       traverse_each_child_r(root, [&](int item) {
199 ///         if (!seen.count(item)) {
200 ///           work.push_back(item);
201 ///         }
202 ///       });
203 ///     }
204 ///   }
205 #define FOLLY_DECLARE_REUSED(name, ...)                                        \
206   struct __folly_reused_type_##name {                                          \
207     __VA_ARGS__ object;                                                        \
208   };                                                                           \
209   auto& name =                                                                 \
210       ::folly::SingletonThreadLocal<__folly_reused_type_##name>::get().object; \
211   auto __folly_reused_g_##name = ::folly::makeGuard([&] { name.clear(); })
212