qwaitcondition_unix.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/corelib/thread/qwaitcondition_unix.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Copyright (C) 2016 Intel Corporation.-
5** Contact: https://www.qt.io/licensing/-
6**-
7** This file is part of the QtCore module of the Qt Toolkit.-
8**-
9** $QT_BEGIN_LICENSE:LGPL$-
10** Commercial License Usage-
11** Licensees holding valid commercial Qt licenses may use this file in-
12** accordance with the commercial license agreement provided with the-
13** Software or, alternatively, in accordance with the terms contained in-
14** a written agreement between you and The Qt Company. For licensing terms-
15** and conditions see https://www.qt.io/terms-conditions. For further-
16** information use the contact form at https://www.qt.io/contact-us.-
17**-
18** GNU Lesser General Public License Usage-
19** Alternatively, this file may be used under the terms of the GNU Lesser-
20** General Public License version 3 as published by the Free Software-
21** Foundation and appearing in the file LICENSE.LGPL3 included in the-
22** packaging of this file. Please review the following information to-
23** ensure the GNU Lesser General Public License version 3 requirements-
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
25**-
26** GNU General Public License Usage-
27** Alternatively, this file may be used under the terms of the GNU-
28** General Public License version 2.0 or (at your option) the GNU General-
29** Public license version 3 or any later version approved by the KDE Free-
30** Qt Foundation. The licenses are as published by the Free Software-
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
32** included in the packaging of this file. Please review the following-
33** information to ensure the GNU General Public License requirements will-
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
35** https://www.gnu.org/licenses/gpl-3.0.html.-
36**-
37** $QT_END_LICENSE$-
38**-
39****************************************************************************/-
40-
41#include "qplatformdefs.h"-
42#include "qwaitcondition.h"-
43#include "qmutex.h"-
44#include "qreadwritelock.h"-
45#include "qatomic.h"-
46#include "qstring.h"-
47#include "qelapsedtimer.h"-
48#include "private/qcore_unix_p.h"-
49-
50#include "qmutex_p.h"-
51#include "qreadwritelock_p.h"-
52-
53#include <errno.h>-
54#include <sys/time.h>-
55#include <time.h>-
56-
57#ifndef QT_NO_THREAD-
58-
59QT_BEGIN_NAMESPACE-
60-
61#ifdef Q_OS_ANDROID-
62// pthread_condattr_setclock is available only since Android 5.0. On older versions, there's-
63// a private function for relative waits (hidden in 5.0).-
64// Use weakref so we can determine at runtime whether each of them is present.-
65static int local_condattr_setclock(pthread_condattr_t*, clockid_t)-
66__attribute__((weakref("pthread_condattr_setclock")));-
67-
68static int local_cond_timedwait_relative(pthread_cond_t*, pthread_mutex_t *, const timespec *)-
69__attribute__((weakref("__pthread_cond_timedwait_relative")));-
70#endif-
71-
72static void report_error(int code, const char *where, const char *what)-
73{-
74 if (code != 0)-
75 qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code)));-
76}-
77-
78void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where)-
79{-
80 pthread_condattr_t condattr;-
81-
82 pthread_condattr_init(&condattr);-
83#if (_POSIX_MONOTONIC_CLOCK-0 >= 0)-
84#if defined(Q_OS_ANDROID)-
85 if (local_condattr_setclock && QElapsedTimer::clockType() == QElapsedTimer::MonotonicClock)-
86 local_condattr_setclock(&condattr, CLOCK_MONOTONIC);-
87#elif !defined(Q_OS_MAC)-
88 if (QElapsedTimer::clockType() == QElapsedTimer::MonotonicClock)-
89 pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);-
90#endif-
91#endif-
92 report_error(pthread_cond_init(cond, &condattr), where, "cv init");-
93 pthread_condattr_destroy(&condattr);-
94}-
95-
96void qt_abstime_for_timeout(timespec *ts, int timeout)-
97{-
98#ifdef Q_OS_MAC-
99 // on Mac, qt_gettime() (on qelapsedtimer_mac.cpp) returns ticks related to the Mach absolute time-
100 // that doesn't work with pthread-
101 // Mac also doesn't have clock_gettime-
102 struct timeval tv;-
103 gettimeofday(&tv, 0);-
104 ts->tv_sec = tv.tv_sec;-
105 ts->tv_nsec = tv.tv_usec * 1000;-
106#else-
107 *ts = qt_gettime();-
108#endif-
109-
110 ts->tv_sec += timeout / 1000;-
111 ts->tv_nsec += timeout % 1000 * Q_UINT64_C(1000) * 1000;-
112 normalizedTimespec(*ts);-
113}-
114-
115class QWaitConditionPrivate {-
116public:-
117 pthread_mutex_t mutex;-
118 pthread_cond_t cond;-
119 int waiters;-
120 int wakeups;-
121-
122 int wait_relative(unsigned long time)-
123 {-
124 timespec ti;-
125#ifdef Q_OS_ANDROID-
126 if (local_cond_timedwait_relative) {-
127 ti.tv_sec = time / 1000;-
128 ti.tv_nsec = time % 1000 * Q_UINT64_C(1000) * 1000;-
129 return local_cond_timedwait_relative(&cond, &mutex, &ti);-
130 }-
131#endif-
132 qt_abstime_for_timeout(&ti, time);-
133 return pthread_cond_timedwait(&cond, &mutex, &ti);-
134 }-
135-
136 bool wait(unsigned long time)-
137 {-
138 int code;-
139 forever {-
140 if (time != ULONG_MAX) {-
141 code = wait_relative(time);-
142 } else {-
143 code = pthread_cond_wait(&cond, &mutex);-
144 }-
145 if (code == 0 && wakeups == 0) {-
146 // many vendors warn of spurious wakeups from-
147 // pthread_cond_wait(), especially after signal delivery,-
148 // even though POSIX doesn't allow for it... sigh-
149 continue;-
150 }-
151 break;-
152 }-
153-
154 Q_ASSERT_X(waiters > 0, "QWaitCondition::wait", "internal error (waiters)");-
155 --waiters;-
156 if (code == 0) {-
157 Q_ASSERT_X(wakeups > 0, "QWaitCondition::wait", "internal error (wakeups)");-
158 --wakeups;-
159 }-
160 report_error(pthread_mutex_unlock(&mutex), "QWaitCondition::wait()", "mutex unlock");-
161-
162 if (code && code != ETIMEDOUT)-
163 report_error(code, "QWaitCondition::wait()", "cv wait");-
164-
165 return (code == 0);-
166 }-
167};-
168-
169-
170QWaitCondition::QWaitCondition()-
171{-
172 d = new QWaitConditionPrivate;-
173 report_error(pthread_mutex_init(&d->mutex, NULL), "QWaitCondition", "mutex init");-
174 qt_initialize_pthread_cond(&d->cond, "QWaitCondition");-
175 d->waiters = d->wakeups = 0;-
176}-
177-
178-
179QWaitCondition::~QWaitCondition()-
180{-
181 report_error(pthread_cond_destroy(&d->cond), "QWaitCondition", "cv destroy");-
182 report_error(pthread_mutex_destroy(&d->mutex), "QWaitCondition", "mutex destroy");-
183 delete d;-
184}-
185-
186void QWaitCondition::wakeOne()-
187{-
188 report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeOne()", "mutex lock");-
189 d->wakeups = qMin(d->wakeups + 1, d->waiters);-
190 report_error(pthread_cond_signal(&d->cond), "QWaitCondition::wakeOne()", "cv signal");-
191 report_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeOne()", "mutex unlock");-
192}-
193-
194void QWaitCondition::wakeAll()-
195{-
196 report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeAll()", "mutex lock");-
197 d->wakeups = d->waiters;-
198 report_error(pthread_cond_broadcast(&d->cond), "QWaitCondition::wakeAll()", "cv broadcast");-
199 report_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeAll()", "mutex unlock");-
200}-
201-
202bool QWaitCondition::wait(QMutex *mutex, unsigned long time)-
203{-
204 if (! mutex)-
205 return false;-
206 if (mutex->isRecursive()) {-
207 qWarning("QWaitCondition: cannot wait on recursive mutexes");-
208 return false;-
209 }-
210-
211 report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");-
212 ++d->waiters;-
213 mutex->unlock();-
214-
215 bool returnValue = d->wait(time);-
216-
217 mutex->lock();-
218-
219 return returnValue;-
220}-
221-
222bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)-
223{-
224 if (!readWriteLock||)
!readWriteLockDescription
TRUEnever evaluated
FALSEevaluated 274 times by 1 test
Evaluated by:
  • tst_QWaitCondition
0-274
225 return false;
never executed: return false;
0
226 auto previousState = readWriteLock->d->accessCountstateForWaitCondition();-
227 if (previousState
previousState ...Lock::UnlockedDescription
TRUEnever evaluated
FALSEevaluated 274 times by 1 test
Evaluated by:
  • tst_QWaitCondition
== 0QReadWriteLock::Unlocked)
previousState ...Lock::UnlockedDescription
TRUEnever evaluated
FALSEevaluated 274 times by 1 test
Evaluated by:
  • tst_QWaitCondition
0-274
228 return false;
never executed: return false;
0
229 if (readWriteLock->d->accessCount < -1previousState == QReadWriteLock::RecursivelyLocked) {
previousState ...ursivelyLockedDescription
TRUEnever evaluated
FALSEevaluated 274 times by 1 test
Evaluated by:
  • tst_QWaitCondition
0-274
230 qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()");-
231 return false;
never executed: return false;
0
232 }-
233-
234 report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");-
235 ++d->waiters;-
int previousAccessCount = readWriteLock->d->accessCount;
236-
237 readWriteLock->unlock();-
238-
239 bool returnValue = d->wait(time);-
240-
241 if (previousAccessCount < 0previousState == QReadWriteLock::LockedForWrite)
previousState ...LockedForWriteDescription
TRUEevaluated 231 times by 1 test
Evaluated by:
  • tst_QWaitCondition
FALSEevaluated 43 times by 1 test
Evaluated by:
  • tst_QWaitCondition
43-231
242 readWriteLock->lockForWrite();
executed 231 times by 1 test: readWriteLock->lockForWrite();
Executed by:
  • tst_QWaitCondition
231
243 else-
244 readWriteLock->lockForRead();
executed 43 times by 1 test: readWriteLock->lockForRead();
Executed by:
  • tst_QWaitCondition
43
245-
246 return returnValue;
executed 274 times by 1 test: return returnValue;
Executed by:
  • tst_QWaitCondition
274
247}-
248-
249QT_END_NAMESPACE-
250-
251#endif // QT_NO_THREAD-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9