Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwaitcondition_unix.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qwaitcondition.h"
6
7#include "qatomic.h"
8#include "qdeadlinetimer.h"
9#include "qmutex.h"
10#include "qplatformdefs.h"
11#include "qreadwritelock.h"
12#include "qstring.h"
13
14#include "private/qcore_unix_p.h"
15#include "qreadwritelock_p.h"
16
17#include <errno.h>
18#include <sys/time.h>
19#include <time.h>
20
22
23static constexpr clockid_t SteadyClockClockId =
24#if !defined(CLOCK_MONOTONIC)
25 // we don't know how to set the monotonic clock
26 CLOCK_REALTIME
27#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
28 // libc++ falling back to system_clock
29 CLOCK_REALTIME
30#elif defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_CLOCK_MONOTONIC)
31 // libstdc++ falling back to system_clock
32 CLOCK_REALTIME
33#elif defined(Q_OS_DARWIN)
34 // Darwin lacks pthread_condattr_setclock()
35 CLOCK_REALTIME
36#elif defined(Q_OS_QNX)
37 // unknown why
38 CLOCK_REALTIME
39#elif defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
40 // both libstdc++ and libc++ do use CLOCK_MONOTONIC
41 CLOCK_MONOTONIC
42#else
43# warning "Unknown C++ Standard Library implementation - code may be sub-optimal"
44 CLOCK_REALTIME
45#endif
46 ;
47
48static void qt_report_pthread_error(int code, const char *where, const char *what)
49{
50 if (code != 0)
51 qErrnoWarning(code, "%s: %s failure", where, what);
52}
53
54static void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where)
55{
56 pthread_condattr_t *attrp = nullptr;
57
58#if defined(CLOCK_MONOTONIC) && !defined(Q_OS_DARWIN)
59 pthread_condattr_t condattr;
60 attrp = &condattr;
61
62 pthread_condattr_init(&condattr);
63 auto destroy = qScopeGuard([&] { pthread_condattr_destroy(&condattr); });
64 if (SteadyClockClockId != CLOCK_REALTIME)
65 pthread_condattr_setclock(&condattr, SteadyClockClockId);
66#endif
67
68 qt_report_pthread_error(pthread_cond_init(cond, attrp), where, "cv init");
69}
70
72{
73 using namespace std::chrono;
74 using Clock =
75 std::conditional_t<SteadyClockClockId == CLOCK_REALTIME, system_clock, steady_clock>;
76 auto timePoint = deadline.deadline<Clock>();
77 *ts = durationToTimespec(timePoint.time_since_epoch());
78}
79
81{
82public:
83 pthread_mutex_t mutex;
84 pthread_cond_t cond;
87
89 {
90 timespec ti;
92 return pthread_cond_timedwait(&cond, &mutex, &ti);
93 }
94
96 {
97 int code;
98 forever {
99 if (!deadline.isForever()) {
100 code = wait_relative(deadline);
101 } else {
102 code = pthread_cond_wait(&cond, &mutex);
103 }
104 if (code == 0 && wakeups == 0) {
105 // spurious wakeup
106 continue;
107 }
108 break;
109 }
110
111 Q_ASSERT_X(waiters > 0, "QWaitCondition::wait", "internal error (waiters)");
112 --waiters;
113 if (code == 0) {
114 Q_ASSERT_X(wakeups > 0, "QWaitCondition::wait", "internal error (wakeups)");
115 --wakeups;
116 }
117 qt_report_pthread_error(pthread_mutex_unlock(&mutex), "QWaitCondition::wait()",
118 "mutex unlock");
119
120 if (code && code != ETIMEDOUT)
121 qt_report_pthread_error(code, "QWaitCondition::wait()", "cv wait");
122
123 return (code == 0);
124 }
125};
126
128{
130 qt_report_pthread_error(pthread_mutex_init(&d->mutex, nullptr), "QWaitCondition", "mutex init");
131 qt_initialize_pthread_cond(&d->cond, "QWaitCondition");
132 d->waiters = d->wakeups = 0;
133}
134
136{
137 qt_report_pthread_error(pthread_cond_destroy(&d->cond), "QWaitCondition", "cv destroy");
138 qt_report_pthread_error(pthread_mutex_destroy(&d->mutex), "QWaitCondition", "mutex destroy");
139 delete d;
140}
141
143{
144 qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeOne()",
145 "mutex lock");
146 d->wakeups = qMin(d->wakeups + 1, d->waiters);
147 qt_report_pthread_error(pthread_cond_signal(&d->cond), "QWaitCondition::wakeOne()",
148 "cv signal");
149 qt_report_pthread_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeOne()",
150 "mutex unlock");
151}
152
154{
155 qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeAll()",
156 "mutex lock");
157 d->wakeups = d->waiters;
158 qt_report_pthread_error(pthread_cond_broadcast(&d->cond), "QWaitCondition::wakeAll()",
159 "cv broadcast");
160 qt_report_pthread_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeAll()",
161 "mutex unlock");
162}
163
164bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
165{
166 if (time == std::numeric_limits<unsigned long>::max())
168 return wait(mutex, QDeadlineTimer(time));
169}
170
172{
173 if (!mutex)
174 return false;
175
176 qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
177 ++d->waiters;
178 mutex->unlock();
179
180 bool returnValue = d->wait(deadline);
181
182 mutex->lock();
183
184 return returnValue;
185}
186
187bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
188{
189 if (time == std::numeric_limits<unsigned long>::max())
190 return wait(readWriteLock, QDeadlineTimer(QDeadlineTimer::Forever));
191 return wait(readWriteLock, QDeadlineTimer(time));
192}
193
195{
196 using namespace QReadWriteLockStates;
197
198 if (!readWriteLock)
199 return false;
200 auto previousState = QReadWriteLockPrivate::stateForWaitCondition(readWriteLock);
201 if (previousState == Unlocked)
202 return false;
203 if (previousState == RecursivelyLocked) {
204 qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()");
205 return false;
206 }
207
208 qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
209 ++d->waiters;
210
211 readWriteLock->unlock();
212
213 bool returnValue = d->wait(deadline);
214
215 if (previousState == LockedForWrite)
216 readWriteLock->lockForWrite();
217 else
218 readWriteLock->lockForRead();
219
220 return returnValue;
221}
222
\inmodule QtCore
qint64 deadline() const noexcept Q_DECL_PURE_FUNCTION
Returns the absolute time point for the deadline stored in QDeadlineTimer object, calculated in milli...
constexpr bool isForever() const noexcept
Returns true if this QDeadlineTimer object never expires, false otherwise.
static constexpr ForeverConstant Forever
\inmodule QtCore
Definition qmutex.h:281
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:289
void lock() noexcept
Locks the mutex.
Definition qmutex.h:286
static QReadWriteLockStates::StateForWaitCondition stateForWaitCondition(const QReadWriteLock *lock)
\inmodule QtCore
bool wait(QDeadlineTimer deadline)
int wait_relative(QDeadlineTimer deadline)
bool wait(QMutex *, QDeadlineTimer=QDeadlineTimer(QDeadlineTimer::Forever))
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
timespec durationToTimespec(std::chrono::nanoseconds timeout) noexcept
#define forever
Definition qforeach.h:78
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
static void qt_abstime_for_timeout(timespec *ts, QDeadlineTimer deadline)
static void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where)
static void qt_report_pthread_error(int code, const char *where, const char *what)
static QT_BEGIN_NAMESPACE constexpr clockid_t SteadyClockClockId
QDeadlineTimer deadline(30s)
QMutex mutex
[2]