Codemod: use #include angle brackets in folly and thrift
[folly.git] / folly / test / FutexTest.cpp
1 /*
2  * Copyright 2014 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/detail/Futex.h>
18 #include <folly/test/DeterministicSchedule.h>
19
20 #include <chrono>
21 #include <thread>
22
23 #include <gflags/gflags.h>
24 #include <gtest/gtest.h>
25 #include <common/logging/logging.h>
26 #include <time.h>
27
28 using namespace folly::detail;
29 using namespace folly::test;
30 using namespace std::chrono;
31
32 typedef DeterministicSchedule DSched;
33
34 template <template<typename> class Atom>
35 void run_basic_tests() {
36   Futex<Atom> f(0);
37
38   EXPECT_FALSE(f.futexWait(1));
39   EXPECT_EQ(f.futexWake(), 0);
40
41   auto thr = DSched::thread([&]{
42     EXPECT_TRUE(f.futexWait(0));
43   });
44
45   while (f.futexWake() != 1) {
46     std::this_thread::yield();
47   }
48
49   DSched::join(thr);
50 }
51
52 template<template<typename> class Atom>
53 void run_wait_until_tests();
54
55 template <typename Clock>
56 void stdAtomicWaitUntilTests() {
57   Futex<std::atomic> f(0);
58
59   auto thrA = DSched::thread([&]{
60     while (true) {
61       typename Clock::time_point nowPlus2s = Clock::now() + seconds(2);
62       auto res = f.futexWaitUntil(0, nowPlus2s);
63       EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::AWOKEN);
64       if (res == FutexResult::AWOKEN) {
65         break;
66       }
67     }
68   });
69
70   while (f.futexWake() != 1) {
71     std::this_thread::yield();
72   }
73
74   DSched::join(thrA);
75
76   auto start = Clock::now();
77   EXPECT_EQ(f.futexWaitUntil(0, start + milliseconds(100)),
78             FutexResult::TIMEDOUT);
79   LOG(INFO) << "Futex wait timed out after waiting for "
80             << duration_cast<milliseconds>(Clock::now() - start).count()
81             << "ms";
82 }
83
84 template <typename Clock>
85 void deterministicAtomicWaitUntilTests() {
86   Futex<DeterministicAtomic> f(0);
87
88   // Futex wait must eventually fail with either FutexResult::TIMEDOUT or
89   // FutexResult::INTERRUPTED
90   auto res = f.futexWaitUntil(0, Clock::now() + milliseconds(100));
91   EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::INTERRUPTED);
92 }
93
94 template <>
95 void run_wait_until_tests<std::atomic>() {
96   stdAtomicWaitUntilTests<system_clock>();
97   stdAtomicWaitUntilTests<steady_clock>();
98 }
99
100 template <>
101 void run_wait_until_tests<DeterministicAtomic>() {
102   deterministicAtomicWaitUntilTests<system_clock>();
103   deterministicAtomicWaitUntilTests<steady_clock>();
104 }
105
106 uint64_t diff(uint64_t a, uint64_t b) {
107   return a > b ? a - b : b - a;
108 }
109
110 void run_system_clock_test() {
111   /* Test to verify that system_clock uses clock_gettime(CLOCK_REALTIME, ...)
112    * for the time_points */
113   struct timespec ts;
114   const int maxIters = 1000;
115   int iter = 0;
116   uint64_t delta = 10000000 /* 10 ms */;
117
118   /** The following loop is only to make the test more robust in the presence of
119    * clock adjustments that can occur. We just run the loop maxIter times and
120    * expect with very high probability that there will be atleast one iteration
121    * of the test during which clock adjustments > delta have not occurred. */
122   while (iter < maxIters) {
123     uint64_t a = duration_cast<nanoseconds>(system_clock::now()
124                                             .time_since_epoch()).count();
125
126     clock_gettime(CLOCK_REALTIME, &ts);
127     uint64_t b = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
128
129     uint64_t c = duration_cast<nanoseconds>(system_clock::now()
130                                             .time_since_epoch()).count();
131
132     if (diff(a, b) <= delta &&
133         diff(b, c) <= delta &&
134         diff(a, c) <= 2 * delta) {
135       /* Success! system_clock uses CLOCK_REALTIME for time_points */
136       break;
137     }
138     iter++;
139   }
140   EXPECT_TRUE(iter < maxIters);
141 }
142
143 void run_steady_clock_test() {
144   /* Test to verify that steady_clock uses clock_gettime(CLOCK_MONOTONIC, ...)
145    * for the time_points */
146   EXPECT_TRUE(steady_clock::is_steady);
147
148   uint64_t A = duration_cast<nanoseconds>(steady_clock::now()
149                                           .time_since_epoch()).count();
150
151   struct timespec ts;
152   clock_gettime(CLOCK_MONOTONIC, &ts);
153   uint64_t B = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
154
155   uint64_t C = duration_cast<nanoseconds>(steady_clock::now()
156                                           .time_since_epoch()).count();
157   EXPECT_TRUE(A <= B && B <= C);
158 }
159
160 TEST(Futex, clock_source) {
161   run_system_clock_test();
162
163   /* On some systems steady_clock is just an alias for system_clock. So,
164    * we must skip run_steady_clock_test if the two clocks are the same. */
165   if (!std::is_same<system_clock,steady_clock>::value) {
166     run_steady_clock_test();
167   }
168 }
169
170 TEST(Futex, basic_live) {
171   run_basic_tests<std::atomic>();
172   run_wait_until_tests<std::atomic>();
173 }
174
175 TEST(Futex, basic_deterministic) {
176   DSched sched(DSched::uniform(0));
177   run_basic_tests<DeterministicAtomic>();
178   run_wait_until_tests<DeterministicAtomic>();
179 }
180
181 int main(int argc, char ** argv) {
182   testing::InitGoogleTest(&argc, argv);
183   google::ParseCommandLineFlags(&argc, &argv, true);
184   return RUN_ALL_TESTS();
185 }
186