1 | //===-------------------- condition_variable.cpp --------------------------===// |
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 | #include "__config" |
10 | |
11 | #ifndef _LIBCPP_HAS_NO_THREADS |
12 | |
13 | #include "condition_variable" |
14 | #include "thread" |
15 | #include "system_error" |
16 | #include "__undef_macros" |
17 | |
18 | #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) |
19 | #pragma comment(lib, "pthread") |
20 | #endif |
21 | |
22 | _LIBCPP_BEGIN_NAMESPACE_STD |
23 | |
24 | // ~condition_variable is defined elsewhere. |
25 | |
26 | void |
27 | condition_variable::notify_one() _NOEXCEPT |
28 | { |
29 | __libcpp_condvar_signal(&__cv_); |
30 | } |
31 | |
32 | void |
33 | condition_variable::notify_all() _NOEXCEPT |
34 | { |
35 | __libcpp_condvar_broadcast(&__cv_); |
36 | } |
37 | |
38 | void |
39 | condition_variable::wait(unique_lock<mutex>& lk) _NOEXCEPT |
40 | { |
41 | if (!lk.owns_lock()) |
42 | __throw_system_error(EPERM, |
43 | "condition_variable::wait: mutex not locked" ); |
44 | int ec = __libcpp_condvar_wait(&__cv_, lk.mutex()->native_handle()); |
45 | if (ec) |
46 | __throw_system_error(ec, "condition_variable wait failed" ); |
47 | } |
48 | |
49 | void |
50 | condition_variable::__do_timed_wait(unique_lock<mutex>& lk, |
51 | chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) _NOEXCEPT |
52 | { |
53 | using namespace chrono; |
54 | if (!lk.owns_lock()) |
55 | __throw_system_error(EPERM, |
56 | "condition_variable::timed wait: mutex not locked" ); |
57 | nanoseconds d = tp.time_since_epoch(); |
58 | if (d > nanoseconds(0x59682F000000E941)) |
59 | d = nanoseconds(0x59682F000000E941); |
60 | __libcpp_timespec_t ts; |
61 | seconds s = duration_cast<seconds>(d); |
62 | typedef decltype(ts.tv_sec) ts_sec; |
63 | _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max(); |
64 | if (s.count() < ts_sec_max) |
65 | { |
66 | ts.tv_sec = static_cast<ts_sec>(s.count()); |
67 | ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count()); |
68 | } |
69 | else |
70 | { |
71 | ts.tv_sec = ts_sec_max; |
72 | ts.tv_nsec = giga::num - 1; |
73 | } |
74 | int ec = __libcpp_condvar_timedwait(&__cv_, lk.mutex()->native_handle(), &ts); |
75 | if (ec != 0 && ec != ETIMEDOUT) |
76 | __throw_system_error(ec, "condition_variable timed_wait failed" ); |
77 | } |
78 | |
79 | void |
80 | notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk) |
81 | { |
82 | auto& tl_ptr = __thread_local_data(); |
83 | // If this thread was not created using std::thread then it will not have |
84 | // previously allocated. |
85 | if (tl_ptr.get() == nullptr) { |
86 | tl_ptr.set_pointer(new __thread_struct); |
87 | } |
88 | __thread_local_data()->notify_all_at_thread_exit(&cond, lk.release()); |
89 | } |
90 | |
91 | _LIBCPP_END_NAMESPACE_STD |
92 | |
93 | #endif // !_LIBCPP_HAS_NO_THREADS |
94 | |