Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
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// Qt-Security score:significant reason:default
5
7
8#include "qatomic.h"
10#include "qmutex.h"
11#include "qplatformdefs.h"
12#include "qreadwritelock.h"
13#include "qstring.h"
14
15#include "private/qcore_unix_p.h"
17
18#include <errno.h>
19#include <sys/time.h>
20#include <time.h>
21
23
24static void qt_report_pthread_error(int code, const char *where, const char *what)
25{
26 if (code != 0)
27 qErrnoWarning(code, "%s: %s failure", where, what);
28}
29
30static void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where)
31{
32 pthread_condattr_t *attrp = nullptr;
33
34#if QT_CONFIG(pthread_condattr_setclock)
35 pthread_condattr_t condattr;
36 attrp = &condattr;
37
38 pthread_condattr_init(&condattr);
39 auto destroy = qScopeGuard([&] { pthread_condattr_destroy(&condattr); });
40 if (QWaitConditionClockId != CLOCK_REALTIME)
41 pthread_condattr_setclock(&condattr, QWaitConditionClockId);
42#endif
43
44 qt_report_pthread_error(pthread_cond_init(cond, attrp), where, "cv init");
45}
46
48{
49public:
50 pthread_mutex_t mutex;
51 pthread_cond_t cond;
54
55 int wait_relative(QDeadlineTimer deadline)
56 {
57 timespec ti = deadlineToAbstime<QWaitConditionClockId>(deadline);
58 return pthread_cond_timedwait(&cond, &mutex, &ti);
59 }
60
61 bool wait(QDeadlineTimer deadline)
62 {
63 int code;
64 forever {
65 if (!deadline.isForever()) {
66 code = wait_relative(deadline);
67 } else {
68 code = pthread_cond_wait(&cond, &mutex);
69 }
70 if (code == 0 && wakeups == 0) {
71 // spurious wakeup
72 continue;
73 }
74 break;
75 }
76
77 Q_ASSERT_X(waiters > 0, "QWaitCondition::wait", "internal error (waiters)");
78 --waiters;
79 if (code == 0) {
80 Q_ASSERT_X(wakeups > 0, "QWaitCondition::wait", "internal error (wakeups)");
81 --wakeups;
82 }
83 qt_report_pthread_error(pthread_mutex_unlock(&mutex), "QWaitCondition::wait()",
84 "mutex unlock");
85
86 if (code && code != ETIMEDOUT)
87 qt_report_pthread_error(code, "QWaitCondition::wait()", "cv wait");
88
89 return (code == 0);
90 }
91};
92
93QWaitCondition::QWaitCondition()
94{
95 d = new QWaitConditionPrivate;
96 qt_report_pthread_error(pthread_mutex_init(&d->mutex, nullptr), "QWaitCondition", "mutex init");
97 qt_initialize_pthread_cond(&d->cond, "QWaitCondition");
98 d->waiters = d->wakeups = 0;
99}
100
101QWaitCondition::~QWaitCondition()
102{
103 qt_report_pthread_error(pthread_cond_destroy(&d->cond), "QWaitCondition", "cv destroy");
104 qt_report_pthread_error(pthread_mutex_destroy(&d->mutex), "QWaitCondition", "mutex destroy");
105 delete d;
106}
107
108void QWaitCondition::wakeOne()
109{
110 qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeOne()",
111 "mutex lock");
112 d->wakeups = qMin(d->wakeups + 1, d->waiters);
113 qt_report_pthread_error(pthread_cond_signal(&d->cond), "QWaitCondition::wakeOne()",
114 "cv signal");
115 qt_report_pthread_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeOne()",
116 "mutex unlock");
117}
118
119void QWaitCondition::wakeAll()
120{
121 qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeAll()",
122 "mutex lock");
123 d->wakeups = d->waiters;
124 qt_report_pthread_error(pthread_cond_broadcast(&d->cond), "QWaitCondition::wakeAll()",
125 "cv broadcast");
126 qt_report_pthread_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeAll()",
127 "mutex unlock");
128}
129
130bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
131{
132 if (time == std::numeric_limits<unsigned long>::max())
133 return wait(mutex, QDeadlineTimer(QDeadlineTimer::Forever));
134 return wait(mutex, QDeadlineTimer(time));
135}
136
137bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline)
138{
139 if (!mutex)
140 return false;
141
142 qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
143 ++d->waiters;
144 mutex->unlock();
145
146 bool returnValue = d->wait(deadline);
147
148 mutex->lock();
149
150 return returnValue;
151}
152
153bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
154{
155 if (time == std::numeric_limits<unsigned long>::max())
156 return wait(readWriteLock, QDeadlineTimer(QDeadlineTimer::Forever));
157 return wait(readWriteLock, QDeadlineTimer(time));
158}
159
160bool QWaitCondition::wait(QReadWriteLock *readWriteLock, QDeadlineTimer deadline)
161{
162 using namespace QReadWriteLockStates;
163
164 if (!readWriteLock)
165 return false;
166 auto previousState = QReadWriteLockPrivate::stateForWaitCondition(readWriteLock);
167 if (previousState == Unlocked)
168 return false;
169 if (previousState == RecursivelyLocked) {
170 qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()");
171 return false;
172 }
173
174 qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
175 ++d->waiters;
176
177 readWriteLock->unlock();
178
179 bool returnValue = d->wait(deadline);
180
181 if (previousState == LockedForWrite)
182 readWriteLock->lockForWrite();
183 else
184 readWriteLock->lockForRead();
185
186 return returnValue;
187}
188
189QT_END_NAMESPACE
bool wait(QDeadlineTimer deadline)
int wait_relative(QDeadlineTimer deadline)
static void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where)
static QT_BEGIN_NAMESPACE void qt_report_pthread_error(int code, const char *where, const char *what)