Reland [OffloadBundler] Compress bundles over 4GB (#122307)
[llvm-project.git] / libcxx / test / std / thread / thread.condition / thread.condition.condvar / wait_for.pass.cpp
blob6a054f74b9fb9d76a458b2c240a85c25c1a5a297
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: no-threads, c++03
11 // <condition_variable>
13 // class condition_variable;
15 // template <class Rep, class Period>
16 // cv_status
17 // wait_for(unique_lock<mutex>& lock,
18 // const chrono::duration<Rep, Period>& rel_time);
20 #include <condition_variable>
21 #include <atomic>
22 #include <cassert>
23 #include <chrono>
24 #include <mutex>
25 #include <thread>
27 #include "make_test_thread.h"
28 #include "test_macros.h"
30 template <class Function>
31 std::chrono::microseconds measure(Function f) {
32 std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
33 f();
34 std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
35 return std::chrono::duration_cast<std::chrono::microseconds>(end - start);
38 int main(int, char**) {
39 // Test unblocking via a call to notify_one() in another thread.
41 // To test this, we set a very long timeout in wait_for() and we wait
42 // again in case we get awoken spuriously. Note that it can actually
43 // happen that we get awoken spuriously and fail to recognize it
44 // (making this test useless), but the likelihood should be small.
46 std::atomic<bool> ready(false);
47 std::atomic<bool> likely_spurious(true);
48 auto timeout = std::chrono::seconds(3600);
49 std::condition_variable cv;
50 std::mutex mutex;
52 std::thread t1 = support::make_test_thread([&] {
53 std::unique_lock<std::mutex> lock(mutex);
54 auto elapsed = measure([&] {
55 ready = true;
56 do {
57 std::cv_status result = cv.wait_for(lock, timeout);
58 assert(result == std::cv_status::no_timeout);
59 } while (likely_spurious);
60 });
62 // This can technically fail if we have many spurious awakenings, but in practice the
63 // tolerance is so high that it shouldn't be a problem.
64 assert(elapsed < timeout);
65 });
67 std::thread t2 = support::make_test_thread([&] {
68 while (!ready) {
69 // spin
72 // Acquire the same mutex as t1. This blocks the condition variable inside its wait call
73 // so we can notify it while it is waiting.
74 std::unique_lock<std::mutex> lock(mutex);
75 cv.notify_one();
76 likely_spurious = false;
77 lock.unlock();
78 });
80 t2.join();
81 t1.join();
84 // Test unblocking via a timeout.
86 // To test this, we create a thread that waits on a condition variable
87 // with a certain timeout, and we never awaken it. To guard against
88 // spurious wakeups, we wait again whenever we are awoken for a reason
89 // other than a timeout.
91 auto timeout = std::chrono::milliseconds(250);
92 std::condition_variable cv;
93 std::mutex mutex;
95 std::thread t1 = support::make_test_thread([&] {
96 std::unique_lock<std::mutex> lock(mutex);
97 std::cv_status result;
98 do {
99 auto elapsed = measure([&] { result = cv.wait_for(lock, timeout); });
100 if (result == std::cv_status::timeout)
101 assert(elapsed >= timeout);
102 } while (result != std::cv_status::timeout);
105 t1.join();
108 return 0;