xref: /aosp_15_r20/external/pigweed/pw_sync/condition_variable_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2022 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_sync/condition_variable.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <chrono>
18*61c4878aSAndroid Build Coastguard Worker #include <functional>
19*61c4878aSAndroid Build Coastguard Worker 
20*61c4878aSAndroid Build Coastguard Worker #include "pw_containers/vector.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_sync/mutex.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_sync/timed_thread_notification.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/non_portable_test_thread_options.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/sleep.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/thread.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
27*61c4878aSAndroid Build Coastguard Worker 
28*61c4878aSAndroid Build Coastguard Worker namespace pw::sync {
29*61c4878aSAndroid Build Coastguard Worker namespace {
30*61c4878aSAndroid Build Coastguard Worker 
31*61c4878aSAndroid Build Coastguard Worker using namespace std::chrono_literals;
32*61c4878aSAndroid Build Coastguard Worker 
33*61c4878aSAndroid Build Coastguard Worker // A timeout for tests where successful behaviour involves waiting.
34*61c4878aSAndroid Build Coastguard Worker constexpr auto kRequiredTimeout = 100ms;
35*61c4878aSAndroid Build Coastguard Worker 
36*61c4878aSAndroid Build Coastguard Worker // Maximum extra wait time allowed for test that ensure something waits for
37*61c4878aSAndroid Build Coastguard Worker // `kRequiredTimeout`.
38*61c4878aSAndroid Build Coastguard Worker const auto kAllowedSlack = kRequiredTimeout * 1.5;
39*61c4878aSAndroid Build Coastguard Worker 
40*61c4878aSAndroid Build Coastguard Worker // A timeout that should only be hit if something goes wrong.
41*61c4878aSAndroid Build Coastguard Worker constexpr auto kFailureTimeout = 5s;
42*61c4878aSAndroid Build Coastguard Worker 
43*61c4878aSAndroid Build Coastguard Worker using StateLock = std::unique_lock<Mutex>;
44*61c4878aSAndroid Build Coastguard Worker 
45*61c4878aSAndroid Build Coastguard Worker struct ThreadInfo {
ThreadInfopw::sync::__anon4908bbcc0111::ThreadInfo46*61c4878aSAndroid Build Coastguard Worker   explicit ThreadInfo(int id) : thread_id(id) {}
47*61c4878aSAndroid Build Coastguard Worker 
48*61c4878aSAndroid Build Coastguard Worker   // waiting_notifier is signalled in predicates to indicate that the predicate
49*61c4878aSAndroid Build Coastguard Worker   // has been evaluated. This guarantees (via insider information) that the
50*61c4878aSAndroid Build Coastguard Worker   // thread will acquire the internal ThreadNotification.
51*61c4878aSAndroid Build Coastguard Worker   TimedThreadNotification waiting_notifier;
52*61c4878aSAndroid Build Coastguard Worker 
53*61c4878aSAndroid Build Coastguard Worker   // Signals when the worker thread is done.
54*61c4878aSAndroid Build Coastguard Worker   TimedThreadNotification done_notifier;
55*61c4878aSAndroid Build Coastguard Worker 
56*61c4878aSAndroid Build Coastguard Worker   // The result of the predicate the worker thread uses with wait*(). Set from
57*61c4878aSAndroid Build Coastguard Worker   // the main test thread and read by the worker thread.
58*61c4878aSAndroid Build Coastguard Worker   bool predicate_result = false;
59*61c4878aSAndroid Build Coastguard Worker 
60*61c4878aSAndroid Build Coastguard Worker   // Stores the result of ConditionVariable::wait_for() or ::wait_until() for
61*61c4878aSAndroid Build Coastguard Worker   // use in test asserts.
62*61c4878aSAndroid Build Coastguard Worker   bool wait_result = false;
63*61c4878aSAndroid Build Coastguard Worker 
64*61c4878aSAndroid Build Coastguard Worker   // For use in recording the order in which threads block on a condition.
65*61c4878aSAndroid Build Coastguard Worker   const int thread_id;
66*61c4878aSAndroid Build Coastguard Worker 
67*61c4878aSAndroid Build Coastguard Worker   // Returns a function which will return the current value of
68*61c4878aSAndroid Build Coastguard Worker   //`predicate_result` and release `waiting_notifier`.
Predicatepw::sync::__anon4908bbcc0111::ThreadInfo69*61c4878aSAndroid Build Coastguard Worker   std::function<bool()> Predicate() {
70*61c4878aSAndroid Build Coastguard Worker     return [this]() {
71*61c4878aSAndroid Build Coastguard Worker       bool result = this->predicate_result;
72*61c4878aSAndroid Build Coastguard Worker       this->waiting_notifier.release();
73*61c4878aSAndroid Build Coastguard Worker       return result;
74*61c4878aSAndroid Build Coastguard Worker     };
75*61c4878aSAndroid Build Coastguard Worker   }
76*61c4878aSAndroid Build Coastguard Worker };
77*61c4878aSAndroid Build Coastguard Worker 
78*61c4878aSAndroid Build Coastguard Worker // A `ThreadCore` implementation that delegates to an `std::function`.
79*61c4878aSAndroid Build Coastguard Worker class LambdaThreadCore : public pw::thread::ThreadCore {
80*61c4878aSAndroid Build Coastguard Worker  public:
LambdaThreadCore(std::function<void ()> work)81*61c4878aSAndroid Build Coastguard Worker   explicit LambdaThreadCore(std::function<void()> work)
82*61c4878aSAndroid Build Coastguard Worker       : work_(std::move(work)) {}
83*61c4878aSAndroid Build Coastguard Worker 
84*61c4878aSAndroid Build Coastguard Worker  private:
Run()85*61c4878aSAndroid Build Coastguard Worker   void Run() override { work_(); }
86*61c4878aSAndroid Build Coastguard Worker 
87*61c4878aSAndroid Build Coastguard Worker   std::function<void()> work_;
88*61c4878aSAndroid Build Coastguard Worker };
89*61c4878aSAndroid Build Coastguard Worker 
90*61c4878aSAndroid Build Coastguard Worker class LambdaThread {
91*61c4878aSAndroid Build Coastguard Worker  public:
92*61c4878aSAndroid Build Coastguard Worker   // Starts a new thread which runs `work`, joining the thread on destruction.
LambdaThread(std::function<void ()> work,pw::thread::Options options=pw::thread::test::TestOptionsThread0 ())93*61c4878aSAndroid Build Coastguard Worker   explicit LambdaThread(
94*61c4878aSAndroid Build Coastguard Worker       std::function<void()> work,
95*61c4878aSAndroid Build Coastguard Worker       // TODO: b/290860904 - Replace TestOptionsThread0 with TestThreadContext.
96*61c4878aSAndroid Build Coastguard Worker       pw::thread::Options options = pw::thread::test::TestOptionsThread0())
97*61c4878aSAndroid Build Coastguard Worker       : thread_core_(std::move(work)), thread_(options, thread_core_) {}
~LambdaThread()98*61c4878aSAndroid Build Coastguard Worker   ~LambdaThread() { thread_.join(); }
99*61c4878aSAndroid Build Coastguard Worker   LambdaThread(const LambdaThread&) = delete;
100*61c4878aSAndroid Build Coastguard Worker   LambdaThread(LambdaThread&&) = delete;
101*61c4878aSAndroid Build Coastguard Worker   LambdaThread& operator=(const LambdaThread&) = delete;
102*61c4878aSAndroid Build Coastguard Worker   LambdaThread&& operator=(LambdaThread&&) = delete;
103*61c4878aSAndroid Build Coastguard Worker 
104*61c4878aSAndroid Build Coastguard Worker  private:
105*61c4878aSAndroid Build Coastguard Worker   LambdaThreadCore thread_core_;
106*61c4878aSAndroid Build Coastguard Worker   pw::Thread thread_;
107*61c4878aSAndroid Build Coastguard Worker };
108*61c4878aSAndroid Build Coastguard Worker 
TEST(Wait,PredicateTrueNoWait)109*61c4878aSAndroid Build Coastguard Worker TEST(Wait, PredicateTrueNoWait) {
110*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
111*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
112*61c4878aSAndroid Build Coastguard Worker   ThreadInfo thread_info(0);
113*61c4878aSAndroid Build Coastguard Worker 
114*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread([&mutex, &condvar, &info = thread_info] {
115*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
116*61c4878aSAndroid Build Coastguard Worker     condvar.wait(l, [] { return true; });
117*61c4878aSAndroid Build Coastguard Worker 
118*61c4878aSAndroid Build Coastguard Worker     info.done_notifier.release();
119*61c4878aSAndroid Build Coastguard Worker   });
120*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(thread_info.done_notifier.try_acquire_for(kFailureTimeout));
121*61c4878aSAndroid Build Coastguard Worker }
122*61c4878aSAndroid Build Coastguard Worker 
TEST(NotifyOne,BlocksUntilSignaled)123*61c4878aSAndroid Build Coastguard Worker TEST(NotifyOne, BlocksUntilSignaled) {
124*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
125*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
126*61c4878aSAndroid Build Coastguard Worker   ThreadInfo thread_info(0);
127*61c4878aSAndroid Build Coastguard Worker 
128*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread([&mutex, &condvar, &info = thread_info] {
129*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
130*61c4878aSAndroid Build Coastguard Worker     condvar.wait(l, info.Predicate());
131*61c4878aSAndroid Build Coastguard Worker     info.done_notifier.release();
132*61c4878aSAndroid Build Coastguard Worker   });
133*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.waiting_notifier.try_acquire_for(kFailureTimeout));
134*61c4878aSAndroid Build Coastguard Worker   {
135*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
136*61c4878aSAndroid Build Coastguard Worker     thread_info.predicate_result = true;
137*61c4878aSAndroid Build Coastguard Worker   }
138*61c4878aSAndroid Build Coastguard Worker   condvar.notify_one();
139*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.done_notifier.try_acquire_for(kFailureTimeout));
140*61c4878aSAndroid Build Coastguard Worker }
141*61c4878aSAndroid Build Coastguard Worker 
TEST(NotifyOne,UnblocksOne)142*61c4878aSAndroid Build Coastguard Worker TEST(NotifyOne, UnblocksOne) {
143*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
144*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
145*61c4878aSAndroid Build Coastguard Worker   std::array<ThreadInfo, 2> thread_info = {ThreadInfo(0), ThreadInfo(1)};
146*61c4878aSAndroid Build Coastguard Worker   pw::Vector<int, 2> wait_order;
147*61c4878aSAndroid Build Coastguard Worker 
148*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread_1(
149*61c4878aSAndroid Build Coastguard Worker       [&mutex, &condvar, &info = thread_info[0], &wait_order] {
150*61c4878aSAndroid Build Coastguard Worker         StateLock l{mutex};
151*61c4878aSAndroid Build Coastguard Worker         auto predicate = [&info, &wait_order] {
152*61c4878aSAndroid Build Coastguard Worker           wait_order.push_back(info.thread_id);
153*61c4878aSAndroid Build Coastguard Worker           auto result = info.predicate_result;
154*61c4878aSAndroid Build Coastguard Worker           info.waiting_notifier.release();
155*61c4878aSAndroid Build Coastguard Worker           return result;
156*61c4878aSAndroid Build Coastguard Worker         };
157*61c4878aSAndroid Build Coastguard Worker         condvar.wait(l, predicate);
158*61c4878aSAndroid Build Coastguard Worker         info.done_notifier.release();
159*61c4878aSAndroid Build Coastguard Worker       },
160*61c4878aSAndroid Build Coastguard Worker       pw::thread::test::TestOptionsThread0());
161*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread_2(
162*61c4878aSAndroid Build Coastguard Worker       [&mutex, &condvar, &info = thread_info[1], &wait_order] {
163*61c4878aSAndroid Build Coastguard Worker         StateLock l{mutex};
164*61c4878aSAndroid Build Coastguard Worker         auto predicate = [&info, &wait_order] {
165*61c4878aSAndroid Build Coastguard Worker           wait_order.push_back(info.thread_id);
166*61c4878aSAndroid Build Coastguard Worker           auto result = info.predicate_result;
167*61c4878aSAndroid Build Coastguard Worker           info.waiting_notifier.release();
168*61c4878aSAndroid Build Coastguard Worker           return result;
169*61c4878aSAndroid Build Coastguard Worker         };
170*61c4878aSAndroid Build Coastguard Worker         condvar.wait(l, predicate);
171*61c4878aSAndroid Build Coastguard Worker         info.done_notifier.release();
172*61c4878aSAndroid Build Coastguard Worker       },
173*61c4878aSAndroid Build Coastguard Worker       pw::thread::test::TestOptionsThread1());
174*61c4878aSAndroid Build Coastguard Worker 
175*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info[0].waiting_notifier.try_acquire_for(kFailureTimeout));
176*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info[1].waiting_notifier.try_acquire_for(kFailureTimeout));
177*61c4878aSAndroid Build Coastguard Worker 
178*61c4878aSAndroid Build Coastguard Worker   {
179*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
180*61c4878aSAndroid Build Coastguard Worker     thread_info[1].predicate_result = true;
181*61c4878aSAndroid Build Coastguard Worker     thread_info[0].predicate_result = true;
182*61c4878aSAndroid Build Coastguard Worker   }
183*61c4878aSAndroid Build Coastguard Worker   condvar.notify_one();
184*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info[wait_order[0]].done_notifier.try_acquire_for(
185*61c4878aSAndroid Build Coastguard Worker       kFailureTimeout));
186*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(thread_info[wait_order[0]].done_notifier.try_acquire());
187*61c4878aSAndroid Build Coastguard Worker   condvar.notify_one();
188*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info[wait_order[1]].done_notifier.try_acquire_for(
189*61c4878aSAndroid Build Coastguard Worker       kFailureTimeout));
190*61c4878aSAndroid Build Coastguard Worker }
191*61c4878aSAndroid Build Coastguard Worker 
TEST(NotifyAll,UnblocksMultiple)192*61c4878aSAndroid Build Coastguard Worker TEST(NotifyAll, UnblocksMultiple) {
193*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
194*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
195*61c4878aSAndroid Build Coastguard Worker   std::array<ThreadInfo, 2> thread_info = {ThreadInfo(0), ThreadInfo(1)};
196*61c4878aSAndroid Build Coastguard Worker 
197*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread_1(
198*61c4878aSAndroid Build Coastguard Worker       [&mutex, &condvar, &info = thread_info[0]] {
199*61c4878aSAndroid Build Coastguard Worker         StateLock l{mutex};
200*61c4878aSAndroid Build Coastguard Worker         condvar.wait(l, info.Predicate());
201*61c4878aSAndroid Build Coastguard Worker         info.done_notifier.release();
202*61c4878aSAndroid Build Coastguard Worker       },
203*61c4878aSAndroid Build Coastguard Worker       pw::thread::test::TestOptionsThread0());
204*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread_2(
205*61c4878aSAndroid Build Coastguard Worker       [&mutex, &condvar, &info = thread_info[1]] {
206*61c4878aSAndroid Build Coastguard Worker         StateLock l{mutex};
207*61c4878aSAndroid Build Coastguard Worker         condvar.wait(l, info.Predicate());
208*61c4878aSAndroid Build Coastguard Worker         info.done_notifier.release();
209*61c4878aSAndroid Build Coastguard Worker       },
210*61c4878aSAndroid Build Coastguard Worker       pw::thread::test::TestOptionsThread1());
211*61c4878aSAndroid Build Coastguard Worker 
212*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info[0].waiting_notifier.try_acquire_for(kFailureTimeout));
213*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info[1].waiting_notifier.try_acquire_for(kFailureTimeout));
214*61c4878aSAndroid Build Coastguard Worker   {
215*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
216*61c4878aSAndroid Build Coastguard Worker     thread_info[0].predicate_result = true;
217*61c4878aSAndroid Build Coastguard Worker     thread_info[1].predicate_result = true;
218*61c4878aSAndroid Build Coastguard Worker   }
219*61c4878aSAndroid Build Coastguard Worker   condvar.notify_all();
220*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info[0].done_notifier.try_acquire_for(kFailureTimeout));
221*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info[1].done_notifier.try_acquire_for(kFailureTimeout));
222*61c4878aSAndroid Build Coastguard Worker }
223*61c4878aSAndroid Build Coastguard Worker 
TEST(WaitFor,ReturnsTrueIfSignalled)224*61c4878aSAndroid Build Coastguard Worker TEST(WaitFor, ReturnsTrueIfSignalled) {
225*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
226*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
227*61c4878aSAndroid Build Coastguard Worker   ThreadInfo thread_info(0);
228*61c4878aSAndroid Build Coastguard Worker 
229*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread([&mutex, &condvar, &info = thread_info] {
230*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
231*61c4878aSAndroid Build Coastguard Worker     info.wait_result = condvar.wait_for(l, kFailureTimeout, info.Predicate());
232*61c4878aSAndroid Build Coastguard Worker     info.done_notifier.release();
233*61c4878aSAndroid Build Coastguard Worker   });
234*61c4878aSAndroid Build Coastguard Worker 
235*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.waiting_notifier.try_acquire_for(kFailureTimeout));
236*61c4878aSAndroid Build Coastguard Worker   {
237*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
238*61c4878aSAndroid Build Coastguard Worker     thread_info.predicate_result = true;
239*61c4878aSAndroid Build Coastguard Worker   }
240*61c4878aSAndroid Build Coastguard Worker   condvar.notify_one();
241*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.done_notifier.try_acquire_for(kFailureTimeout));
242*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.wait_result);
243*61c4878aSAndroid Build Coastguard Worker }
244*61c4878aSAndroid Build Coastguard Worker 
TEST(WaitFor,ReturnsFalseIfTimesOut)245*61c4878aSAndroid Build Coastguard Worker TEST(WaitFor, ReturnsFalseIfTimesOut) {
246*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
247*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
248*61c4878aSAndroid Build Coastguard Worker   ThreadInfo thread_info(0);
249*61c4878aSAndroid Build Coastguard Worker 
250*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread([&mutex, &condvar, &info = thread_info] {
251*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
252*61c4878aSAndroid Build Coastguard Worker     info.wait_result = condvar.wait_for(l, 0ms, info.Predicate());
253*61c4878aSAndroid Build Coastguard Worker     info.done_notifier.release();
254*61c4878aSAndroid Build Coastguard Worker   });
255*61c4878aSAndroid Build Coastguard Worker 
256*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.waiting_notifier.try_acquire_for(kFailureTimeout));
257*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.done_notifier.try_acquire_for(kFailureTimeout));
258*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(thread_info.wait_result);
259*61c4878aSAndroid Build Coastguard Worker }
260*61c4878aSAndroid Build Coastguard Worker 
261*61c4878aSAndroid Build Coastguard Worker // NOTE: This test waits even in successful circumstances.
TEST(WaitFor,TimeoutApproximatelyCorrect)262*61c4878aSAndroid Build Coastguard Worker TEST(WaitFor, TimeoutApproximatelyCorrect) {
263*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
264*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
265*61c4878aSAndroid Build Coastguard Worker   ThreadInfo thread_info(0);
266*61c4878aSAndroid Build Coastguard Worker   pw::chrono::SystemClock::duration wait_duration{};
267*61c4878aSAndroid Build Coastguard Worker 
268*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread([&mutex, &condvar, &info = thread_info, &wait_duration] {
269*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
270*61c4878aSAndroid Build Coastguard Worker     auto start = pw::chrono::SystemClock::now();
271*61c4878aSAndroid Build Coastguard Worker     info.wait_result = condvar.wait_for(l, kRequiredTimeout, info.Predicate());
272*61c4878aSAndroid Build Coastguard Worker     wait_duration = pw::chrono::SystemClock::now() - start;
273*61c4878aSAndroid Build Coastguard Worker     info.done_notifier.release();
274*61c4878aSAndroid Build Coastguard Worker   });
275*61c4878aSAndroid Build Coastguard Worker 
276*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.waiting_notifier.try_acquire_for(kFailureTimeout));
277*61c4878aSAndroid Build Coastguard Worker   // Wake up thread multiple times. Make sure the timeout is observed.
278*61c4878aSAndroid Build Coastguard Worker   for (int i = 0; i < 5; ++i) {
279*61c4878aSAndroid Build Coastguard Worker     condvar.notify_one();
280*61c4878aSAndroid Build Coastguard Worker     pw::this_thread::sleep_for(kRequiredTimeout / 6);
281*61c4878aSAndroid Build Coastguard Worker   }
282*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.done_notifier.try_acquire_for(kFailureTimeout));
283*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(thread_info.wait_result);
284*61c4878aSAndroid Build Coastguard Worker   EXPECT_GE(wait_duration, kRequiredTimeout);
285*61c4878aSAndroid Build Coastguard Worker   EXPECT_LT(wait_duration, (kRequiredTimeout + kAllowedSlack));
286*61c4878aSAndroid Build Coastguard Worker }
287*61c4878aSAndroid Build Coastguard Worker 
TEST(WaitUntil,ReturnsTrueIfSignalled)288*61c4878aSAndroid Build Coastguard Worker TEST(WaitUntil, ReturnsTrueIfSignalled) {
289*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
290*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
291*61c4878aSAndroid Build Coastguard Worker   ThreadInfo thread_info(0);
292*61c4878aSAndroid Build Coastguard Worker 
293*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread([&mutex, &condvar, &info = thread_info] {
294*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
295*61c4878aSAndroid Build Coastguard Worker     info.wait_result = condvar.wait_until(
296*61c4878aSAndroid Build Coastguard Worker         l, pw::chrono::SystemClock::now() + kRequiredTimeout, info.Predicate());
297*61c4878aSAndroid Build Coastguard Worker     info.done_notifier.release();
298*61c4878aSAndroid Build Coastguard Worker   });
299*61c4878aSAndroid Build Coastguard Worker 
300*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.waiting_notifier.try_acquire_for(kFailureTimeout));
301*61c4878aSAndroid Build Coastguard Worker   {
302*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
303*61c4878aSAndroid Build Coastguard Worker     thread_info.predicate_result = true;
304*61c4878aSAndroid Build Coastguard Worker   }
305*61c4878aSAndroid Build Coastguard Worker   condvar.notify_one();
306*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.done_notifier.try_acquire_for(kFailureTimeout));
307*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.wait_result);
308*61c4878aSAndroid Build Coastguard Worker }
309*61c4878aSAndroid Build Coastguard Worker 
310*61c4878aSAndroid Build Coastguard Worker // NOTE: This test waits even in successful circumstances.
TEST(WaitUntil,ReturnsFalseIfTimesOut)311*61c4878aSAndroid Build Coastguard Worker TEST(WaitUntil, ReturnsFalseIfTimesOut) {
312*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
313*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
314*61c4878aSAndroid Build Coastguard Worker   ThreadInfo thread_info(0);
315*61c4878aSAndroid Build Coastguard Worker 
316*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread([&mutex, &condvar, &info = thread_info] {
317*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
318*61c4878aSAndroid Build Coastguard Worker     info.wait_result = condvar.wait_until(
319*61c4878aSAndroid Build Coastguard Worker         l, pw::chrono::SystemClock::now() + kRequiredTimeout, info.Predicate());
320*61c4878aSAndroid Build Coastguard Worker     info.done_notifier.release();
321*61c4878aSAndroid Build Coastguard Worker   });
322*61c4878aSAndroid Build Coastguard Worker 
323*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.waiting_notifier.try_acquire_for(kFailureTimeout));
324*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.done_notifier.try_acquire_for(kFailureTimeout));
325*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(thread_info.wait_result);
326*61c4878aSAndroid Build Coastguard Worker }
327*61c4878aSAndroid Build Coastguard Worker 
328*61c4878aSAndroid Build Coastguard Worker // NOTE: This test waits even in successful circumstances.
TEST(WaitUntil,TimeoutApproximatelyCorrect)329*61c4878aSAndroid Build Coastguard Worker TEST(WaitUntil, TimeoutApproximatelyCorrect) {
330*61c4878aSAndroid Build Coastguard Worker   Mutex mutex;
331*61c4878aSAndroid Build Coastguard Worker   ConditionVariable condvar;
332*61c4878aSAndroid Build Coastguard Worker   ThreadInfo thread_info(0);
333*61c4878aSAndroid Build Coastguard Worker   pw::chrono::SystemClock::duration wait_duration{};
334*61c4878aSAndroid Build Coastguard Worker 
335*61c4878aSAndroid Build Coastguard Worker   LambdaThread thread([&mutex, &condvar, &info = thread_info, &wait_duration] {
336*61c4878aSAndroid Build Coastguard Worker     StateLock l{mutex};
337*61c4878aSAndroid Build Coastguard Worker     auto start = pw::chrono::SystemClock::now();
338*61c4878aSAndroid Build Coastguard Worker     info.wait_result = condvar.wait_until(
339*61c4878aSAndroid Build Coastguard Worker         l, pw::chrono::SystemClock::now() + kRequiredTimeout, info.Predicate());
340*61c4878aSAndroid Build Coastguard Worker     wait_duration = pw::chrono::SystemClock::now() - start;
341*61c4878aSAndroid Build Coastguard Worker     info.done_notifier.release();
342*61c4878aSAndroid Build Coastguard Worker   });
343*61c4878aSAndroid Build Coastguard Worker 
344*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.waiting_notifier.try_acquire_for(kFailureTimeout));
345*61c4878aSAndroid Build Coastguard Worker   // Wake up thread multiple times. Make sure the timeout is observed.
346*61c4878aSAndroid Build Coastguard Worker   for (int i = 0; i < 5; ++i) {
347*61c4878aSAndroid Build Coastguard Worker     condvar.notify_one();
348*61c4878aSAndroid Build Coastguard Worker     pw::this_thread::sleep_for(kRequiredTimeout / 6);
349*61c4878aSAndroid Build Coastguard Worker   }
350*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(thread_info.done_notifier.try_acquire_for(kFailureTimeout));
351*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(thread_info.wait_result);
352*61c4878aSAndroid Build Coastguard Worker   ASSERT_GE(wait_duration, kRequiredTimeout);
353*61c4878aSAndroid Build Coastguard Worker   ASSERT_LE(wait_duration, kRequiredTimeout + kAllowedSlack);
354*61c4878aSAndroid Build Coastguard Worker }
355*61c4878aSAndroid Build Coastguard Worker 
356*61c4878aSAndroid Build Coastguard Worker }  // namespace
357*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::sync
358