-/*
-Ran with 24 threads on dual 12-core Xeon(R) X5650 @ 2.67GHz with 12-MB caches
-
-Benchmark Iters Total t t/iter iter/sec
-------------------------------------------------------------------------------
-* BM_mt_tlp 100000000 39.88 ms 398.8 ps 2.335 G
- +5.91% BM_mt_pthread_get_specific 100000000 42.23 ms 422.3 ps 2.205 G
- + 295% BM_mt_boost_tsp 100000000 157.8 ms 1.578 ns 604.5 M
-------------------------------------------------------------------------------
-*/
+#ifndef _WIN32
+struct HoldsOneTag2 {};
+
+TEST(ThreadLocal, Fork2) {
+ // A thread-local tag that was used in the parent from a *different* thread
+ // (but not the forking thread) would cause the child to hang in a
+ // ThreadLocalPtr's object destructor. Yeah.
+ ThreadLocal<HoldsOne, HoldsOneTag2> p;
+ {
+ // use tag in different thread
+ std::thread t([&p] { p.get(); });
+ t.join();
+ }
+ pid_t pid = fork();
+ if (pid == 0) {
+ {
+ ThreadLocal<HoldsOne, HoldsOneTag2> q;
+ q.get();
+ }
+ _exit(0);
+ } else if (pid > 0) {
+ int status;
+ EXPECT_EQ(pid, waitpid(pid, &status, 0));
+ EXPECT_TRUE(WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+ } else {
+ ADD_FAILURE() << "fork failed";
+ }
+}
+
+// Elide this test when using any sanitizer. Otherwise, the dlopen'ed code
+// would end up running without e.g., ASAN-initialized data structures and
+// failing right away.
+#if !defined FOLLY_SANITIZE_ADDRESS && !defined UNDEFINED_SANITIZER && \
+ !defined FOLLY_SANITIZE_THREAD
+
+TEST(ThreadLocal, SharedLibrary) {
+ auto exe = fs::executable_path();
+ auto lib = exe.parent_path() / "thread_local_test_lib.so";
+ auto handle = dlopen(lib.string().c_str(), RTLD_LAZY);
+ EXPECT_NE(nullptr, handle);
+
+ typedef void (*useA_t)();
+ dlerror();
+ useA_t useA = (useA_t) dlsym(handle, "useA");
+
+ const char *dlsym_error = dlerror();
+ EXPECT_EQ(nullptr, dlsym_error);
+
+ useA();
+
+ folly::Baton<> b11, b12, b21, b22;
+
+ std::thread t1([&]() {
+ useA();
+ b11.post();
+ b12.wait();
+ });
+
+ std::thread t2([&]() {
+ useA();
+ b21.post();
+ b22.wait();
+ });
+
+ b11.wait();
+ b21.wait();
+
+ dlclose(handle);
+
+ b12.post();
+ b22.post();
+
+ t1.join();
+ t2.join();
+}
+
+#endif
+#endif
+
+namespace folly { namespace threadlocal_detail {
+struct PthreadKeyUnregisterTester {
+ PthreadKeyUnregister p;
+ constexpr PthreadKeyUnregisterTester() = default;
+};
+}}
+
+TEST(ThreadLocal, UnregisterClassHasConstExprCtor) {
+ folly::threadlocal_detail::PthreadKeyUnregisterTester x;
+ // yep!
+ SUCCEED();
+}