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 //===----------------------------------------------------------------------===//
8 //
9 // UNSUPPORTED: libcpp-has-no-threads
10 // UNSUPPORTED: c++98, c++03
11 
12 // FLAKY_TEST.
13 
14 // <future>
15 
16 // class shared_future<R>
17 
18 // template <class Clock, class Duration>
19 //   future_status
20 //   wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
21 
22 #include <future>
23 #include <atomic>
24 #include <cassert>
25 
26 enum class WorkerThreadState { Uninitialized, AllowedToRun, Exiting };
27 typedef std::chrono::milliseconds ms;
28 
29 std::atomic<WorkerThreadState> thread_state(WorkerThreadState::Uninitialized);
30 
31 void set_worker_thread_state(WorkerThreadState state)
32 {
33     thread_state.store(state, std::memory_order_relaxed);
34 }
35 
36 void wait_for_worker_thread_state(WorkerThreadState state)
37 {
38     while (thread_state.load(std::memory_order_relaxed) != state);
39 }
40 
41 void func1(std::promise<int> p)
42 {
43     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
44     p.set_value(3);
45     set_worker_thread_state(WorkerThreadState::Exiting);
46 }
47 
48 int j = 0;
49 
50 void func3(std::promise<int&> p)
51 {
52     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
53     j = 5;
54     p.set_value(j);
55     set_worker_thread_state(WorkerThreadState::Exiting);
56 }
57 
58 void func5(std::promise<void> p)
59 {
60     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
61     p.set_value();
62     set_worker_thread_state(WorkerThreadState::Exiting);
63 }
64 
65 int main(int, char**)
66 {
67     typedef std::chrono::high_resolution_clock Clock;
68     {
69         typedef int T;
70         std::promise<T> p;
71         std::shared_future<T> f = p.get_future();
72         std::thread(func1, std::move(p)).detach();
73         assert(f.valid());
74         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
75         assert(f.valid());
76 
77         // allow the worker thread to produce the result and wait until the worker is done
78         set_worker_thread_state(WorkerThreadState::AllowedToRun);
79         wait_for_worker_thread_state(WorkerThreadState::Exiting);
80 
81         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
82         assert(f.valid());
83         Clock::time_point t0 = Clock::now();
84         f.wait();
85         Clock::time_point t1 = Clock::now();
86         assert(f.valid());
87         assert(t1-t0 < ms(5));
88     }
89     {
90         typedef int& T;
91         std::promise<T> p;
92         std::shared_future<T> f = p.get_future();
93         std::thread(func3, std::move(p)).detach();
94         assert(f.valid());
95         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
96         assert(f.valid());
97 
98         // allow the worker thread to produce the result and wait until the worker is done
99         set_worker_thread_state(WorkerThreadState::AllowedToRun);
100         wait_for_worker_thread_state(WorkerThreadState::Exiting);
101 
102         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
103         assert(f.valid());
104         Clock::time_point t0 = Clock::now();
105         f.wait();
106         Clock::time_point t1 = Clock::now();
107         assert(f.valid());
108         assert(t1-t0 < ms(5));
109     }
110     {
111         typedef void T;
112         std::promise<T> p;
113         std::shared_future<T> f = p.get_future();
114         std::thread(func5, std::move(p)).detach();
115         assert(f.valid());
116         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
117         assert(f.valid());
118 
119         // allow the worker thread to produce the result and wait until the worker is done
120         set_worker_thread_state(WorkerThreadState::AllowedToRun);
121         wait_for_worker_thread_state(WorkerThreadState::Exiting);
122 
123         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
124         assert(f.valid());
125         Clock::time_point t0 = Clock::now();
126         f.wait();
127         Clock::time_point t1 = Clock::now();
128         assert(f.valid());
129         assert(t1-t0 < ms(5));
130     }
131 
132   return 0;
133 }
134