blob: 526ad0ef39e7257515074bc83f7d495270b26792 [file] [log] [blame]
#include <c10/util/ThreadLocal.h>
#include <gtest/gtest.h>
#include <atomic>
#include <thread>
namespace {
TEST(ThreadLocal, TestNoOpScopeWithOneVar) {
C10_DEFINE_TLS_static(std::string, str);
}
TEST(ThreadLocalTest, TestNoOpScopeWithTwoVars) {
C10_DEFINE_TLS_static(std::string, str);
C10_DEFINE_TLS_static(std::string, str2);
}
TEST(ThreadLocalTest, TestScopeWithOneVar) {
C10_DEFINE_TLS_static(std::string, str);
EXPECT_EQ(*str, std::string());
EXPECT_EQ(*str, "");
*str = "abc";
EXPECT_EQ(*str, "abc");
EXPECT_EQ(str->length(), 3);
EXPECT_EQ(str.get(), "abc");
}
TEST(ThreadLocalTest, TestScopeWithTwoVars) {
C10_DEFINE_TLS_static(std::string, str);
EXPECT_EQ(*str, "");
C10_DEFINE_TLS_static(std::string, str2);
*str = "abc";
EXPECT_EQ(*str, "abc");
EXPECT_EQ(*str2, "");
*str2 = *str;
EXPECT_EQ(*str, "abc");
EXPECT_EQ(*str2, "abc");
str->clear();
EXPECT_EQ(*str, "");
EXPECT_EQ(*str2, "abc");
}
TEST(ThreadLocalTest, TestInnerScopeWithTwoVars) {
C10_DEFINE_TLS_static(std::string, str);
*str = "abc";
{
C10_DEFINE_TLS_static(std::string, str2);
EXPECT_EQ(*str2, "");
*str2 = *str;
EXPECT_EQ(*str, "abc");
EXPECT_EQ(*str2, "abc");
str->clear();
EXPECT_EQ(*str2, "abc");
}
EXPECT_EQ(*str, "");
}
struct Foo {
C10_DECLARE_TLS_class_static(Foo, std::string, str_);
};
C10_DEFINE_TLS_class_static(Foo, std::string, str_);
TEST(ThreadLocalTest, TestClassScope) {
EXPECT_EQ(*Foo::str_, "");
*Foo::str_ = "abc";
EXPECT_EQ(*Foo::str_, "abc");
EXPECT_EQ(Foo::str_->length(), 3);
EXPECT_EQ(Foo::str_.get(), "abc");
}
C10_DEFINE_TLS_static(std::string, global_);
C10_DEFINE_TLS_static(std::string, global2_);
TEST(ThreadLocalTest, TestTwoGlobalScopeVars) {
EXPECT_EQ(*global_, "");
EXPECT_EQ(*global2_, "");
*global_ = "abc";
EXPECT_EQ(global_->length(), 3);
EXPECT_EQ(*global_, "abc");
EXPECT_EQ(*global2_, "");
*global2_ = *global_;
EXPECT_EQ(*global_, "abc");
EXPECT_EQ(*global2_, "abc");
global_->clear();
EXPECT_EQ(*global_, "");
EXPECT_EQ(*global2_, "abc");
EXPECT_EQ(global2_.get(), "abc");
}
C10_DEFINE_TLS_static(std::string, global3_);
TEST(ThreadLocalTest, TestGlobalWithLocalScopeVars) {
*global3_ = "abc";
C10_DEFINE_TLS_static(std::string, str);
std::swap(*global3_, *str);
EXPECT_EQ(*str, "abc");
EXPECT_EQ(*global3_, "");
}
TEST(ThreadLocalTest, TestThreadWithLocalScopeVar) {
C10_DEFINE_TLS_static(std::string, str);
*str = "abc";
std::atomic_bool b(false);
std::thread t([&b]() {
EXPECT_EQ(*str, "");
*str = "def";
b = true;
EXPECT_EQ(*str, "def");
});
t.join();
EXPECT_TRUE(b);
EXPECT_EQ(*str, "abc");
}
C10_DEFINE_TLS_static(std::string, global4_);
TEST(ThreadLocalTest, TestThreadWithGlobalScopeVar) {
*global4_ = "abc";
std::atomic_bool b(false);
std::thread t([&b]() {
EXPECT_EQ(*global4_, "");
*global4_ = "def";
b = true;
EXPECT_EQ(*global4_, "def");
});
t.join();
EXPECT_TRUE(b);
EXPECT_EQ(*global4_, "abc");
}
TEST(ThreadLocalTest, TestObjectsAreReleased) {
static std::atomic<int> ctors{0};
static std::atomic<int> dtors{0};
struct A {
A() : i() {
++ctors;
}
~A() {
++dtors;
}
A(const A&) = delete;
A& operator=(const A&) = delete;
int i;
};
C10_DEFINE_TLS_static(A, a);
std::atomic_bool b(false);
std::thread t([&b]() {
EXPECT_EQ(a->i, 0);
a->i = 1;
EXPECT_EQ(a->i, 1);
b = true;
});
t.join();
EXPECT_TRUE(b);
EXPECT_EQ(ctors, 1);
EXPECT_EQ(dtors, 1);
}
TEST(ThreadLocalTest, TestObjectsAreReleasedByNonstaticThreadLocal) {
static std::atomic<int> ctors(0);
static std::atomic<int> dtors(0);
struct A {
A() : i() {
++ctors;
}
~A() {
++dtors;
}
A(const A&) = delete;
A& operator=(const A&) = delete;
int i;
};
std::atomic_bool b(false);
std::thread t([&b]() {
#if defined(C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE)
::c10::ThreadLocal<A> a;
#else // defined(C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE)
::c10::ThreadLocal<A> a([]() {
static thread_local A var;
return &var;
});
#endif // defined(C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE)
EXPECT_EQ(a->i, 0);
a->i = 1;
EXPECT_EQ(a->i, 1);
b = true;
});
t.join();
EXPECT_TRUE(b);
EXPECT_EQ(ctors, 1);
EXPECT_EQ(dtors, 1);
}
} // namespace