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