1 | // Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | #ifndef QWAITCONDITION_P_H |
4 | #define QWAITCONDITION_P_H |
5 | |
6 | // |
7 | // W A R N I N G |
8 | // ------------- |
9 | // |
10 | // This file is not part of the Qt API. It exists for the convenience of |
11 | // qmutex.cpp and qmutex_unix.cpp. This header file may change from version to |
12 | // version without notice, or even be removed. |
13 | // |
14 | // We mean it. |
15 | // |
16 | |
17 | #include <QtCore/QWaitCondition> |
18 | #include <QtCore/QMutex> |
19 | #include <QtCore/QDeadlineTimer> |
20 | #include <QtCore/private/qglobal_p.h> |
21 | |
22 | // This header always defines a class called "mutex" and one called |
23 | // "condition_variable", so those mustn't be used to mark ELF symbol |
24 | // visibility. Don't add more classes to this header! |
25 | // ELFVERSION:stop |
26 | |
27 | #include <condition_variable> |
28 | #include <mutex> |
29 | |
30 | // There's no feature macro for C++11 std::mutex, so we use the C++14 one |
31 | // for shared_mutex to detect it. |
32 | // Needed for: MinGW without gthreads, Integrity |
33 | #if __has_include(<shared_mutex>) |
34 | # include <shared_mutex> |
35 | #endif |
36 | |
37 | QT_BEGIN_NAMESPACE |
38 | |
39 | namespace QtPrivate { |
40 | |
41 | #if !defined(__cpp_lib_shared_timed_mutex) |
42 | |
43 | enum class cv_status { no_timeout, timeout }; |
44 | class condition_variable; |
45 | |
46 | class mutex : private QMutex |
47 | { |
48 | friend class QtPrivate::condition_variable; |
49 | |
50 | public: |
51 | // all special member functions are ok! |
52 | // do not expose the (QMutex::Recursive) ctor |
53 | // don't use 'using QMutex::lock;' etc as those have the wrong noexcept |
54 | |
55 | void lock() { return QMutex::lock(); } |
56 | void unlock() { return QMutex::unlock(); } |
57 | bool try_lock() { return QMutex::tryLock(); } |
58 | }; |
59 | |
60 | class condition_variable : private QWaitCondition |
61 | { |
62 | public: |
63 | // all special member functions are ok! |
64 | |
65 | void notify_one() { QWaitCondition::wakeOne(); } |
66 | void notify_all() { QWaitCondition::wakeAll(); } |
67 | |
68 | void wait(std::unique_lock<QtPrivate::mutex> &lock) { QWaitCondition::wait(lock.mutex()); } |
69 | template <class Predicate> |
70 | void wait(std::unique_lock<QtPrivate::mutex> &lock, Predicate p) |
71 | { |
72 | while (!p()) |
73 | wait(lock); |
74 | } |
75 | |
76 | template <typename Rep, typename Period> |
77 | cv_status wait_for(std::unique_lock<QtPrivate::mutex> &lock, |
78 | const std::chrono::duration<Rep, Period> &d) |
79 | { |
80 | return QWaitCondition::wait(lock.mutex(), QDeadlineTimer{d}) |
81 | ? cv_status::no_timeout |
82 | : cv_status::timeout; |
83 | } |
84 | template <typename Rep, typename Period, typename Predicate> |
85 | bool wait_for(std::unique_lock<QtPrivate::mutex> &lock, |
86 | const std::chrono::duration<Rep, Period> &d, Predicate p) |
87 | { |
88 | const auto timer = QDeadlineTimer{d}; |
89 | while (!p()) { |
90 | if (!QWaitCondition::wait(lock.mutex(), timer)) |
91 | return p(); |
92 | } |
93 | return true; |
94 | } |
95 | |
96 | template <typename Clock, typename Duration> |
97 | cv_status wait_until(std::unique_lock<QtPrivate::mutex> &lock, |
98 | const std::chrono::time_point<Clock, Duration> &t) |
99 | { |
100 | return QWaitCondition::wait(lock.mutex(), QDeadlineTimer{t}) |
101 | ? cv_status::no_timeout |
102 | : cv_status::timeout; |
103 | } |
104 | |
105 | template <typename Clock, typename Duration, typename Predicate> |
106 | bool wait_until(std::unique_lock<QtPrivate::mutex> &lock, |
107 | const std::chrono::time_point<Clock, Duration> &t, Predicate p) |
108 | { |
109 | const auto timer = QDeadlineTimer{t}; |
110 | while (!p()) { |
111 | if (!QWaitCondition::wait(lock.mutex(), timer)) |
112 | return p(); |
113 | } |
114 | return true; |
115 | } |
116 | |
117 | }; |
118 | |
119 | #else // C++11 threads |
120 | |
121 | using mutex = std::mutex; |
122 | using condition_variable = std::condition_variable; |
123 | |
124 | #endif // C++11 threads |
125 | |
126 | } // namespace QtPrivate |
127 | |
128 | QT_END_NAMESPACE |
129 | |
130 | #endif /* QWAITCONDITION_P_H */ |
131 | |