Commit bab85e25 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by facebook-github-bot-9

Avoid the ODR issue with ThreadLocalDetail's kInvalid

Summary: [Folly] Avoid the ODR issue with `ThreadLocalDetail`'s `kInvalid`.

The problem is that it is a `static constexpr` class member, so pull it out of the class.

Reviewed By: bmaurer

Differential Revision: D2549272

fb-gh-sync-id: 28a73e73b9cf9f21bee2bba2125513c02ef56ce2
parent ef40ac82
...@@ -161,7 +161,7 @@ struct ThreadEntry { ...@@ -161,7 +161,7 @@ struct ThreadEntry {
ThreadEntry* prev; ThreadEntry* prev;
}; };
constexpr uint32_t kEntryIDInvalid = std::numeric_limits<uint32_t>::max();
// Held in a singleton to track our global instances. // Held in a singleton to track our global instances.
// We have one of these per "Tag", by default one for the whole system // We have one of these per "Tag", by default one for the whole system
...@@ -178,20 +178,19 @@ struct StaticMeta { ...@@ -178,20 +178,19 @@ struct StaticMeta {
// fail). It allows us to keep a constexpr constructor and avoid SIOF. // fail). It allows us to keep a constexpr constructor and avoid SIOF.
class EntryID { class EntryID {
public: public:
static constexpr uint32_t kInvalid = std::numeric_limits<uint32_t>::max();
std::atomic<uint32_t> value; std::atomic<uint32_t> value;
constexpr EntryID() : value(kInvalid) { constexpr EntryID() : value(kEntryIDInvalid) {
} }
EntryID(EntryID&& other) noexcept : value(other.value.load()) { EntryID(EntryID&& other) noexcept : value(other.value.load()) {
other.value = kInvalid; other.value = kEntryIDInvalid;
} }
EntryID& operator=(EntryID&& other) { EntryID& operator=(EntryID&& other) {
assert(this != &other); assert(this != &other);
value = other.value.load(); value = other.value.load();
other.value = kInvalid; other.value = kEntryIDInvalid;
return *this; return *this;
} }
...@@ -208,7 +207,7 @@ struct StaticMeta { ...@@ -208,7 +207,7 @@ struct StaticMeta {
uint32_t getOrAllocate() { uint32_t getOrAllocate() {
uint32_t id = getOrInvalid(); uint32_t id = getOrInvalid();
if (id != kInvalid) { if (id != kEntryIDInvalid) {
return id; return id;
} }
// The lock inside allocate ensures that a single value is allocated // The lock inside allocate ensures that a single value is allocated
...@@ -356,7 +355,7 @@ struct StaticMeta { ...@@ -356,7 +355,7 @@ struct StaticMeta {
std::lock_guard<std::mutex> g(meta.lock_); std::lock_guard<std::mutex> g(meta.lock_);
id = ent->value.load(); id = ent->value.load();
if (id != EntryID::kInvalid) { if (id != kEntryIDInvalid) {
return id; return id;
} }
...@@ -368,7 +367,7 @@ struct StaticMeta { ...@@ -368,7 +367,7 @@ struct StaticMeta {
} }
uint32_t old_id = ent->value.exchange(id); uint32_t old_id = ent->value.exchange(id);
DCHECK_EQ(old_id, EntryID::kInvalid); DCHECK_EQ(old_id, kEntryIDInvalid);
return id; return id;
} }
...@@ -379,8 +378,8 @@ struct StaticMeta { ...@@ -379,8 +378,8 @@ struct StaticMeta {
std::vector<ElementWrapper> elements; std::vector<ElementWrapper> elements;
{ {
std::lock_guard<std::mutex> g(meta.lock_); std::lock_guard<std::mutex> g(meta.lock_);
uint32_t id = ent->value.exchange(EntryID::kInvalid); uint32_t id = ent->value.exchange(kEntryIDInvalid);
if (id == EntryID::kInvalid) { if (id == kEntryIDInvalid) {
return; return;
} }
...@@ -524,9 +523,6 @@ struct StaticMeta { ...@@ -524,9 +523,6 @@ struct StaticMeta {
} }
}; };
template <class Tag>
constexpr uint32_t StaticMeta<Tag>::EntryID::kInvalid;
#ifdef FOLLY_TLD_USE_FOLLY_TLS #ifdef FOLLY_TLD_USE_FOLLY_TLS
template <class Tag> template <class Tag>
FOLLY_TLS ThreadEntry StaticMeta<Tag>::threadEntry_ = {nullptr, 0, FOLLY_TLS ThreadEntry StaticMeta<Tag>::threadEntry_ = {nullptr, 0,
......
...@@ -250,14 +250,6 @@ TEST(ThreadLocal, InterleavedDestructors) { ...@@ -250,14 +250,6 @@ TEST(ThreadLocal, InterleavedDestructors) {
EXPECT_EQ(wVersionMax * 10, Widget::totalVal_); EXPECT_EQ(wVersionMax * 10, Widget::totalVal_);
} }
TEST(ThreadLocalPtr, ODRUseEntryIDkInvalid) {
// EntryID::kInvalid is odr-used
// see http://en.cppreference.com/w/cpp/language/static
const uint32_t* pInvalid =
&(threadlocal_detail::StaticMeta<void>::EntryID::kInvalid);
EXPECT_EQ(std::numeric_limits<uint32_t>::max(), *pInvalid);
}
class SimpleThreadCachedInt { class SimpleThreadCachedInt {
class NewTag; class NewTag;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment