0d86b361240faf17368d298522a4bc0b4659d0da
[folly.git] / folly / test / BatonTestHelpers.h
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 #pragma once
18
19 #include <folly/Baton.h>
20 #include <folly/test/DeterministicSchedule.h>
21
22 #include <gtest/gtest.h>
23
24 namespace folly {
25 namespace test {
26
27 typedef DeterministicSchedule DSched;
28
29 template <template <typename> class Atom>
30 void run_pingpong_test(int numRounds) {
31   Baton<Atom> batons[17];
32   Baton<Atom>& a = batons[0];
33   Baton<Atom>& b = batons[16]; // to get it on a different cache line
34   auto thr = DSched::thread([&] {
35     for (int i = 0; i < numRounds; ++i) {
36       a.wait();
37       a.reset();
38       b.post();
39     }
40   });
41   for (int i = 0; i < numRounds; ++i) {
42     a.post();
43     b.wait();
44     b.reset();
45   }
46   DSched::join(thr);
47 }
48
49 template <template <typename> class Atom, typename Clock>
50 void run_basic_timed_wait_tests() {
51   Baton<Atom> b;
52   b.post();
53   // tests if early delivery works fine
54   EXPECT_TRUE(b.timed_wait(Clock::now()));
55 }
56
57 template <template <typename> class Atom, typename Clock>
58 void run_timed_wait_tmo_tests() {
59   Baton<Atom> b;
60
61   auto thr = DSched::thread([&] {
62     bool rv = b.timed_wait(Clock::now() + std::chrono::milliseconds(1));
63     // main thread is guaranteed to not post until timeout occurs
64     EXPECT_FALSE(rv);
65   });
66   DSched::join(thr);
67 }
68
69 template <template <typename> class Atom, typename Clock>
70 void run_timed_wait_regular_test() {
71   Baton<Atom> b;
72
73   auto thr = DSched::thread([&] {
74     // To wait forever we'd like to use time_point<Clock>::max, but
75     // std::condition_variable does math to convert the timeout to
76     // system_clock without handling overflow.
77     auto farFuture = Clock::now() + std::chrono::hours(1000);
78     bool rv = b.timed_wait(farFuture);
79     if (!std::is_same<Atom<int>, DeterministicAtomic<int>>::value) {
80       // DeterministicAtomic ignores actual times, so doesn't guarantee
81       // a lack of timeout
82       EXPECT_TRUE(rv);
83     }
84   });
85
86   if (!std::is_same<Atom<int>, DeterministicAtomic<int>>::value) {
87     // If we are using std::atomic (or EmulatedFutexAtomic) then
88     // a sleep here guarantees to a large extent that 'thr' will
89     // execute wait before we post it, thus testing late delivery. For
90     // DeterministicAtomic, we just rely on DeterministicSchedule to do
91     // the scheduling.  The test won't fail if we lose the race, we just
92     // don't get coverage.
93     std::this_thread::sleep_for(std::chrono::milliseconds(2));
94   }
95
96   b.post();
97   DSched::join(thr);
98 }
99
100 template <template <typename> class Atom>
101 void run_try_wait_tests() {
102   Baton<Atom> b;
103   EXPECT_FALSE(b.try_wait());
104   b.post();
105   EXPECT_TRUE(b.try_wait());
106 }
107 }
108 }