constexpr uint32_t kEntryIDInvalid = std::numeric_limits<uint32_t>::max();
+struct PthreadKeyUnregisterTester;
+
/**
* We want to disable onThreadExit call at the end of shutdown, we don't care
* about leaking memory at that point.
*
* Otherwise if ThreadLocal is used in a shared library, onThreadExit may be
* called after dlclose().
+ *
+ * This class has one single static instance; however since it's so widely used,
+ * directly or indirectly, by so many classes, we need to take care to avoid
+ * problems stemming from the Static Initialization/Destruction Order Fiascos.
+ * Therefore this class needs to be constexpr-constructible, so as to avoid
+ * the need for this to participate in init/destruction order.
*/
class PthreadKeyUnregister {
public:
+ static constexpr size_t kMaxKeys = 1UL << 16;
+
~PthreadKeyUnregister() {
std::lock_guard<std::mutex> lg(mutex_);
-
- for (const auto& key: keys_) {
- pthread_key_delete(key);
+ while (size_--) {
+ pthread_key_delete(keys_[size_]);
}
}
}
private:
- PthreadKeyUnregister() {}
+ /**
+ * Only one global instance should exist, hence this is private.
+ * See also the important note at the top of this class about `constexpr`
+ * usage.
+ */
+ constexpr PthreadKeyUnregister() : mutex_(), size_(0), keys_() { }
+ friend class folly::threadlocal_detail::PthreadKeyUnregisterTester;
void registerKeyImpl(pthread_key_t key) {
std::lock_guard<std::mutex> lg(mutex_);
-
- keys_.push_back(key);
+ CHECK_LT(size_, kMaxKeys);
+ keys_[size_++] = key;
}
std::mutex mutex_;
- std::vector<pthread_key_t> keys_;
+ size_t size_;
+ pthread_key_t keys_[kMaxKeys];
static PthreadKeyUnregister instance_;
};
-
// Held in a singleton to track our global instances.
// We have one of these per "Tag", by default one for the whole system
// (Tag=void).
t2.join();
}
+namespace folly { namespace threadlocal_detail {
+struct PthreadKeyUnregisterTester {
+ PthreadKeyUnregister p;
+ constexpr PthreadKeyUnregisterTester() = default;
+};
+}}
+
+TEST(ThreadLocal, UnregisterClassHasConstExprCtor) {
+ folly::threadlocal_detail::PthreadKeyUnregisterTester x;
+ // yep!
+ SUCCEED();
+}
+
// clang is unable to compile this code unless in c++14 mode.
#if __cplusplus >= 201402L
namespace {