27 #include <glog/logging.h> 48 #if !FOLLY_MOBILE && !defined(__APPLE__) && !defined(_MSC_VER) 49 #define FOLLY_TLD_USE_FOLLY_TLS 1 51 #undef FOLLY_TLD_USE_FOLLY_TLS 59 namespace threadlocal_detail {
79 void initIfZero(
bool locked);
83 parent = prev = next = entry;
89 prev = next =
nullptr;
94 return (next == parent);
122 if (
ptr ==
nullptr) {
126 DCHECK(deleter1 !=
nullptr);
134 if (
ptr !=
nullptr) {
144 DCHECK(
ptr ==
nullptr);
145 DCHECK(deleter1 ==
nullptr);
148 node.initIfZero(
true );
151 delete static_cast<Ptr
>(pt);
158 template <
class Ptr,
class Deleter>
159 void set(Ptr p,
const Deleter& d) {
165 DCHECK(
ptr ==
nullptr);
166 DCHECK(deleter2 ==
nullptr);
168 node.initIfZero(
true );
171 deleter2 =
new std::function<DeleterFunType>(
173 d2(static_cast<Ptr>(pt),
mode);
211 std::atomic<size_t> elementsCapacity{0};
217 bool removed_{
false};
220 return elementsCapacity.load(std::memory_order_relaxed);
224 elementsCapacity.store(capacity, std::memory_order_relaxed);
236 return &prev->elements[id].node;
240 return &
next->elements[id].node;
258 static constexpr
size_t kMaxKeys = 1UL << 16;
263 #if !defined(__APPLE__) && !defined(_MSC_VER) 266 pthread_key_delete(keys_[--size_]);
272 instance_.registerKeyImpl(key);
286 if (size_ == kMaxKeys) {
287 throw std::logic_error(
"pthread_key limit has already been reached");
289 keys_[size_++] = key;
294 pthread_key_t keys_[kMaxKeys];
308 constexpr
EntryID() : value(kEntryIDInvalid) {}
315 assert(
this != &other);
316 value = other.value.load();
329 return value.load(std::memory_order_relaxed);
334 if (
id != kEntryIDInvalid) {
359 static void onThreadExit(
void*
ptr);
379 void reserveHeadUnlocked(
uint32_t id);
413 template <
class Tag,
class AccessMode>
421 &StaticMeta::preFork,
422 &StaticMeta::onForkParent,
423 &StaticMeta::onForkChild);
431 static auto instance =
432 detail::createGlobal<StaticMeta<Tag, AccessMode>,
void>();
440 #ifdef FOLLY_TLD_USE_FOLLY_TLS 442 static FOLLY_TLS
size_t capacity{};
448 getSlowReserveAndCache(ent,
id, threadEntry, capacity);
450 return threadEntry->elements[id];
458 auto& inst = instance();
459 threadEntry = inst.threadEntry_();
465 assert(capacity >
id);
469 auto& meta = instance();
470 auto key = meta.pthreadKey_;
472 static_cast<ThreadEntry*
>(pthread_getspecific(key));
475 #ifdef FOLLY_TLD_USE_FOLLY_TLS 477 threadEntry = &threadEntrySingleton;
485 if (!threadEntry->
list) {
486 threadEntry->
list = threadEntryList;
488 threadEntryList->
head = threadEntry;
494 threadEntryList->
count++;
496 threadEntry->
meta = &meta;
497 int ret = pthread_setspecific(key, threadEntry);
504 return instance().lock_.try_lock();
508 instance().lock_.unlock();
513 auto& head = instance().head_;
515 head.next = head.prev = &head;
517 auto elementsCapacity = head.getElementsCapacity();
518 for (
size_t i = 0u;
i < elementsCapacity; ++
i) {
519 head.elements[
i].node.init(&head, static_cast<uint32_t>(
i));
522 ThreadEntry* threadEntry = instance().threadEntry_();
524 for (
size_t i = 0u;
i < elementsCapacity; ++
i) {
527 threadEntry, static_cast<uint32_t>(
i));
533 if (elementsCapacity != 0) {
534 instance().push_back(threadEntry);
536 instance().lock_.unlock();
static PthreadKeyUnregister instance_
void(void *, TLPDestructionMode) DeleterFunType
FOLLY_ALWAYS_INLINE ThreadEntry * getThreadEntry()
FOLLY_ALWAYS_INLINE bool empty() const
#define FOLLY_ALWAYS_INLINE
EntryID(EntryID &&other) noexcept
std::lock_guard< MicroSpinLock > MSLGuard
std::atomic< uint32_t > value
#define FOLLY_UNLIKELY(x)
—— Concurrent Priority Queue Implementation ——
std::function< DeleterFunType > * deleter2
requires E e noexcept(noexcept(s.error(std::move(e))))
folly::Optional< PskKeyExchangeMode > mode
void init(ThreadEntry *entry, uint32_t newId)
void BENCHFUN() push_back(size_t iters, size_t arg)
bool dispose(TLPDestructionMode mode)
constexpr PthreadKeyUnregister()
void checkPosixError(int err, Args &&...args)
void initIfZero(bool locked)
size_t getElementsCapacity() const noexcept
Encoder::MutableCompressedList list
GuardImpl guard(ErrorHandler &&handler)
std::enable_if< std::is_integral< Src >::value &&IsSomeString< Tgt >::value &&sizeof(Src)< 4 >::typetoAppend(Src value, Tgt *result){typedef typename std::conditional< std::is_signed< Src >::value, int64_t, uint64_t >::type Intermediate;toAppend< Tgt >static_cast< Intermediate >value), result);}template< class Src >typename std::enable_if< std::is_integral< Src >::value &&sizeof(Src)< 4 &&!std::is_same< Src, char >::value, size_t >::typeestimateSpaceNeeded(Src value){typedef typename std::conditional< std::is_signed< Src >::value, int64_t, uint64_t >::type Intermediate;return estimateSpaceNeeded(static_cast< Intermediate >value));}template< class Tgt, class Src >typename std::enable_if< std::is_enum< Src >::value &&IsSomeString< Tgt >::value >::typetoAppend(Src value, Tgt *result){toAppend(static_cast< typename std::underlying_type< Src >::type >value), result);}template< class Src >typename std::enable_if< std::is_enum< Src >::value, size_t >::typeestimateSpaceNeeded(Src value){return estimateSpaceNeeded(static_cast< typename std::underlying_type< Src >::type >value));}namespace detail{constexpr int kConvMaxDecimalInShortestLow=-6;constexpr int kConvMaxDecimalInShortestHigh=21;}template< class Tgt, class Src >typename std::enable_if< std::is_floating_point< Src >::value &&IsSomeString< Tgt >::value >::typetoAppend(Src value, Tgt *result, double_conversion::DoubleToStringConverter::DtoaMode mode, unsigned int numDigits){using namespace double_conversion;DoubleToStringConverter conv(DoubleToStringConverter::NO_FLAGS,"Infinity","NaN", 'E', detail::kConvMaxDecimalInShortestLow, detail::kConvMaxDecimalInShortestHigh, 6, 1);char buffer[256];StringBuilder builder(buffer, sizeof(buffer));switch(mode){case DoubleToStringConverter::SHORTEST:conv.ToShortest(value,&builder);break;case DoubleToStringConverter::SHORTEST_SINGLE:conv.ToShortestSingle(static_cast< float >value),&builder);break;case DoubleToStringConverter::FIXED:conv.ToFixed(value, int(numDigits),&builder);break;default:CHECK(mode==DoubleToStringConverter::PRECISION);conv.ToPrecision(value, int(numDigits),&builder);break;}const size_t length=size_t(builder.position());builder.Finalize();result->append(buffer, length);}template< class Tgt, class Src >typename std::enable_if< std::is_floating_point< Src >::value &&IsSomeString< Tgt >::value >::typetoAppend(Src value, Tgt *result){toAppend(value, result, double_conversion::DoubleToStringConverter::SHORTEST, 0);}template< class Src >typename std::enable_if< std::is_floating_point< Src >::value, size_t >::typeestimateSpaceNeeded(Src value){constexpr int kMaxMantissaSpace=double_conversion::DoubleToStringConverter::kBase10MaximalLength+1;constexpr int kMaxExponentSpace=2+3;static const int kMaxPositiveSpace=std::max({kMaxMantissaSpace+kMaxExponentSpace, kMaxMantissaSpace-detail::kConvMaxDecimalInShortestLow, detail::kConvMaxDecimalInShortestHigh,});return size_t(kMaxPositiveSpace+(value< 0?1:0));}template< class Src >struct HasLengthEstimator:std::false_type{};template< class Src >constexpr typename std::enable_if< !std::is_fundamental< Src >::value &&!IsSomeString< Src >::value &&!std::is_convertible< Src, const char * >::value &&!std::is_convertible< Src, StringPiece >::value &&!std::is_enum< Src >::value &&!HasLengthEstimator< Src >::value, size_t >::typeestimateSpaceNeeded(const Src &){return sizeof(Src)+1;}namespace detail{template< class Tgt >typename std::enable_if< IsSomeString< Tgt >::value, size_t >::typeestimateSpaceToReserve(size_t sofar, Tgt *){return sofar;}template< class T, class...Ts >size_t estimateSpaceToReserve(size_t sofar, const T &v, const Ts &...vs){return estimateSpaceToReserve(sofar+estimateSpaceNeeded(v), vs...);}template< class...Ts >void reserveInTarget(const Ts &...vs){getLastElement(vs...) -> reserve(estimateSpaceToReserve(0, vs...))
uint32_t getOrAllocate(StaticMetaBase &meta)
EntryID & operator=(EntryID &&other)
FOLLY_ALWAYS_INLINE bool zero() const
FOLLY_NODISCARD detail::ScopeGuardImplDecay< F, true > makeGuard(F &&f) noexcept(noexcept(detail::ScopeGuardImplDecay< F, true >(static_cast< F && >(f))))
DeleterFunType * deleter1
constexpr uint32_t kEntryIDInvalid
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
void initZero(ThreadEntry *entry, uint32_t newId)
static void registerKey(pthread_key_t key)
void registerKeyImpl(pthread_key_t key)
static void registerHandler(void *object, folly::Function< bool()> prepare, folly::Function< void()> parent, folly::Function< void()> child)
ElementWrapper * elements
folly::Function< void()> parent
void setElementsCapacity(size_t capacity) noexcept