proxygen
SingletonThreadLocal.h
Go to the documentation of this file.
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>
25 
26 namespace folly {
27 
60 template <
61  typename T,
62  typename Tag = detail::DefaultTag,
63  typename Make = detail::DefaultMake<T>,
64  typename TLTag = _t<std::conditional<
66  void,
67  Tag>>>
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 {
77  bool& stale;
78 
79  Node(Wrapper*& cache_, bool& stale_) : cache(cache_), stale(stale_) {
80  auto& wrapper = getWrapper();
81  wrapper.caches.push_front(*this);
82  cache = &wrapper;
83  }
84  ~Node() {
85  clear();
86  }
87 
88  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>
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)];
105  };
107 
108  /* implicit */ operator T&() {
109  return object;
110  }
111 
112  // normal make types
115  (void)new (storage) S(Make{}());
116  }
117  // default and special make types for non-move-constructible T, until C++17
120  (void)Make{}(storage);
121  }
123  for (auto& node : caches) {
124  node.clear();
125  }
126  caches.clear();
127  object.~T();
128  }
129  };
130 
132 
133  SingletonThreadLocal() = delete;
134 
136  static auto& entry = *detail::createGlobal<WrapperTL, Tag>();
137  return entry;
138  }
139 
141  return *getWrapperTL();
142  }
143 
144 #ifdef FOLLY_TLS
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:
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
166  return getWrapperTL().accessAllThreads();
167  }
168 };
169 
170 } // namespace folly
171 
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(); })
void * object
Definition: AtFork.cpp:32
#define FOLLY_ALWAYS_INLINE
Definition: CPortability.h:151
Accessor accessAllThreads() const
Definition: ThreadLocal.h:87
static FOLLY_NOINLINE Wrapper & getWrapper()
folly::std T
static WrapperTL::Accessor accessAllThreads()
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
#define FOLLY_EXPORT
Definition: CPortability.h:133
FOLLY_EXPORT static FOLLY_NOINLINE WrapperTL & getWrapperTL()
#define FOLLY_NOINLINE
Definition: CPortability.h:142
typename T::type _t
Definition: Traits.h:171
static const char *const value
Definition: Conv.cpp:50
boost::intrusive::list_base_hook< boost::intrusive::link_mode< boost::intrusive::auto_unlink >> NodeBase
#define FOLLY_LIKELY(x)
Definition: Likely.h:35
Node(Wrapper *&cache_, bool &stale_)
bool check(const dynamic &schema, const dynamic &value, bool check=true)