fix flaky ConnectTFOTimeout and ConnectTFOFallbackTimeout tests
[folly.git] / folly / test / ThreadLocalTest.cpp
index 685802c91deec52b1793ed5fbe2c5c58f3841a76..7a3dab1def48fa92b5bc275f48dbae7e212ea60c 100644 (file)
@@ -19,7 +19,6 @@
 #include <dlfcn.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <unistd.h>
 
 #include <array>
 #include <atomic>
 #include <thread>
 #include <unordered_map>
 
-#include <boost/thread/tss.hpp>
-#include <gflags/gflags.h>
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
-#include <folly/Benchmark.h>
 #include <folly/Baton.h>
+#include <folly/Memory.h>
 #include <folly/experimental/io/FsUtil.h>
+#include <folly/portability/Unistd.h>
 
 using namespace folly;
 
@@ -51,7 +49,7 @@ struct Widget {
   }
 
   static void customDeleter(Widget* w, TLPDestructionMode mode) {
-    totalVal_ += (mode == TLPDestructionMode::ALL_THREADS) * 1000;
+    totalVal_ += (mode == TLPDestructionMode::ALL_THREADS) ? 1000 : 1;
     delete w;
   }
 };
@@ -75,6 +73,37 @@ TEST(ThreadLocalPtr, CustomDeleter1) {
         w.reset(new Widget(), Widget::customDeleter);
         w.get()->val_ += 10;
       }).join();
+    EXPECT_EQ(11, Widget::totalVal_);
+  }
+  EXPECT_EQ(11, Widget::totalVal_);
+}
+
+TEST(ThreadLocalPtr, CustomDeleterOwnershipTransfer) {
+  Widget::totalVal_ = 0;
+  {
+    ThreadLocalPtr<Widget> w;
+    auto deleter = [](Widget* ptr) {
+      Widget::customDeleter(ptr, TLPDestructionMode::THIS_THREAD);
+    };
+    std::unique_ptr<Widget, decltype(deleter)> source(new Widget(), deleter);
+    std::thread([&w, &source]() {
+      w.reset(std::move(source));
+      w.get()->val_ += 10;
+    }).join();
+    EXPECT_EQ(11, Widget::totalVal_);
+  }
+  EXPECT_EQ(11, Widget::totalVal_);
+}
+
+TEST(ThreadLocalPtr, DefaultDeleterOwnershipTransfer) {
+  Widget::totalVal_ = 0;
+  {
+    ThreadLocalPtr<Widget> w;
+    auto source = folly::make_unique<Widget>();
+    std::thread([&w, &source]() {
+      w.reset(std::move(source));
+      w.get()->val_ += 10;
+    }).join();
     EXPECT_EQ(10, Widget::totalVal_);
   }
   EXPECT_EQ(10, Widget::totalVal_);
@@ -543,6 +572,12 @@ TEST(ThreadLocal, Fork2) {
   }
 }
 
+// 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() / "lib_thread_local_test.so";
@@ -584,6 +619,8 @@ TEST(ThreadLocal, SharedLibrary) {
   t2.join();
 }
 
+#endif
+
 namespace folly { namespace threadlocal_detail {
 struct PthreadKeyUnregisterTester {
   PthreadKeyUnregister p;
@@ -596,91 +633,3 @@ TEST(ThreadLocal, UnregisterClassHasConstExprCtor) {
   // yep!
   SUCCEED();
 }
-
-// clang is unable to compile this code unless in c++14 mode.
-#if __cplusplus >= 201402L
-namespace {
-// This will fail to compile unless ThreadLocal{Ptr} has a constexpr
-// default constructor. This ensures that ThreadLocal is safe to use in
-// static constructors without worrying about initialization order
-class ConstexprThreadLocalCompile {
-  ThreadLocal<int> a_;
-  ThreadLocalPtr<int> b_;
-
-  constexpr ConstexprThreadLocalCompile() {}
-};
-}
-#endif
-
-// Simple reference implementation using pthread_get_specific
-template<typename T>
-class PThreadGetSpecific {
- public:
-  PThreadGetSpecific() : key_(0) {
-    pthread_key_create(&key_, OnThreadExit);
-  }
-
-  T* get() const {
-    return static_cast<T*>(pthread_getspecific(key_));
-  }
-
-  void reset(T* t) {
-    delete get();
-    pthread_setspecific(key_, t);
-  }
-  static void OnThreadExit(void* obj) {
-    delete static_cast<T*>(obj);
-  }
- private:
-  pthread_key_t key_;
-};
-
-DEFINE_int32(numThreads, 8, "Number simultaneous threads for benchmarks.");
-
-#define REG(var)                                                \
-  BENCHMARK(FB_CONCATENATE(BM_mt_, var), iters) {               \
-    const int itersPerThread = iters / FLAGS_numThreads;        \
-    std::vector<std::thread> threads;                           \
-    for (int i = 0; i < FLAGS_numThreads; ++i) {                \
-      threads.push_back(std::thread([&]() {                     \
-        var.reset(new int(0));                                  \
-        for (int i = 0; i < itersPerThread; ++i) {              \
-          ++(*var.get());                                       \
-        }                                                       \
-      }));                                                      \
-    }                                                           \
-    for (auto& t : threads) {                                   \
-      t.join();                                                 \
-    }                                                           \
-  }
-
-ThreadLocalPtr<int> tlp;
-REG(tlp);
-PThreadGetSpecific<int> pthread_get_specific;
-REG(pthread_get_specific);
-boost::thread_specific_ptr<int> boost_tsp;
-REG(boost_tsp);
-BENCHMARK_DRAW_LINE();
-
-int main(int argc, char** argv) {
-  testing::InitGoogleTest(&argc, argv);
-  gflags::ParseCommandLineFlags(&argc, &argv, true);
-  gflags::SetCommandLineOptionWithMode(
-    "bm_max_iters", "100000000", gflags::SET_FLAG_IF_DEFAULT
-  );
-  if (FLAGS_benchmark) {
-    folly::runBenchmarks();
-  }
-  return RUN_ALL_TESTS();
-}
-
-/*
-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
-------------------------------------------------------------------------------
-*/