1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: no-exceptions
10 // UNSUPPORTED: no-threads
12 // <condition_variable>
14 // class condition_variable_any;
27 // -----------------------------------------------------------------------------
29 // Check that std::terminate is called if wait(...) fails to meet its post
30 // conditions. This can happen when reacquiring the mutex throws
33 // The following methods are tested within this file
34 // 1. void wait(Lock& lock);
35 // 2. void wait(Lock& lock, Pred);
36 // 3. void wait_for(Lock& lock, Duration);
37 // 4. void wait_for(Lock& lock, Duration, Pred);
38 // 5. void wait_until(Lock& lock, TimePoint);
39 // 6. void wait_until(Lock& lock, TimePoint, Pred);
40 // 7. bool wait(Lock& lock, stop_token stoken, Predicate pred);
41 // 8. bool wait_for(Lock& lock, stop_token stoken, Duration, Predicate pred);
42 // 9. bool wait_until(Lock& lock, stop_token stoken, TimePoint, Predicate pred);
45 // 1 Create a mutex type, 'ThrowingMutex', that throws when the lock is acquired
46 // for the *second* time.
48 // 2 Replace the terminate handler with one that exits with a '0' exit code.
50 // 3 Create a 'condition_variable_any' object 'cv' and a 'ThrowingMutex'
51 // object 'm' and lock 'm'.
53 // 4 Start a thread 'T2' that will notify 'cv' once 'm' has been unlocked.
55 // 5 From the main thread call the specified wait method on 'cv' with 'm'.
56 // When 'T2' notifies 'cv' and the wait method attempts to re-lock
57 // 'm' an exception will be thrown from 'm.lock()'.
59 // 6 Check that control flow does not return from the wait method and that
60 // terminate is called (If the program exits with a 0 exit code we know
61 // that terminate has been called)
67 #include <condition_variable>
74 #include "make_test_thread.h"
75 #include "test_macros.h"
78 std::_Exit(0); // Use _Exit to prevent cleanup from taking place.
81 // The predicate used in the cv.wait calls.
83 bool pred_function() {
89 std::atomic_bool locked
;
91 ThrowingMutex(const ThrowingMutex
&) = delete;
92 ThrowingMutex
& operator=(const ThrowingMutex
&) = delete;
97 ~ThrowingMutex() = default;
102 assert(pred
); // Check that we actually waited until we were signaled.
103 throw 1; // this throw should end up calling terminate()
107 void unlock() { locked
= false; }
108 bool isLocked() const { return locked
== true; }
112 std::condition_variable_any cv
;
115 while (mut
.isLocked()) {} // wait until T1 releases mut inside the cv.wait call.
120 typedef std::chrono::system_clock Clock
;
121 typedef std::chrono::milliseconds MS
;
123 int main(int argc
, char **argv
) {
125 int id
= std::stoi(argv
[1]);
126 assert(id
>= 1 && id
<= 9);
127 std::set_terminate(my_terminate
); // set terminate after std::stoi because it can throw.
131 assert(pred
== false);
132 support::make_test_thread(signal_me
).detach();
134 case 1: cv
.wait(mut
); break;
135 case 2: cv
.wait(mut
, pred_function
); break;
136 case 3: cv
.wait_for(mut
, wait
); break;
137 case 4: cv
.wait_for(mut
, wait
, pred_function
); break;
138 case 5: cv
.wait_until(mut
, Clock::now() + wait
); break;
139 case 6: cv
.wait_until(mut
, Clock::now() + wait
, pred_function
); break;
140 #if TEST_STD_VER >= 20 && !(defined(_LIBCPP_VERSION) && !_LIBCPP_AVAILABILITY_HAS_SYNC)
141 case 7: cv
.wait(mut
, std::stop_source
{}.get_token(), pred_function
); break;
142 case 8: cv
.wait_for(mut
, std::stop_source
{}.get_token(), wait
, pred_function
); break;
143 case 9: cv
.wait_until(mut
, std::stop_source
{}.get_token(), Clock::now() + wait
, pred_function
); break;
150 default: assert(false);