fix flaky ConnectTFOTimeout and ConnectTFOFallbackTimeout tests
[folly.git] / folly / test / ThreadLocalTest.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/ThreadLocal.h>
18
19 #include <dlfcn.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22
23 #include <array>
24 #include <atomic>
25 #include <chrono>
26 #include <condition_variable>
27 #include <limits.h>
28 #include <map>
29 #include <mutex>
30 #include <set>
31 #include <thread>
32 #include <unordered_map>
33
34 #include <glog/logging.h>
35 #include <gtest/gtest.h>
36
37 #include <folly/Baton.h>
38 #include <folly/Memory.h>
39 #include <folly/experimental/io/FsUtil.h>
40 #include <folly/portability/Unistd.h>
41
42 using namespace folly;
43
44 struct Widget {
45   static int totalVal_;
46   int val_;
47   ~Widget() {
48     totalVal_ += val_;
49   }
50
51   static void customDeleter(Widget* w, TLPDestructionMode mode) {
52     totalVal_ += (mode == TLPDestructionMode::ALL_THREADS) ? 1000 : 1;
53     delete w;
54   }
55 };
56 int Widget::totalVal_ = 0;
57
58 TEST(ThreadLocalPtr, BasicDestructor) {
59   Widget::totalVal_ = 0;
60   ThreadLocalPtr<Widget> w;
61   std::thread([&w]() {
62       w.reset(new Widget());
63       w.get()->val_ += 10;
64     }).join();
65   EXPECT_EQ(10, Widget::totalVal_);
66 }
67
68 TEST(ThreadLocalPtr, CustomDeleter1) {
69   Widget::totalVal_ = 0;
70   {
71     ThreadLocalPtr<Widget> w;
72     std::thread([&w]() {
73         w.reset(new Widget(), Widget::customDeleter);
74         w.get()->val_ += 10;
75       }).join();
76     EXPECT_EQ(11, Widget::totalVal_);
77   }
78   EXPECT_EQ(11, Widget::totalVal_);
79 }
80
81 TEST(ThreadLocalPtr, CustomDeleterOwnershipTransfer) {
82   Widget::totalVal_ = 0;
83   {
84     ThreadLocalPtr<Widget> w;
85     auto deleter = [](Widget* ptr) {
86       Widget::customDeleter(ptr, TLPDestructionMode::THIS_THREAD);
87     };
88     std::unique_ptr<Widget, decltype(deleter)> source(new Widget(), deleter);
89     std::thread([&w, &source]() {
90       w.reset(std::move(source));
91       w.get()->val_ += 10;
92     }).join();
93     EXPECT_EQ(11, Widget::totalVal_);
94   }
95   EXPECT_EQ(11, Widget::totalVal_);
96 }
97
98 TEST(ThreadLocalPtr, DefaultDeleterOwnershipTransfer) {
99   Widget::totalVal_ = 0;
100   {
101     ThreadLocalPtr<Widget> w;
102     auto source = folly::make_unique<Widget>();
103     std::thread([&w, &source]() {
104       w.reset(std::move(source));
105       w.get()->val_ += 10;
106     }).join();
107     EXPECT_EQ(10, Widget::totalVal_);
108   }
109   EXPECT_EQ(10, Widget::totalVal_);
110 }
111
112 TEST(ThreadLocalPtr, resetNull) {
113   ThreadLocalPtr<int> tl;
114   EXPECT_FALSE(tl);
115   tl.reset(new int(4));
116   EXPECT_TRUE(static_cast<bool>(tl));
117   EXPECT_EQ(*tl.get(), 4);
118   tl.reset();
119   EXPECT_FALSE(tl);
120 }
121
122 TEST(ThreadLocalPtr, TestRelease) {
123   Widget::totalVal_ = 0;
124   ThreadLocalPtr<Widget> w;
125   std::unique_ptr<Widget> wPtr;
126   std::thread([&w, &wPtr]() {
127       w.reset(new Widget());
128       w.get()->val_ += 10;
129
130       wPtr.reset(w.release());
131     }).join();
132   EXPECT_EQ(0, Widget::totalVal_);
133   wPtr.reset();
134   EXPECT_EQ(10, Widget::totalVal_);
135 }
136
137 TEST(ThreadLocalPtr, CreateOnThreadExit) {
138   Widget::totalVal_ = 0;
139   ThreadLocal<Widget> w;
140   ThreadLocalPtr<int> tl;
141
142   std::thread([&] {
143     tl.reset(new int(1),
144              [&](int* ptr, TLPDestructionMode /* mode */) {
145                delete ptr;
146                // This test ensures Widgets allocated here are not leaked.
147                ++w.get()->val_;
148                ThreadLocal<Widget> wl;
149                ++wl.get()->val_;
150              });
151   }).join();
152   EXPECT_EQ(2, Widget::totalVal_);
153 }
154
155 // Test deleting the ThreadLocalPtr object
156 TEST(ThreadLocalPtr, CustomDeleter2) {
157   Widget::totalVal_ = 0;
158   std::thread t;
159   std::mutex mutex;
160   std::condition_variable cv;
161   enum class State {
162     START,
163     DONE,
164     EXIT
165   };
166   State state = State::START;
167   {
168     ThreadLocalPtr<Widget> w;
169     t = std::thread([&]() {
170         w.reset(new Widget(), Widget::customDeleter);
171         w.get()->val_ += 10;
172
173         // Notify main thread that we're done
174         {
175           std::unique_lock<std::mutex> lock(mutex);
176           state = State::DONE;
177           cv.notify_all();
178         }
179
180         // Wait for main thread to allow us to exit
181         {
182           std::unique_lock<std::mutex> lock(mutex);
183           while (state != State::EXIT) {
184             cv.wait(lock);
185           }
186         }
187     });
188
189     // Wait for main thread to start (and set w.get()->val_)
190     {
191       std::unique_lock<std::mutex> lock(mutex);
192       while (state != State::DONE) {
193         cv.wait(lock);
194       }
195     }
196
197     // Thread started but hasn't exited yet
198     EXPECT_EQ(0, Widget::totalVal_);
199
200     // Destroy ThreadLocalPtr<Widget> (by letting it go out of scope)
201   }
202
203   EXPECT_EQ(1010, Widget::totalVal_);
204
205   // Allow thread to exit
206   {
207     std::unique_lock<std::mutex> lock(mutex);
208     state = State::EXIT;
209     cv.notify_all();
210   }
211   t.join();
212
213   EXPECT_EQ(1010, Widget::totalVal_);
214 }
215
216 TEST(ThreadLocal, BasicDestructor) {
217   Widget::totalVal_ = 0;
218   ThreadLocal<Widget> w;
219   std::thread([&w]() { w->val_ += 10; }).join();
220   EXPECT_EQ(10, Widget::totalVal_);
221 }
222
223 TEST(ThreadLocal, SimpleRepeatDestructor) {
224   Widget::totalVal_ = 0;
225   {
226     ThreadLocal<Widget> w;
227     w->val_ += 10;
228   }
229   {
230     ThreadLocal<Widget> w;
231     w->val_ += 10;
232   }
233   EXPECT_EQ(20, Widget::totalVal_);
234 }
235
236 TEST(ThreadLocal, InterleavedDestructors) {
237   Widget::totalVal_ = 0;
238   std::unique_ptr<ThreadLocal<Widget>> w;
239   int wVersion = 0;
240   const int wVersionMax = 2;
241   int thIter = 0;
242   std::mutex lock;
243   auto th = std::thread([&]() {
244     int wVersionPrev = 0;
245     while (true) {
246       while (true) {
247         std::lock_guard<std::mutex> g(lock);
248         if (wVersion > wVersionMax) {
249           return;
250         }
251         if (wVersion > wVersionPrev) {
252           // We have a new version of w, so it should be initialized to zero
253           EXPECT_EQ((*w)->val_, 0);
254           break;
255         }
256       }
257       std::lock_guard<std::mutex> g(lock);
258       wVersionPrev = wVersion;
259       (*w)->val_ += 10;
260       ++thIter;
261     }
262   });
263   FOR_EACH_RANGE(i, 0, wVersionMax) {
264     int thIterPrev = 0;
265     {
266       std::lock_guard<std::mutex> g(lock);
267       thIterPrev = thIter;
268       w.reset(new ThreadLocal<Widget>());
269       ++wVersion;
270     }
271     while (true) {
272       std::lock_guard<std::mutex> g(lock);
273       if (thIter > thIterPrev) {
274         break;
275       }
276     }
277   }
278   {
279     std::lock_guard<std::mutex> g(lock);
280     wVersion = wVersionMax + 1;
281   }
282   th.join();
283   EXPECT_EQ(wVersionMax * 10, Widget::totalVal_);
284 }
285
286 class SimpleThreadCachedInt {
287
288   class NewTag;
289   ThreadLocal<int,NewTag> val_;
290
291  public:
292   void add(int val) {
293     *val_ += val;
294   }
295
296   int read() {
297     int ret = 0;
298     for (const auto& i : val_.accessAllThreads()) {
299       ret += i;
300     }
301     return ret;
302   }
303 };
304
305 TEST(ThreadLocalPtr, AccessAllThreadsCounter) {
306   const int kNumThreads = 10;
307   SimpleThreadCachedInt stci;
308   std::atomic<bool> run(true);
309   std::atomic<int> totalAtomic(0);
310   std::vector<std::thread> threads;
311   for (int i = 0; i < kNumThreads; ++i) {
312     threads.push_back(std::thread([&,i]() {
313       stci.add(1);
314       totalAtomic.fetch_add(1);
315       while (run.load()) { usleep(100); }
316     }));
317   }
318   while (totalAtomic.load() != kNumThreads) { usleep(100); }
319   EXPECT_EQ(kNumThreads, stci.read());
320   run.store(false);
321   for (auto& t : threads) {
322     t.join();
323   }
324 }
325
326 TEST(ThreadLocal, resetNull) {
327   ThreadLocal<int> tl;
328   tl.reset(new int(4));
329   EXPECT_EQ(*tl.get(), 4);
330   tl.reset();
331   EXPECT_EQ(*tl.get(), 0);
332   tl.reset(new int(5));
333   EXPECT_EQ(*tl.get(), 5);
334 }
335
336 namespace {
337 struct Tag {};
338
339 struct Foo {
340   folly::ThreadLocal<int, Tag> tl;
341 };
342 }  // namespace
343
344 TEST(ThreadLocal, Movable1) {
345   Foo a;
346   Foo b;
347   EXPECT_TRUE(a.tl.get() != b.tl.get());
348
349   a = Foo();
350   b = Foo();
351   EXPECT_TRUE(a.tl.get() != b.tl.get());
352 }
353
354 TEST(ThreadLocal, Movable2) {
355   std::map<int, Foo> map;
356
357   map[42];
358   map[10];
359   map[23];
360   map[100];
361
362   std::set<void*> tls;
363   for (auto& m : map) {
364     tls.insert(m.second.tl.get());
365   }
366
367   // Make sure that we have 4 different instances of *tl
368   EXPECT_EQ(4, tls.size());
369 }
370
371 namespace {
372
373 constexpr size_t kFillObjectSize = 300;
374
375 std::atomic<uint64_t> gDestroyed;
376
377 /**
378  * Fill a chunk of memory with a unique-ish pattern that includes the thread id
379  * (so deleting one of these from another thread would cause a failure)
380  *
381  * Verify it explicitly and on destruction.
382  */
383 class FillObject {
384  public:
385   explicit FillObject(uint64_t idx) : idx_(idx) {
386     uint64_t v = val();
387     for (size_t i = 0; i < kFillObjectSize; ++i) {
388       data_[i] = v;
389     }
390   }
391
392   void check() {
393     uint64_t v = val();
394     for (size_t i = 0; i < kFillObjectSize; ++i) {
395       CHECK_EQ(v, data_[i]);
396     }
397   }
398
399   ~FillObject() {
400     ++gDestroyed;
401   }
402
403  private:
404   uint64_t val() const {
405     return (idx_ << 40) | uint64_t(pthread_self());
406   }
407
408   uint64_t idx_;
409   uint64_t data_[kFillObjectSize];
410 };
411
412 }  // namespace
413
414 #if FOLLY_HAVE_STD_THIS_THREAD_SLEEP_FOR
415 TEST(ThreadLocal, Stress) {
416   constexpr size_t numFillObjects = 250;
417   std::array<ThreadLocalPtr<FillObject>, numFillObjects> objects;
418
419   constexpr size_t numThreads = 32;
420   constexpr size_t numReps = 20;
421
422   std::vector<std::thread> threads;
423   threads.reserve(numThreads);
424
425   for (size_t i = 0; i < numThreads; ++i) {
426     threads.emplace_back([&objects] {
427       for (size_t rep = 0; rep < numReps; ++rep) {
428         for (size_t i = 0; i < objects.size(); ++i) {
429           objects[i].reset(new FillObject(rep * objects.size() + i));
430           std::this_thread::sleep_for(std::chrono::microseconds(100));
431         }
432         for (size_t i = 0; i < objects.size(); ++i) {
433           objects[i]->check();
434         }
435       }
436     });
437   }
438
439   for (auto& t : threads) {
440     t.join();
441   }
442
443   EXPECT_EQ(numFillObjects * numThreads * numReps, gDestroyed);
444 }
445 #endif
446
447 // Yes, threads and fork don't mix
448 // (http://cppwisdom.quora.com/Why-threads-and-fork-dont-mix) but if you're
449 // stupid or desperate enough to try, we shouldn't stand in your way.
450 namespace {
451 class HoldsOne {
452  public:
453   HoldsOne() : value_(1) { }
454   // Do an actual access to catch the buggy case where this == nullptr
455   int value() const { return value_; }
456  private:
457   int value_;
458 };
459
460 struct HoldsOneTag {};
461
462 ThreadLocal<HoldsOne, HoldsOneTag> ptr;
463
464 int totalValue() {
465   int value = 0;
466   for (auto& p : ptr.accessAllThreads()) {
467     value += p.value();
468   }
469   return value;
470 }
471
472 }  // namespace
473
474 #ifdef FOLLY_HAVE_PTHREAD_ATFORK
475 TEST(ThreadLocal, Fork) {
476   EXPECT_EQ(1, ptr->value());  // ensure created
477   EXPECT_EQ(1, totalValue());
478   // Spawn a new thread
479
480   std::mutex mutex;
481   bool started = false;
482   std::condition_variable startedCond;
483   bool stopped = false;
484   std::condition_variable stoppedCond;
485
486   std::thread t([&] () {
487     EXPECT_EQ(1, ptr->value());  // ensure created
488     {
489       std::unique_lock<std::mutex> lock(mutex);
490       started = true;
491       startedCond.notify_all();
492     }
493     {
494       std::unique_lock<std::mutex> lock(mutex);
495       while (!stopped) {
496         stoppedCond.wait(lock);
497       }
498     }
499   });
500
501   {
502     std::unique_lock<std::mutex> lock(mutex);
503     while (!started) {
504       startedCond.wait(lock);
505     }
506   }
507
508   EXPECT_EQ(2, totalValue());
509
510   pid_t pid = fork();
511   if (pid == 0) {
512     // in child
513     int v = totalValue();
514
515     // exit successfully if v == 1 (one thread)
516     // diagnostic error code otherwise :)
517     switch (v) {
518     case 1: _exit(0);
519     case 0: _exit(1);
520     }
521     _exit(2);
522   } else if (pid > 0) {
523     // in parent
524     int status;
525     EXPECT_EQ(pid, waitpid(pid, &status, 0));
526     EXPECT_TRUE(WIFEXITED(status));
527     EXPECT_EQ(0, WEXITSTATUS(status));
528   } else {
529     EXPECT_TRUE(false) << "fork failed";
530   }
531
532   EXPECT_EQ(2, totalValue());
533
534   {
535     std::unique_lock<std::mutex> lock(mutex);
536     stopped = true;
537     stoppedCond.notify_all();
538   }
539
540   t.join();
541
542   EXPECT_EQ(1, totalValue());
543 }
544 #endif
545
546 struct HoldsOneTag2 {};
547
548 TEST(ThreadLocal, Fork2) {
549   // A thread-local tag that was used in the parent from a *different* thread
550   // (but not the forking thread) would cause the child to hang in a
551   // ThreadLocalPtr's object destructor. Yeah.
552   ThreadLocal<HoldsOne, HoldsOneTag2> p;
553   {
554     // use tag in different thread
555     std::thread t([&p] { p.get(); });
556     t.join();
557   }
558   pid_t pid = fork();
559   if (pid == 0) {
560     {
561       ThreadLocal<HoldsOne, HoldsOneTag2> q;
562       q.get();
563     }
564     _exit(0);
565   } else if (pid > 0) {
566     int status;
567     EXPECT_EQ(pid, waitpid(pid, &status, 0));
568     EXPECT_TRUE(WIFEXITED(status));
569     EXPECT_EQ(0, WEXITSTATUS(status));
570   } else {
571     EXPECT_TRUE(false) << "fork failed";
572   }
573 }
574
575 // Elide this test when using any sanitizer. Otherwise, the dlopen'ed code
576 // would end up running without e.g., ASAN-initialized data structures and
577 // failing right away.
578 #if !defined FOLLY_SANITIZE_ADDRESS && !defined UNDEFINED_SANITIZER && \
579     !defined FOLLY_SANITIZE_THREAD
580
581 TEST(ThreadLocal, SharedLibrary) {
582   auto exe = fs::executable_path();
583   auto lib = exe.parent_path() / "lib_thread_local_test.so";
584   auto handle = dlopen(lib.string().c_str(), RTLD_LAZY);
585   EXPECT_NE(nullptr, handle);
586
587   typedef void (*useA_t)();
588   dlerror();
589   useA_t useA = (useA_t) dlsym(handle, "useA");
590
591   const char *dlsym_error = dlerror();
592   EXPECT_EQ(nullptr, dlsym_error);
593
594   useA();
595
596   folly::Baton<> b11, b12, b21, b22;
597
598   std::thread t1([&]() {
599       useA();
600       b11.post();
601       b12.wait();
602     });
603
604   std::thread t2([&]() {
605       useA();
606       b21.post();
607       b22.wait();
608     });
609
610   b11.wait();
611   b21.wait();
612
613   dlclose(handle);
614
615   b12.post();
616   b22.post();
617
618   t1.join();
619   t2.join();
620 }
621
622 #endif
623
624 namespace folly { namespace threadlocal_detail {
625 struct PthreadKeyUnregisterTester {
626   PthreadKeyUnregister p;
627   constexpr PthreadKeyUnregisterTester() = default;
628 };
629 }}
630
631 TEST(ThreadLocal, UnregisterClassHasConstExprCtor) {
632   folly::threadlocal_detail::PthreadKeyUnregisterTester x;
633   // yep!
634   SUCCEED();
635 }