Absolute File Name: | /home/qt/qt5_coco/qt5/qtbase/src/corelib/thread/qreadwritelock.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /**************************************************************************** | - | ||||||||||||||||||||||||
2 | ** | - | ||||||||||||||||||||||||
3 | ** Copyright (C) 2016 The Qt Company Ltd. | - | ||||||||||||||||||||||||
4 | ** Copyright (C) 2016 Intel Corporation. | - | ||||||||||||||||||||||||
5 | ** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com> | - | ||||||||||||||||||||||||
6 | ** Contact: https://www.qt.io/licensing/ | - | ||||||||||||||||||||||||
7 | ** | - | ||||||||||||||||||||||||
8 | ** This file is part of the QtCore module of the Qt Toolkit. | - | ||||||||||||||||||||||||
9 | ** | - | ||||||||||||||||||||||||
10 | ** $QT_BEGIN_LICENSE:LGPL$ | - | ||||||||||||||||||||||||
11 | ** Commercial License Usage | - | ||||||||||||||||||||||||
12 | ** Licensees holding valid commercial Qt licenses may use this file in | - | ||||||||||||||||||||||||
13 | ** accordance with the commercial license agreement provided with the | - | ||||||||||||||||||||||||
14 | ** Software or, alternatively, in accordance with the terms contained in | - | ||||||||||||||||||||||||
15 | ** a written agreement between you and The Qt Company. For licensing terms | - | ||||||||||||||||||||||||
16 | ** and conditions see https://www.qt.io/terms-conditions. For further | - | ||||||||||||||||||||||||
17 | ** information use the contact form at https://www.qt.io/contact-us. | - | ||||||||||||||||||||||||
18 | ** | - | ||||||||||||||||||||||||
19 | ** GNU Lesser General Public License Usage | - | ||||||||||||||||||||||||
20 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - | ||||||||||||||||||||||||
21 | ** General Public License version 3 as published by the Free Software | - | ||||||||||||||||||||||||
22 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | - | ||||||||||||||||||||||||
23 | ** packaging of this file. Please review the following information to | - | ||||||||||||||||||||||||
24 | ** ensure the GNU Lesser General Public License version 3 requirements | - | ||||||||||||||||||||||||
25 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | - | ||||||||||||||||||||||||
26 | ** | - | ||||||||||||||||||||||||
27 | ** GNU General Public License Usage | - | ||||||||||||||||||||||||
28 | ** Alternatively, this file may be used under the terms of the GNU | - | ||||||||||||||||||||||||
29 | ** General Public License version 2.0 or (at your option) the GNU General | - | ||||||||||||||||||||||||
30 | ** Public license version 3 or any later version approved by the KDE Free | - | ||||||||||||||||||||||||
31 | ** Qt Foundation. The licenses are as published by the Free Software | - | ||||||||||||||||||||||||
32 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | - | ||||||||||||||||||||||||
33 | ** included in the packaging of this file. Please review the following | - | ||||||||||||||||||||||||
34 | ** information to ensure the GNU General Public License requirements will | - | ||||||||||||||||||||||||
35 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | - | ||||||||||||||||||||||||
36 | ** https://www.gnu.org/licenses/gpl-3.0.html. | - | ||||||||||||||||||||||||
37 | ** | - | ||||||||||||||||||||||||
38 | ** $QT_END_LICENSE$ | - | ||||||||||||||||||||||||
39 | ** | - | ||||||||||||||||||||||||
40 | ****************************************************************************/ | - | ||||||||||||||||||||||||
41 | - | |||||||||||||||||||||||||
42 | #include "qplatformdefs.h" | - | ||||||||||||||||||||||||
43 | #include "qreadwritelock.h" | - | ||||||||||||||||||||||||
44 | - | |||||||||||||||||||||||||
45 | #ifndef QT_NO_THREAD | - | ||||||||||||||||||||||||
46 | #include "qmutex.h" | - | ||||||||||||||||||||||||
47 | #include "qthread.h" | - | ||||||||||||||||||||||||
48 | #include "qwaitcondition.h" | - | ||||||||||||||||||||||||
49 | #include "qreadwritelock_p.h" | - | ||||||||||||||||||||||||
50 | #include "qelapsedtimer.h" | - | ||||||||||||||||||||||||
51 | #include "private/qfreelist_p.h" | - | ||||||||||||||||||||||||
52 | - | |||||||||||||||||||||||||
53 | QT_BEGIN_NAMESPACE | - | ||||||||||||||||||||||||
54 | - | |||||||||||||||||||||||||
55 | /* | - | ||||||||||||||||||||||||
56 | * Implementation details of QReadWriteLock: | - | ||||||||||||||||||||||||
57 | * | - | ||||||||||||||||||||||||
58 | * Depending on the valued of d_ptr, the lock is in the following state: | - | ||||||||||||||||||||||||
59 | * - when d_ptr == 0x0: Unlocked (no readers, no writers) and non-recursive. | - | ||||||||||||||||||||||||
60 | * - when d_ptr & 0x1: If the least significant bit is set, we are locked for read. | - | ||||||||||||||||||||||||
61 | * In that case, d_ptr>>4 represents the number of reading threads minus 1. No writers | - | ||||||||||||||||||||||||
62 | * are waiting, and the lock is not recursive. | - | ||||||||||||||||||||||||
63 | * - when d_ptr == 0x2: We are locked for write and nobody is waiting. (no contention) | - | ||||||||||||||||||||||||
64 | * - In any other case, d_ptr points to an actual QReadWriteLockPrivate. | - | ||||||||||||||||||||||||
65 | */ | - | ||||||||||||||||||||||||
66 | - | |||||||||||||||||||||||||
67 | namespace { | - | ||||||||||||||||||||||||
68 | enum { | - | ||||||||||||||||||||||||
69 | StateMask = 0x3, | - | ||||||||||||||||||||||||
70 | StateLockedForRead = 0x1, | - | ||||||||||||||||||||||||
71 | StateLockedForWrite = 0x2, | - | ||||||||||||||||||||||||
72 | }; | - | ||||||||||||||||||||||||
73 | const auto dummyLockedForRead = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(StateLockedForRead)); | - | ||||||||||||||||||||||||
74 | const auto dummyLockedForWrite = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(StateLockedForWrite)); | - | ||||||||||||||||||||||||
75 | inline bool isUncontendedLocked(const QReadWriteLockPrivate *d) | - | ||||||||||||||||||||||||
76 | { executed 317361 times by 523 tests: return quintptr(d) & StateMask; Executed by:
executed 317361 times by 523 tests: return quintptr(d) & StateMask; }return quintptr(d) & StateMask; Executed by:
executed 317361 times by 523 tests: return quintptr(d) & StateMask; Executed by:
| 317361 | ||||||||||||||||||||||||
77 | } | - | ||||||||||||||||||||||||
78 | - | |||||||||||||||||||||||||
79 | /*! \class QReadWriteLock | - | ||||||||||||||||||||||||
80 | \inmodule QtCore | - | ||||||||||||||||||||||||
81 | \brief The QReadWriteLock class provides read-write locking. | - | ||||||||||||||||||||||||
82 | - | |||||||||||||||||||||||||
83 | \threadsafe | - | ||||||||||||||||||||||||
84 | - | |||||||||||||||||||||||||
85 | \ingroup thread | - | ||||||||||||||||||||||||
86 | - | |||||||||||||||||||||||||
87 | A read-write lock is a synchronization tool for protecting | - | ||||||||||||||||||||||||
88 | resources that can be accessed for reading and writing. This type | - | ||||||||||||||||||||||||
89 | of lock is useful if you want to allow multiple threads to have | - | ||||||||||||||||||||||||
90 | simultaneous read-only access, but as soon as one thread wants to | - | ||||||||||||||||||||||||
91 | write to the resource, all other threads must be blocked until | - | ||||||||||||||||||||||||
92 | the writing is complete. | - | ||||||||||||||||||||||||
93 | - | |||||||||||||||||||||||||
94 | In many cases, QReadWriteLock is a direct competitor to QMutex. | - | ||||||||||||||||||||||||
95 | QReadWriteLock is a good choice if there are many concurrent | - | ||||||||||||||||||||||||
96 | reads and writing occurs infrequently. | - | ||||||||||||||||||||||||
97 | - | |||||||||||||||||||||||||
98 | Example: | - | ||||||||||||||||||||||||
99 | - | |||||||||||||||||||||||||
100 | \snippet code/src_corelib_thread_qreadwritelock.cpp 0 | - | ||||||||||||||||||||||||
101 | - | |||||||||||||||||||||||||
102 | To ensure that writers aren't blocked forever by readers, readers | - | ||||||||||||||||||||||||
103 | attempting to obtain a lock will not succeed if there is a blocked | - | ||||||||||||||||||||||||
104 | writer waiting for access, even if the lock is currently only | - | ||||||||||||||||||||||||
105 | accessed by other readers. Also, if the lock is accessed by a | - | ||||||||||||||||||||||||
106 | writer and another writer comes in, that writer will have | - | ||||||||||||||||||||||||
107 | priority over any readers that might also be waiting. | - | ||||||||||||||||||||||||
108 | - | |||||||||||||||||||||||||
109 | Like QMutex, a QReadWriteLock can be recursively locked by the | - | ||||||||||||||||||||||||
110 | same thread when constructed with \l{QReadWriteLock::Recursive} as | - | ||||||||||||||||||||||||
111 | \l{QReadWriteLock::RecursionMode}. In such cases, | - | ||||||||||||||||||||||||
112 | unlock() must be called the same number of times lockForWrite() or | - | ||||||||||||||||||||||||
113 | lockForRead() was called. Note that the lock type cannot be | - | ||||||||||||||||||||||||
114 | changed when trying to lock recursively, i.e. it is not possible | - | ||||||||||||||||||||||||
115 | to lock for reading in a thread that already has locked for | - | ||||||||||||||||||||||||
116 | writing (and vice versa). | - | ||||||||||||||||||||||||
117 | - | |||||||||||||||||||||||||
118 | \sa QReadLocker, QWriteLocker, QMutex, QSemaphore | - | ||||||||||||||||||||||||
119 | */ | - | ||||||||||||||||||||||||
120 | - | |||||||||||||||||||||||||
121 | /*! | - | ||||||||||||||||||||||||
122 | \enum QReadWriteLock::RecursionMode | - | ||||||||||||||||||||||||
123 | \since 4.4 | - | ||||||||||||||||||||||||
124 | - | |||||||||||||||||||||||||
125 | \value Recursive In this mode, a thread can lock the same | - | ||||||||||||||||||||||||
126 | QReadWriteLock multiple times. The QReadWriteLock won't be unlocked | - | ||||||||||||||||||||||||
127 | until a corresponding number of unlock() calls have been made. | - | ||||||||||||||||||||||||
128 | - | |||||||||||||||||||||||||
129 | \value NonRecursive In this mode, a thread may only lock a | - | ||||||||||||||||||||||||
130 | QReadWriteLock once. | - | ||||||||||||||||||||||||
131 | - | |||||||||||||||||||||||||
132 | \sa QReadWriteLock() | - | ||||||||||||||||||||||||
133 | */ | - | ||||||||||||||||||||||||
134 | - | |||||||||||||||||||||||||
135 | /*! | - | ||||||||||||||||||||||||
136 | \since 4.4 | - | ||||||||||||||||||||||||
137 | - | |||||||||||||||||||||||||
138 | Constructs a QReadWriteLock object in the given \a recursionMode. | - | ||||||||||||||||||||||||
139 | - | |||||||||||||||||||||||||
140 | The default recursion mode is NonRecursive. | - | ||||||||||||||||||||||||
141 | - | |||||||||||||||||||||||||
142 | \sa lockForRead(), lockForWrite(), RecursionMode | - | ||||||||||||||||||||||||
143 | */ | - | ||||||||||||||||||||||||
144 | QReadWriteLock::QReadWriteLock(RecursionMode recursionMode) | - | ||||||||||||||||||||||||
145 | : dd_ptr(recursionMode == Recursive ? new QReadWriteLockPrivate(recursionMode))true) : nullptr) | - | ||||||||||||||||||||||||
146 | { | - | ||||||||||||||||||||||||
147 | Q_ASSERT_X(!(quintptr(d_ptr.load()) & StateMask), "QReadWriteLock::QReadWriteLock", "bad d_ptr alignment"); | - | ||||||||||||||||||||||||
148 | } executed 42232 times by 296 tests: end of block Executed by:
| 42232 | ||||||||||||||||||||||||
149 | - | |||||||||||||||||||||||||
150 | /*! | - | ||||||||||||||||||||||||
151 | Destroys the QReadWriteLock object. | - | ||||||||||||||||||||||||
152 | - | |||||||||||||||||||||||||
153 | \warning Destroying a read-write lock that is in use may result | - | ||||||||||||||||||||||||
154 | in undefined behavior. | - | ||||||||||||||||||||||||
155 | */ | - | ||||||||||||||||||||||||
156 | QReadWriteLock::~QReadWriteLock() | - | ||||||||||||||||||||||||
157 | { | - | ||||||||||||||||||||||||
158 | auto d = d_ptr.load(); | - | ||||||||||||||||||||||||
159 | if (isUncontendedLocked(d))
| 0-43112 | ||||||||||||||||||||||||
160 | qWarning("QReadWriteLock: destroying locked QReadWriteLock"); | - | ||||||||||||||||||||||||
161 | return; never executed: return; | 0 | ||||||||||||||||||||||||
162 | } | - | ||||||||||||||||||||||||
163 | delete d; | - | ||||||||||||||||||||||||
164 | } executed 43112 times by 519 tests: end of block Executed by:
| 43112 | ||||||||||||||||||||||||
165 | - | |||||||||||||||||||||||||
166 | /*! | - | ||||||||||||||||||||||||
167 | Locks the lock for reading. This function will block the current | - | ||||||||||||||||||||||||
168 | thread if another thread has locked for writing. | - | ||||||||||||||||||||||||
169 | - | |||||||||||||||||||||||||
170 | It is not possible to lock for read if the thread already has | - | ||||||||||||||||||||||||
171 | locked for write. | - | ||||||||||||||||||||||||
172 | - | |||||||||||||||||||||||||
173 | \sa unlock(), lockForWrite(), tryLockForRead() | - | ||||||||||||||||||||||||
174 | */ | - | ||||||||||||||||||||||||
175 | void QReadWriteLock::lockForRead() | - | ||||||||||||||||||||||||
176 | { | - | ||||||||||||||||||||||||
177 | QMutexLocker lockif (&d->mutexd_ptr.testAndSetAcquire(nullptr, dummyLockedForRead))
| 143670-1557572 | ||||||||||||||||||||||||
178 | return; executed 1557572 times by 355 tests: return; Executed by:
| 1557572 | ||||||||||||||||||||||||
179 | tryLockForRead(-1); | - | ||||||||||||||||||||||||
Qt executed 143670 times by 10 tests: }end of block Executed by:
executed 143670 times by 10 tests: end of block Executed by:
| ||||||||||||||||||||||||||
181 | - | |||||||||||||||||||||||||
182 | /*! | - | ||||||||||||||||||||||||
183 | Attempts to lock for reading. If the lock was obtained, this | - | ||||||||||||||||||||||||
184 | function returns \c true, otherwise it returns \c false instead of | - | ||||||||||||||||||||||||
185 | waiting for the lock to become available, i.e. it does not block. | - | ||||||||||||||||||||||||
186 | - | |||||||||||||||||||||||||
187 | The lock attempt will fail if another thread has locked for | - | ||||||||||||||||||||||||
188 | writing. | - | ||||||||||||||||||||||||
189 | - | |||||||||||||||||||||||||
190 | If the lock was obtained, the lock must be unlocked with unlock() | - | ||||||||||||||||||||||||
191 | before another thread can successfully lock it for writing. | - | ||||||||||||||||||||||||
192 | - | |||||||||||||||||||||||||
193 | It is not possible to lock for read if the thread already has | - | ||||||||||||||||||||||||
194 | locked for write. | - | ||||||||||||||||||||||||
195 | - | |||||||||||||||||||||||||
196 | \sa unlock(), lockForRead() | - | ||||||||||||||||||||||||
197 | */ | - | ||||||||||||||||||||||||
198 | bool QReadWriteLock::HANDLE self =tryLockForRead() | - | ||||||||||||||||||||||||
199 | { | - | ||||||||||||||||||||||||
200 | return tryLockForRead( executed 43 times by 2 tests: 0);return tryLockForRead(0); Executed by:
executed 43 times by 2 tests: return tryLockForRead(0); Executed by:
| 43 | ||||||||||||||||||||||||
201 | } | - | ||||||||||||||||||||||||
202 | - | |||||||||||||||||||||||||
203 | /*! \overload | - | ||||||||||||||||||||||||
204 | - | |||||||||||||||||||||||||
205 | Attempts to lock for reading. This function returns \c true if the | - | ||||||||||||||||||||||||
206 | lock was obtained; otherwise it returns \c false. If another thread | - | ||||||||||||||||||||||||
207 | has locked for writing, this function will wait for at most \a | - | ||||||||||||||||||||||||
208 | timeout milliseconds for the lock to become available. | - | ||||||||||||||||||||||||
209 | - | |||||||||||||||||||||||||
210 | Note: Passing a negative number as the \a timeout is equivalent to | - | ||||||||||||||||||||||||
211 | calling lockForRead(), i.e. this function will wait forever until | - | ||||||||||||||||||||||||
212 | lock can be locked for reading when \a timeout is negative. | - | ||||||||||||||||||||||||
213 | - | |||||||||||||||||||||||||
214 | If the lock was obtained, the lock must be unlocked with unlock() | - | ||||||||||||||||||||||||
215 | before another thread can successfully lock it for writing. | - | ||||||||||||||||||||||||
216 | - | |||||||||||||||||||||||||
217 | It is not possible to lock for read if the thread already has | - | ||||||||||||||||||||||||
218 | locked for write. | - | ||||||||||||||||||||||||
219 | - | |||||||||||||||||||||||||
220 | \sa unlock(), lockForRead() | - | ||||||||||||||||||||||||
221 | */ | - | ||||||||||||||||||||||||
222 | bool QReadWriteLock::tryLockForRead(int timeout) | - | ||||||||||||||||||||||||
223 | { | - | ||||||||||||||||||||||||
224 | // Fast case: non contended: | - | ||||||||||||||||||||||||
225 | QReadWriteLockPrivate *d; | - | ||||||||||||||||||||||||
226 | if (d_ptr.testAndSetAcquire(nullptr, dummyLockedForRead, d->recursive))
| 4-143712 | ||||||||||||||||||||||||
227 | return true; executed 4 times by 1 test: return true; Executed by:
| 4 | ||||||||||||||||||||||||
228 | - | |||||||||||||||||||||||||
229 | while (true) { | - | ||||||||||||||||||||||||
230 | self = QThread::currentThreadId();
| 0-143712 | ||||||||||||||||||||||||
QHash<Qt::HANDLE, int>::iterator it =
| ||||||||||||||||||||||||||
231 | if (!d_ptr
| 0 | ||||||||||||||||||||||||
232 | continue; never executed: continue; | 0 | ||||||||||||||||||||||||
233 | return true; never executed: return true; | 0 | ||||||||||||||||||||||||
234 | } | - | ||||||||||||||||||||||||
235 | - | |||||||||||||||||||||||||
236 | if ((quintptr(it !=d->currentReaders.end())) & StateMask) == StateLockedForRead) {
| 11198-132514 | ||||||||||||||||||||||||
237 | ++it.value(); | - | ||||||||||||||||||||||||
++// locked for read, increase the counter | ||||||||||||||||||||||||||
238 | const auto val = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d->accessCount;) + (1U<<4)); | - | ||||||||||||||||||||||||
239 | Q_ASSERT_X(d->accessCountquintptr(val) > 0,(1U<<4), "QReadWriteLock::lockForReadtryLockForRead()", | - | ||||||||||||||||||||||||
240 | "Overflow in lock counter"); | - | ||||||||||||||||||||||||
241 | if (!d_ptr.testAndSetAcquire(d, val, d))
| 0-11198 | ||||||||||||||||||||||||
242 | continue; never executed: continue; | 0 | ||||||||||||||||||||||||
243 | return true; executed 11198 times by 6 tests: return true; Executed by:
| 11198 | ||||||||||||||||||||||||
244 | }} | - | ||||||||||||||||||||||||
245 | - | |||||||||||||||||||||||||
246 | whileif (d->accessCount < 0 ||d ->waitingWriters== dummyLockedForWrite) {
| 42-132472 | ||||||||||||||||||||||||
247 | ++d->waitingReadersif (!timeout)
| 2-40 | ||||||||||||||||||||||||
248 | return false executed 2 times by 1 test: ;return false; Executed by:
executed 2 times by 1 test: return false; Executed by:
| 2 | ||||||||||||||||||||||||
249 | - | |||||||||||||||||||||||||
250 | d// locked for write, assign a d_ptr and wait. | - | ||||||||||||||||||||||||
251 | auto val = QReadWriteLockPrivate::allocate(); | - | ||||||||||||||||||||||||
252 | val->readerWaitwriterCount = 1; | - | ||||||||||||||||||||||||
253 | if (!d_ptr
| 0-40 | ||||||||||||||||||||||||
--
| ||||||||||||||||||||||||||
254 | val->waitingReaderswriterCount = 0; | - | ||||||||||||||||||||||||
255 | val->release(); | - | ||||||||||||||||||||||||
256 | continue; never executed: continue; | 0 | ||||||||||||||||||||||||
257 | } | - | ||||||||||||||||||||||||
258 | d = val; | - | ||||||||||||||||||||||||
259 | } executed 40 times by 3 tests: end of block Executed by:
| 40 | ||||||||||||||||||||||||
260 | Q_ASSERT(!isUncontendedLocked(d)); | - | ||||||||||||||||||||||||
261 | // d is an actual pointer; | - | ||||||||||||||||||||||||
262 | - | |||||||||||||||||||||||||
263 | if (d->recursive)
| 126-132386 | ||||||||||||||||||||||||
264 | return d->currentReaders.insertrecursiveLockForRead(self, 1timeout); executed 126 times by 5 tests: return d->recursiveLockForRead(timeout); Executed by:
| 126 | ||||||||||||||||||||||||
265 | - | |||||||||||||||||||||||||
266 | ++dQMutexLocker lock(&d->accessCount; | - | ||||||||||||||||||||||||
Q_ASSERT_Xmutex); | ||||||||||||||||||||||||||
267 | if
| 0-132386 | ||||||||||||||||||||||||
268 | // d_ptr has changed: this QReadWriteLock was unlocked before we had | - | ||||||||||||||||||||||||
269 | // time to lock d->mutex. | - | ||||||||||||||||||||||||
270 | // We are holding a lock to a mutex within a QReadWriteLockPrivate | - | ||||||||||||||||||||||||
271 | // that is already released (or even is already re-used). That's ok | - | ||||||||||||||||||||||||
272 | // because the QFreeList never frees them. | - | ||||||||||||||||||||||||
273 | // Just unlock d->mutex (at the end of the scope) and retry. | - | ||||||||||||||||||||||||
274 | d = d_ptr.loadAcquire(); | - | ||||||||||||||||||||||||
275 | continue; never executed: continue; | 0 | ||||||||||||||||||||||||
276 | } | - | ||||||||||||||||||||||||
277 | return executed 132386 times by 3 tests: d->accessCount > 0, "QReadWriteLock::lockForRead(timeout);return d->lockForRead(timeout); Executed by:
executed 132386 times by 3 tests: return d->lockForRead(timeout); Executed by:
| 132386 | ||||||||||||||||||||||||
278 | } | - | ||||||||||||||||||||||||
279 | } never executed: end of block | 0 | ||||||||||||||||||||||||
280 | - | |||||||||||||||||||||||||
281 | /*! | - | ||||||||||||||||||||||||
282 | Locks the lock for writing. This function will block the current | - | ||||||||||||||||||||||||
283 | thread if another thread (including the current) has locked for | - | ||||||||||||||||||||||||
284 | reading or writing (unless the lock has been created using the | - | ||||||||||||||||||||||||
285 | \l{QReadWriteLock::Recursive} mode). | - | ||||||||||||||||||||||||
286 | - | |||||||||||||||||||||||||
287 | It is not possible to lock for write if the thread already has | - | ||||||||||||||||||||||||
288 | locked for read. | - | ||||||||||||||||||||||||
289 | - | |||||||||||||||||||||||||
290 | \sa unlock(), lockForRead(), tryLockForWrite() | - | ||||||||||||||||||||||||
291 | */ | - | ||||||||||||||||||||||||
292 | void QReadWriteLock::lockForWrite() | - | ||||||||||||||||||||||||
", "Overflow in lock counter"{ | ||||||||||||||||||||||||||
294 | tryLockForWrite(-1); | - | ||||||||||||||||||||||||
295 | } executed 348346 times by 568 tests: end of block Executed by:
| 348346 | ||||||||||||||||||||||||
296 | - | |||||||||||||||||||||||||
297 | /*! | - | ||||||||||||||||||||||||
298 | Attempts to lock for writing. If the lock was obtained, this | - | ||||||||||||||||||||||||
299 | function returns \c true; otherwise, it returns \c false immediately. | - | ||||||||||||||||||||||||
300 | - | |||||||||||||||||||||||||
301 | The lock attempt will fail if another thread has locked for | - | ||||||||||||||||||||||||
302 | reading or writing. | - | ||||||||||||||||||||||||
303 | - | |||||||||||||||||||||||||
304 | If the lock was obtained, the lock must be unlocked with unlock() | - | ||||||||||||||||||||||||
305 | before another thread can successfully lock it. | - | ||||||||||||||||||||||||
306 | - | |||||||||||||||||||||||||
307 | It is not possible to lock for write if the thread already has | - | ||||||||||||||||||||||||
308 | locked for read. | - | ||||||||||||||||||||||||
309 | - | |||||||||||||||||||||||||
310 | \sa unlock(), lockForWrite() | - | ||||||||||||||||||||||||
311 | */ | - | ||||||||||||||||||||||||
312 | bool QReadWriteLock::tryLockForReadtryLockForWrite() | - | ||||||||||||||||||||||||
313 | { | - | ||||||||||||||||||||||||
314 | QMutexLocker lockreturn tryLockForWrite(&d->mutex0); executed 62 times by 4 tests: return tryLockForWrite(0); Executed by:
| 62 | ||||||||||||||||||||||||
Qt} | ||||||||||||||||||||||||||
316 | - | |||||||||||||||||||||||||
317 | /*! \overload | - | ||||||||||||||||||||||||
318 | - | |||||||||||||||||||||||||
319 | Attempts to lock for writing. This function returns \c true if the | - | ||||||||||||||||||||||||
320 | lock was obtained; otherwise it returns \c false. If another thread | - | ||||||||||||||||||||||||
321 | has locked for reading or writing, this function will wait for at | - | ||||||||||||||||||||||||
322 | most \a timeout milliseconds for the lock to become available. | - | ||||||||||||||||||||||||
323 | - | |||||||||||||||||||||||||
324 | Note: Passing a negative number as the \a timeout is equivalent to | - | ||||||||||||||||||||||||
325 | calling lockForWrite(), i.e. this function will wait forever until | - | ||||||||||||||||||||||||
326 | lock can be locked for writing when \a timeout is negative. | - | ||||||||||||||||||||||||
327 | - | |||||||||||||||||||||||||
328 | If the lock was obtained, the lock must be unlocked with unlock() | - | ||||||||||||||||||||||||
329 | before another thread can successfully lock it. | - | ||||||||||||||||||||||||
330 | - | |||||||||||||||||||||||||
331 | It is not possible to lock for write if the thread already has | - | ||||||||||||||||||||||||
332 | locked for read. | - | ||||||||||||||||||||||||
333 | - | |||||||||||||||||||||||||
334 | \sa unlock(), lockForWrite() | - | ||||||||||||||||||||||||
335 | */ | - | ||||||||||||||||||||||||
336 | bool QReadWriteLock::HANDLE self = 0; | - | ||||||||||||||||||||||||
iftryLockForWrite(d->recursiveint timeout) | ||||||||||||||||||||||||||
337 | { | - | ||||||||||||||||||||||||
338 | self = QThread::currentThreadId(); | - | ||||||||||||||||||||||||
QHash<Qt::HANDLE, int>::iterator it =// Fast case: non contended: | ||||||||||||||||||||||||||
339 | QReadWriteLockPrivate *d->currentReaders; | - | ||||||||||||||||||||||||
340 | if (d_ptr
| 3057-345353 | ||||||||||||||||||||||||
341 | return true; executed 345353 times by 565 tests: return true; Executed by:
| 345353 | ||||||||||||||||||||||||
342 | - | |||||||||||||||||||||||||
343 | while (true) { | - | ||||||||||||||||||||||||
344 | if (it !=d ->currentReaders.end())== 0) {
| 0-3057 | ||||||||||||||||||||||||
345 | ++itif (!d_ptr.value();
| 0 | ||||||||||||||||||||||||
++d->accessCount;
| ||||||||||||||||||||||||||
Q_ASSERT_X
| ||||||||||||||||||||||||||
"Overflow in lock counter");
| ||||||||||||||||||||||||||
346 | continue; never executed: continue; | 0 | ||||||||||||||||||||||||
347 | return true; never executed: return true; | 0 | ||||||||||||||||||||||||
348 | }} | - | ||||||||||||||||||||||||
349 | - | |||||||||||||||||||||||||
350 | if (isUncontendedLocked(d->accessCount < 0)) {
| 88-2969 | ||||||||||||||||||||||||
351 | if (!timeout
| 10-78 | ||||||||||||||||||||||||
352 | return false; executed 10 times by 3 tests: return false; Executed by:
| 10 | ||||||||||||||||||||||||
353 | - | |||||||||||||||||||||||||
354 | // locked for either read or write, assign a d_ptr and wait. | - | ||||||||||||||||||||||||
355 | auto val = QReadWriteLockPrivate::allocate(); | - | ||||||||||||||||||||||||
356 | if (d ->recursive== dummyLockedForWrite)
| 24-54 | ||||||||||||||||||||||||
357 | dval->currentReaders.insert(self,writerCount = 1); executed 54 times by 3 tests: val->writerCount = 1; Executed by:
| 54 | ||||||||||||||||||||||||
++d executed 54 times by 3 tests: ;val->writerCount = 1; Executed by:
executed 54 times by 3 tests: val->writerCount = 1; Executed by:
| ||||||||||||||||||||||||||
358 | else | - | ||||||||||||||||||||||||
359 | val executed 24 times by 3 tests: ->accessCountreaderCount = (quintptr(d) >> 4) + 1;val->readerCount = (quintptr(d) >> 4) + 1; Executed by:
executed 24 times by 3 tests: val->readerCount = (quintptr(d) >> 4) + 1; Executed by:
| 24 | ||||||||||||||||||||||||
360 | Q_ASSERT_Xif (!d_ptr.testAndSetOrdered(d->accessCount > 0, "QReadWriteLock::tryLockForRead()"val, "Overflow in lock counter");
| 0-78 | ||||||||||||||||||||||||
return true;
| ||||||||||||||||||||||||||
}
| ||||||||||||||||||||||||||
bool QReadWriteLock::tryLockForRead(int timeout)
| ||||||||||||||||||||||||||
361 | QMutexLocker lock(&dval->mutex); | - | ||||||||||||||||||||||||
Qt::HANDLE selfwriterCount = val->readerCount = 0; | ||||||||||||||||||||||||||
362 | val->release(); | - | ||||||||||||||||||||||||
363 | continue; never executed: continue; | 0 | ||||||||||||||||||||||||
364 | } | - | ||||||||||||||||||||||||
365 | d = val; | - | ||||||||||||||||||||||||
366 | } executed 78 times by 3 tests: end of block Executed by:
| 78 | ||||||||||||||||||||||||
367 | Q_ASSERT(!isUncontendedLocked(d)); | - | ||||||||||||||||||||||||
368 | // d is an actual pointer; | - | ||||||||||||||||||||||||
369 | - | |||||||||||||||||||||||||
370 | if (d->recursive)
| 76-2971 | ||||||||||||||||||||||||
371 | { executed 76 times by 8 tests: return d->recursiveLockForWrite(timeout); Executed by:
| 76 | ||||||||||||||||||||||||
self = QThread::currentThreadId(); executed 76 times by 8 tests: return d->recursiveLockForWrite(timeout); Executed by:
| ||||||||||||||||||||||||||
QHash<Qt::HANDLE, int>::iterator it = executed 76 times by 8 tests: return d->currentReaders.findrecursiveLockForWrite(selftimeout);return d->recursiveLockForWrite(timeout); Executed by:
executed 76 times by 8 tests: return d->recursiveLockForWrite(timeout); Executed by:
| ||||||||||||||||||||||||||
372 | - | |||||||||||||||||||||||||
373 | QMutexLocker lock(&d->mutex); | - | ||||||||||||||||||||||||
374 | if (it !=d ->currentReaders!= d_ptr.endload()) {
| 0-2971 | ||||||||||||||||||||||||
375 | ++it// The mutex was unlocked before we had time to lock the mutex. | - | ||||||||||||||||||||||||
376 | // We are holding to a mutex within a QReadWriteLockPrivate that is already released | - | ||||||||||||||||||||||||
377 | // (or even is already re-used) but that's ok because the QFreeList never frees them. | - | ||||||||||||||||||||||||
378 | d = d_ptr.valueloadAcquire(); | - | ||||||||||||||||||||||||
379 | ++continue; never executed: continue; | 0 | ||||||||||||||||||||||||
380 | } | - | ||||||||||||||||||||||||
381 | return executed 2971 times by 3 tests: d->accessCount;lockForWrite(timeout);return d->lockForWrite(timeout); Executed by:
executed 2971 times by 3 tests: return d->lockForWrite(timeout); Executed by:
| 2971 | ||||||||||||||||||||||||
382 | } | - | ||||||||||||||||||||||||
383 | } never executed: end of block | 0 | ||||||||||||||||||||||||
384 | - | |||||||||||||||||||||||||
385 | /*! | - | ||||||||||||||||||||||||
386 | Unlocks the lock. | - | ||||||||||||||||||||||||
387 | - | |||||||||||||||||||||||||
388 | Attempting to unlock a lock that is not locked is an error, and will result | - | ||||||||||||||||||||||||
389 | in program termination. | - | ||||||||||||||||||||||||
390 | - | |||||||||||||||||||||||||
391 | \sa lockForRead(), lockForWrite(), tryLockForRead(), tryLockForWrite() | - | ||||||||||||||||||||||||
392 | */ | - | ||||||||||||||||||||||||
393 | void QReadWriteLock::unlock() | - | ||||||||||||||||||||||||
394 | { | - | ||||||||||||||||||||||||
395 | QReadWriteLockPrivate *d = d_ptr.load(); | - | ||||||||||||||||||||||||
396 | while (true) { | - | ||||||||||||||||||||||||
397 | Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForReadunlock()", | - | ||||||||||||||||||||||||
"Overflow in"Cannot lockunlock counter"an unlocked lock"); | ||||||||||||||||||||||||||
398 | - | |||||||||||||||||||||||||
399 | // Fast case: no contention: (no waiters, no other readers) | - | ||||||||||||||||||||||||
400 |
| 146830-1902811 | ||||||||||||||||||||||||
401 |
| 1-1902810 | ||||||||||||||||||||||||
402 | continue; executed 1 time by 1 test: continue; Executed by:
| 1 | ||||||||||||||||||||||||
403 | returntrue; executed 1902810 times by 572 tests: return; Executed by:
| 1902810 | ||||||||||||||||||||||||
404 | }} | - | ||||||||||||||||||||||||
405 | - | |||||||||||||||||||||||||
406 | whileif ((quintptr(d->accessCount < 0 ||d->waitingWriters) & StateMask) == StateLockedForRead) {
| 11197-135633 | ||||||||||||||||||||||||
407 | ++Q_ASSERT(quintptr(d->waitingReaders; | - | ||||||||||||||||||||||||
bool success) > (1U<<4)); //otherwise that would be the fast case | ||||||||||||||||||||||||||
408 | // Just decrease the reader's count. | - | ||||||||||||||||||||||||
409 | auto val = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d->readerWait) - (1U<<4)); | - | ||||||||||||||||||||||||
410 | if (!d_ptr
| 0-11197 | ||||||||||||||||||||||||
--
| ||||||||||||||||||||||||||
411 | continue never executed: ;continue; never executed: continue; | 0 | ||||||||||||||||||||||||
412 | if (!success)returnfalse; executed 11197 times by 6 tests: return; Executed by:
| 11197 | ||||||||||||||||||||||||
413 | } | - | ||||||||||||||||||||||||
414 | - | |||||||||||||||||||||||||
415 | Q_ASSERT(!isUncontendedLocked(d)); | - | ||||||||||||||||||||||||
416 | - | |||||||||||||||||||||||||
417 | if (d->recursive) d->currentReaders.insert(self, 1);
| 159-135474 | ||||||||||||||||||||||||
++d->accessCount;
| ||||||||||||||||||||||||||
Q_ASSERT_X(
| ||||||||||||||||||||||||||
418 | d->accessCount > 0, "QReadWriteLock::tryLockForRead()", "Overflow in lock counter");recursiveUnlock(); | - | ||||||||||||||||||||||||
419 | returntrue; executed 159 times by 8 tests: return; Executed by:
| 159 | ||||||||||||||||||||||||
420 | } | - | ||||||||||||||||||||||||
421 | - | |||||||||||||||||||||||||
422 | void QReadWriteLock::lockForWrite() | - | ||||||||||||||||||||||||
{QMutexLocker locklocker(&d->mutex); | ||||||||||||||||||||||||||
423 | Qt::HANDLE self = 0;if (d->recursivewriterCount) {
| 3064-132410 | ||||||||||||||||||||||||
424 | self = QThread::currentThreadId(); | - | ||||||||||||||||||||||||
ifQ_ASSERT(d->currentWriterwriterCount == self) { | ||||||||||||||||||||||||||
--1); | ||||||||||||||||||||||||||
425 | Q_ASSERT(d->accessCountreaderCount == 0); | - | ||||||||||||||||||||||||
426 | d->writerCount = 0; | - | ||||||||||||||||||||||||
427 | Q_ASSERT_X} else { executed 3064 times by 3 tests: end of block Executed by:
| 3064 | ||||||||||||||||||||||||
428 | Q_ASSERT(d->accessCount <readerCount > 0, "QReadWriteLock::lockForWrite()", | - | ||||||||||||||||||||||||
"Overflow in lock counter"); | ||||||||||||||||||||||||||
429 | d->readerCount--; | - | ||||||||||||||||||||||||
430 | if (d->readerCount > 0)
| 265-132145 | ||||||||||||||||||||||||
431 | return; executed 132145 times by 1 test: return; Executed by:
| 132145 | ||||||||||||||||||||||||
432 | }} executed 265 times by 3 tests: end of block Executed by:
| 265 | ||||||||||||||||||||||||
433 | - | |||||||||||||||||||||||||
434 | whileif (d->accessCount != 0) {
| 118-3002 | ||||||||||||||||||||||||
++
| ||||||||||||||||||||||||||
435 | d->writerWaitunlock(); | - | ||||||||||||||||||||||||
436 | } else { executed 3211 times by 3 tests: end of block Executed by:
| 3211 | ||||||||||||||||||||||||
437 | Q_ASSERT(d_ptr.waitload() == d); // should not change when we still hold the mutex | - | ||||||||||||||||||||||||
438 | d_ptr.storeRelease(&d->mutexnullptr); | - | ||||||||||||||||||||||||
439 | --d->waitingWritersrelease(); | - | ||||||||||||||||||||||||
440 | } executed 118 times by 3 tests: end of block Executed by:
| 118 | ||||||||||||||||||||||||
441 | return executed 3329 times by 3 tests: ;return; Executed by:
executed 3329 times by 3 tests: return; Executed by:
| 3329 | ||||||||||||||||||||||||
442 | } | - | ||||||||||||||||||||||||
if never executed: }end of block never executed: end of block | ||||||||||||||||||||||||||
444 | - | |||||||||||||||||||||||||
445 | /*! \internal Helper for QWaitCondition::wait */ | - | ||||||||||||||||||||||||
446 | QReadWriteLock::StateForWaitCondition QReadWriteLock::stateForWaitCondition() const | - | ||||||||||||||||||||||||
447 | { | - | ||||||||||||||||||||||||
448 | QReadWriteLockPrivate *d = d_ptr.load(); | - | ||||||||||||||||||||||||
449 | switch (quintptr(d->recursive) & StateMask) { | - | ||||||||||||||||||||||||
450 | case StateLockedForRead: return LockedForRead; executed 25 times by 1 test: return LockedForRead; Executed by:
executed 25 times by 1 test: case StateLockedForRead: Executed by:
| 25 | ||||||||||||||||||||||||
451 | case StateLockedForWrite: return LockedForWrite; executed 108 times by 1 test: return LockedForWrite; Executed by:
executed 108 times by 1 test: case StateLockedForWrite: Executed by:
| 108 | ||||||||||||||||||||||||
452 | } | - | ||||||||||||||||||||||||
453 | - | |||||||||||||||||||||||||
454 | if (!
| 0-141 | ||||||||||||||||||||||||
455 | return Unlocked never executed: ;return Unlocked; never executed: return Unlocked; | 0 | ||||||||||||||||||||||||
456 | --if (d->accessCountwriterCount > 1)
| 0-141 | ||||||||||||||||||||||||
457 | return RecursivelyLocked never executed: ;return RecursivelyLocked; never executed: return RecursivelyLocked; | 0 | ||||||||||||||||||||||||
458 | Q_ASSERT_Xelse if (d->accessCount < 0, "QReadWriteLock::lockForWrite()", "Overflow in lock counter");writerCount == 1)
| 18-123 | ||||||||||||||||||||||||
459 | return LockedForWrite; executed 123 times by 1 test: return LockedForWrite; Executed by:
| 123 | ||||||||||||||||||||||||
460 | return LockedForRead; executed 18 times by 1 test: return LockedForRead; Executed by:
| 18 | ||||||||||||||||||||||||
461 | - | |||||||||||||||||||||||||
462 | } | - | ||||||||||||||||||||||||
463 | - | |||||||||||||||||||||||||
464 | bool QReadWriteLockQReadWriteLockPrivate::tryLockForWrite() | - | ||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||
QMutexLocker locklockForRead(&d->int timeout) | ||||||||||||||||||||||||||
465 | { | - | ||||||||||||||||||||||||
466 | Q_ASSERT(!mutex); | - | ||||||||||||||||||||||||
Qt::HANDLE self =.tryLock()); // mutex must be locked when entering this function | ||||||||||||||||||||||||||
467 | - | |||||||||||||||||||||||||
468 | QElapsedTimer t; | - | ||||||||||||||||||||||||
469 | if (timeout > 0)
| 1-132492 | ||||||||||||||||||||||||
470 | t.start(); executed 1 time by 1 test: t.start(); Executed by:
| 1 | ||||||||||||||||||||||||
471 | - | |||||||||||||||||||||||||
472 | while (waitingWriters || writerCount) {
| 72-132543 | ||||||||||||||||||||||||
473 | if (timeout ==
| 21-437 | ||||||||||||||||||||||||
474 | return false executed 21 times by 2 tests: ;return false; Executed by:
executed 21 times by 2 tests: return false; Executed by:
| 21 | ||||||||||||||||||||||||
475 | if (d->recursivetimeout > 0) {
| 8-429 | ||||||||||||||||||||||||
476 | selfauto elapsed = QThread::currentThreadIdt.elapsed(); | - | ||||||||||||||||||||||||
477 | if (d->currentWriter == selfelapsed > timeout)
| 1-7 | ||||||||||||||||||||||||
478 | { executed 1 time by 1 test: return false; Executed by:
| 1 | ||||||||||||||||||||||||
--d->accessCount executed 1 time by 1 test: return false;return false; Executed by:
executed 1 time by 1 test: return false; Executed by:
| ||||||||||||||||||||||||||
479 | Q_ASSERT_XwaitingReaders++; | - | ||||||||||||||||||||||||
480 | readerCond.wait(d->accessCount < 0, "QReadWriteLock::lockForWrite()"&mutex, | - | ||||||||||||||||||||||||
"Overflow in lock counter"timeout - elapsed); | ||||||||||||||||||||||||||
481 | } else { executed 7 times by 1 test: end of block Executed by:
| 7 | ||||||||||||||||||||||||
482 | waitingReaders++; | - | ||||||||||||||||||||||||
483 | readerCond.wait(&mutex); | - | ||||||||||||||||||||||||
484 | } executed 429 times by 3 tests: end of block Executed by:
| 429 | ||||||||||||||||||||||||
485 | waitingReaders--; | - | ||||||||||||||||||||||||
486 | } executed 436 times by 3 tests: end of block Executed by:
| 436 | ||||||||||||||||||||||||
487 | readerCount++; | - | ||||||||||||||||||||||||
488 | Q_ASSERT(writerCount == 0); | - | ||||||||||||||||||||||||
489 | return true; executed 132471 times by 6 tests: return true; Executed by:
| 132471 | ||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||
491 | - | |||||||||||||||||||||||||
492 | bool QReadWriteLockPrivate::lockForWrite(int timeout) | - | ||||||||||||||||||||||||
493 | { | - | ||||||||||||||||||||||||
494 | Q_ASSERT(!mutex.tryLock()); // mutex must be locked when entering this function | - | ||||||||||||||||||||||||
495 | - | |||||||||||||||||||||||||
496 | QElapsedTimer t; | - | ||||||||||||||||||||||||
497 | if (d->accessCount !=timeout > 0)
| 1-3034 | ||||||||||||||||||||||||
498 | t.start(); executed 1 time by 1 test: t.start(); Executed by:
| 1 | ||||||||||||||||||||||||
499 | - | |||||||||||||||||||||||||
500 | while (readerCount || writerCount) {
| 74-3276 | ||||||||||||||||||||||||
501 | if (timeout ==
| 22-316 | ||||||||||||||||||||||||
502 | return false; executed 22 times by 2 tests: return false; Executed by:
| 22 | ||||||||||||||||||||||||
503 | if (d->recursivetimeout > 0) d->currentWriter{
| 8-308 | ||||||||||||||||||||||||
504 | auto elapsed = self; | - | ||||||||||||||||||||||||
--d->accessCountt.elapsed(); | ||||||||||||||||||||||||||
505 | if (elapsed > timeout) {
| 1-7 | ||||||||||||||||||||||||
506 | if (waitingReaders && !waitingWriters && !writerCount) {
| 0-1 | ||||||||||||||||||||||||
507 | // We timed out and now there is no more writers or waiting writers, but some | - | ||||||||||||||||||||||||
508 | // readers were queueud (probably because of us). Wake the waiting readers. | - | ||||||||||||||||||||||||
509 | readerCond.wakeAll(); | - | ||||||||||||||||||||||||
510 | } never executed: end of block | 0 | ||||||||||||||||||||||||
511 | return false executed 1 time by 1 test: ;return false; Executed by:
executed 1 time by 1 test: return false; Executed by:
| 1 | ||||||||||||||||||||||||
512 | Q_ASSERT_X} | - | ||||||||||||||||||||||||
513 | waitingWriters++; | - | ||||||||||||||||||||||||
514 | writerCond.wait(d->accessCount < 0, "QReadWriteLock::tryLockForWrite()"&mutex, | - | ||||||||||||||||||||||||
"Overflow in lock counter"timeout - elapsed); | ||||||||||||||||||||||||||
515 | } else { executed 7 times by 1 test: end of block Executed by:
| 7 | ||||||||||||||||||||||||
516 | waitingWriters++; | - | ||||||||||||||||||||||||
517 | writerCond.wait(&mutex); | - | ||||||||||||||||||||||||
518 | } executed 308 times by 3 tests: end of block Executed by:
| 308 | ||||||||||||||||||||||||
519 | waitingWriters--; | - | ||||||||||||||||||||||||
520 | } executed 315 times by 3 tests: end of block Executed by:
| 315 | ||||||||||||||||||||||||
521 | - | |||||||||||||||||||||||||
522 | Q_ASSERT(writerCount == 0); | - | ||||||||||||||||||||||||
523 | Q_ASSERT(readerCount == 0); | - | ||||||||||||||||||||||||
524 | writerCount = 1; | - | ||||||||||||||||||||||||
525 | return true; executed 3012 times by 9 tests: return true; Executed by:
| 3012 | ||||||||||||||||||||||||
526 | } | - | ||||||||||||||||||||||||
527 | - | |||||||||||||||||||||||||
528 | void QReadWriteLockPrivate::unlock() | - | ||||||||||||||||||||||||
529 | { | - | ||||||||||||||||||||||||
530 | Q_ASSERT(!mutex.tryLock()); // mutex must be locked when entering this function | - | ||||||||||||||||||||||||
531 |
| 417-2922 | ||||||||||||||||||||||||
532 | writerCond.wakeOne(); executed 2922 times by 3 tests: writerCond.wakeOne(); Executed by:
| 2922 | ||||||||||||||||||||||||
533 | else if (waitingReaders)
| 127-290 | ||||||||||||||||||||||||
534 | readerCond.wakeAll(); executed 290 times by 3 tests: readerCond.wakeAll(); Executed by:
| 290 | ||||||||||||||||||||||||
535 | } executed 3339 times by 9 tests: end of block Executed by:
| 3339 | ||||||||||||||||||||||||
536 | - | |||||||||||||||||||||||||
537 | bool QReadWriteLockQReadWriteLockPrivate::tryLockForWriterecursiveLockForRead(int timeout) | - | ||||||||||||||||||||||||
538 | { | - | ||||||||||||||||||||||||
539 | Q_ASSERT(recursive); | - | ||||||||||||||||||||||||
540 | QMutexLocker lock(&d->mutex&mutex); | - | ||||||||||||||||||||||||
541 | - | |||||||||||||||||||||||||
542 | Qt::HANDLE self = 0; | - | ||||||||||||||||||||||||
if (d->recursive) {self = QThread::currentThreadId(); | ||||||||||||||||||||||||||
543 | - | |||||||||||||||||||||||||
544 | ifauto it = currentReaders.find(d->currentWriter ==self)); | - | ||||||||||||||||||||||||
545 | if (it != currentReaders.end())
| 19-107 | ||||||||||||||||||||||||
546 | --d->accessCount++it.value(); | - | ||||||||||||||||||||||||
547 | return true executed 19 times by 4 tests: ;return true; Executed by:
executed 19 times by 4 tests: return true; Executed by:
| 19 | ||||||||||||||||||||||||
548 | Q_ASSERT_X} | - | ||||||||||||||||||||||||
549 | - | |||||||||||||||||||||||||
550 | if (!lockForRead
| 21-86 | ||||||||||||||||||||||||
551 | return false; executed 21 times by 2 tests: return false; Executed by:
| 21 | ||||||||||||||||||||||||
552 | - | |||||||||||||||||||||||||
553 | currentReaders.insert(self, | - | ||||||||||||||||||||||||
"Overflow in lock counter"1); | ||||||||||||||||||||||||||
554 | return true; executed 86 times by 5 tests: return true; Executed by:
| 86 | ||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||
556 | - | |||||||||||||||||||||||||
whilebool QReadWriteLockPrivate::recursiveLockForWrite(d->accessCount != 0int timeout) | ||||||||||||||||||||||||||
558 | { | - | ||||||||||||||||||||||||
559 | ++d->waitingWriters; | - | ||||||||||||||||||||||||
bool success = d->writerWait.waitQ_ASSERT(&d->mutex, timeout < 0 ? ULONG_MAX : ulongrecursive); | ||||||||||||||||||||||||||
560 | QMutexLocker lock(timeout)); | - | ||||||||||||||||||||||||
--d->waitingWriters;&mutex); | ||||||||||||||||||||||||||
561 | - | |||||||||||||||||||||||||
562 | Qt::HANDLE self = QThread::currentThreadId(); | - | ||||||||||||||||||||||||
563 | if (!success(currentWriter == self) {
| 12-64 | ||||||||||||||||||||||||
564 | writerCount++; | - | ||||||||||||||||||||||||
565 | return falsetrue; executed 12 times by 2 tests: return true; Executed by:
| 12 | ||||||||||||||||||||||||
566 | } | - | ||||||||||||||||||||||||
567 | - | |||||||||||||||||||||||||
568 | if (!lockForWrite(d->recursive)
| 22-42 | ||||||||||||||||||||||||
d->
| ||||||||||||||||||||||||||
569 | return false; executed 22 times by 2 tests: return false; Executed by:
| 22 | ||||||||||||||||||||||||
570 | - | |||||||||||||||||||||||||
571 | currentWriter = self; | - | ||||||||||||||||||||||||
--d->accessCount; | ||||||||||||||||||||||||||
572 | Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::tryLockForWrite()", executed 42 times by 8 tests: return true; Executed by:
| 42 | ||||||||||||||||||||||||
"Overflow in lock counter"); executed 42 times by 8 tests: return true;return true; Executed by:
executed 42 times by 8 tests: return true; Executed by:
| ||||||||||||||||||||||||||
573 | } | - | ||||||||||||||||||||||||
574 | - | |||||||||||||||||||||||||
575 | void QReadWriteLockQReadWriteLockPrivate::unlockrecursiveUnlock() | - | ||||||||||||||||||||||||
576 | { | - | ||||||||||||||||||||||||
577 | QMutexLocker lockQ_ASSERT(&d->mutexrecursive); | - | ||||||||||||||||||||||||
578 | Q_ASSERT_XQMutexLocker lock(d->accessCount != 0, "QReadWriteLock::unlock()", "Cannot unlock an unlocked lock"&mutex); | - | ||||||||||||||||||||||||
579 | - | |||||||||||||||||||||||||
580 | bool unlocked = false; | - | ||||||||||||||||||||||||
if (d->accessCount > 0) { | ||||||||||||||||||||||||||
if (d->recursive) {Qt::HANDLE self = QThread::currentThreadId(); | ||||||||||||||||||||||||||
581 | QHash<Qt::HANDLE, int>::iteratorif (self == currentWriter) {
| 54-105 | ||||||||||||||||||||||||
582 | if (--writerCount > 0)
| 12-42 | ||||||||||||||||||||||||
583 | return; executed 12 times by 2 tests: return; Executed by:
| 12 | ||||||||||||||||||||||||
584 | currentWriter = 0; | - | ||||||||||||||||||||||||
585 | } else { executed 42 times by 8 tests: end of block Executed by:
| 42 | ||||||||||||||||||||||||
586 | auto it = d->currentReaders.find(self); | - | ||||||||||||||||||||||||
587 | if (it != d->== currentReaders.end()) {
| 0-105 | ||||||||||||||||||||||||
588 | qWarning("QReadWriteLock::unlock: unlocking from a thread that did not lock"); | - | ||||||||||||||||||||||||
589 | return; never executed: return; | 0 | ||||||||||||||||||||||||
590 | } else { | - | ||||||||||||||||||||||||
591 | if (--it.value() <= 0) d->{
| 19-86 | ||||||||||||||||||||||||
592 | currentReaders.erase(it); | - | ||||||||||||||||||||||||
593 | readerCount--; | - | ||||||||||||||||||||||||
594 | } executed 86 times by 5 tests: end of block Executed by:
| 86 | ||||||||||||||||||||||||
595 | if (readerCount)
| 19-86 | ||||||||||||||||||||||||
596 | return; executed 19 times by 4 tests: return; Executed by:
| 19 | ||||||||||||||||||||||||
597 | } executed 86 times by 5 tests: end of block Executed by:
| 86 | ||||||||||||||||||||||||
598 | unlocked} | - | ||||||||||||||||||||||||
599 | - | |||||||||||||||||||||||||
600 | unlock(); | - | ||||||||||||||||||||||||
601 | } executed 128 times by 8 tests: end of block Executed by:
| 128 | ||||||||||||||||||||||||
602 | - | |||||||||||||||||||||||||
603 | // The freelist management | - | ||||||||||||||||||||||||
604 | namespace { | - | ||||||||||||||||||||||||
605 | struct FreeListConstants : QFreeListDefaultConstants { | - | ||||||||||||||||||||||||
606 | enum { BlockCount = --d->accessCount == 04, MaxIndex=0xffff }; | - | ||||||||||||||||||||||||
607 | static const int Sizes[BlockCount]; | - | ||||||||||||||||||||||||
608 | }; | - | ||||||||||||||||||||||||
609 | const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = { | - | ||||||||||||||||||||||||
610 | 16, | - | ||||||||||||||||||||||||
611 | 128, | - | ||||||||||||||||||||||||
612 | 1024, | - | ||||||||||||||||||||||||
613 | FreeListConstants::MaxIndex - (16 + 128 + 1024) | - | ||||||||||||||||||||||||
614 | }; | - | ||||||||||||||||||||||||
615 | - | |||||||||||||||||||||||||
616 | typedef QFreeList<QReadWriteLockPrivate, FreeListConstants> FreeList; | - | ||||||||||||||||||||||||
} else if executed 3 times by 3 tests: end of block Executed by:
executed 3 times by 3 tests: guard.store(QtGlobalStatic::Destroyed); Executed by:
executed 354 times by 3 tests: return &holder.value; Executed by:
executed 3 times by 3 tests: end of block Executed by:
executed 3 times by 3 tests: guard.store(QtGlobalStatic::Destroyed); Executed by:
executed 354 times by 3 tests: return &holder.value; Executed by:
| ||||||||||||||||||||||||||
618 | } | - | ||||||||||||||||||||||||
619 | - | |||||||||||||||||||||||||
620 | QReadWriteLockPrivate *QReadWriteLockPrivate::allocate() | - | ||||||||||||||||||||||||
621 | { | - | ||||||||||||||||||||||||
622 | int i = freelist->accessCount < 0 && ++next(); | - | ||||||||||||||||||||||||
623 | QReadWriteLockPrivate *d ->accessCount == 0) { | - | ||||||||||||||||||||||||
unlocked= true;&(*freelist)[i]; | ||||||||||||||||||||||||||
624 | d->currentWriterid = 0i; | - | ||||||||||||||||||||||||
625 | } | - | ||||||||||||||||||||||||
if (unlocked) { | ||||||||||||||||||||||||||
if (Q_ASSERT(!d->waitingWriters) {recursive); | ||||||||||||||||||||||||||
626 | Q_ASSERT(!d->writerWait.wakeOne(); | - | ||||||||||||||||||||||||
} else if (waitingReaders && !d->waitingReaders ) {&& !d->readerWait.wakeAll(); | ||||||||||||||||||||||||||
}readerCount && !d->writerCount); | ||||||||||||||||||||||||||
627 | return d; executed 118 times by 3 tests: return d; Executed by:
| 118 | ||||||||||||||||||||||||
628 | } | - | ||||||||||||||||||||||||
629 | - | |||||||||||||||||||||||||
630 | void QReadWriteLockPrivate::release() | - | ||||||||||||||||||||||||
631 | { | - | ||||||||||||||||||||||||
632 | Q_ASSERT(!recursive); | - | ||||||||||||||||||||||||
633 | Q_ASSERT(!waitingReaders && !waitingReaders && !readerCount && !writerCount); | - | ||||||||||||||||||||||||
634 | freelist->release(id); | - | ||||||||||||||||||||||||
635 | } executed 118 times by 3 tests: end of block Executed by:
| 118 | ||||||||||||||||||||||||
636 | - | |||||||||||||||||||||||||
637 | /*! | - | ||||||||||||||||||||||||
638 | \class QReadLocker | - | ||||||||||||||||||||||||
639 | \inmodule QtCore | - | ||||||||||||||||||||||||
640 | \brief The QReadLocker class is a convenience class that | - | ||||||||||||||||||||||||
641 | simplifies locking and unlocking read-write locks for read access. | - | ||||||||||||||||||||||||
642 | - | |||||||||||||||||||||||||
643 | \threadsafe | - | ||||||||||||||||||||||||
644 | - | |||||||||||||||||||||||||
645 | \ingroup thread | - | ||||||||||||||||||||||||
646 | - | |||||||||||||||||||||||||
647 | The purpose of QReadLocker (and QWriteLocker) is to simplify | - | ||||||||||||||||||||||||
648 | QReadWriteLock locking and unlocking. Locking and unlocking | - | ||||||||||||||||||||||||
649 | statements or in exception handling code is error-prone and | - | ||||||||||||||||||||||||
650 | difficult to debug. QReadLocker can be used in such situations | - | ||||||||||||||||||||||||
651 | to ensure that the state of the lock is always well-defined. | - | ||||||||||||||||||||||||
652 | - | |||||||||||||||||||||||||
653 | Here's an example that uses QReadLocker to lock and unlock a | - | ||||||||||||||||||||||||
654 | read-write lock for reading: | - | ||||||||||||||||||||||||
655 | - | |||||||||||||||||||||||||
656 | \snippet code/src_corelib_thread_qreadwritelock.cpp 1 | - | ||||||||||||||||||||||||
657 | - | |||||||||||||||||||||||||
658 | It is equivalent to the following code: | - | ||||||||||||||||||||||||
659 | - | |||||||||||||||||||||||||
660 | \snippet code/src_corelib_thread_qreadwritelock.cpp 2 | - | ||||||||||||||||||||||||
661 | - | |||||||||||||||||||||||||
662 | The QMutexLocker documentation shows examples where the use of a | - | ||||||||||||||||||||||||
663 | locker object greatly simplifies programming. | - | ||||||||||||||||||||||||
664 | - | |||||||||||||||||||||||||
665 | \sa QWriteLocker, QReadWriteLock | - | ||||||||||||||||||||||||
666 | */ | - | ||||||||||||||||||||||||
667 | - | |||||||||||||||||||||||||
668 | /*! | - | ||||||||||||||||||||||||
669 | \fn QReadLocker::QReadLocker(QReadWriteLock *lock) | - | ||||||||||||||||||||||||
670 | - | |||||||||||||||||||||||||
671 | Constructs a QReadLocker and locks \a lock for reading. The lock | - | ||||||||||||||||||||||||
672 | will be unlocked when the QReadLocker is destroyed. If \c lock is | - | ||||||||||||||||||||||||
673 | zero, QReadLocker does nothing. | - | ||||||||||||||||||||||||
674 | - | |||||||||||||||||||||||||
675 | \sa QReadWriteLock::lockForRead() | - | ||||||||||||||||||||||||
676 | */ | - | ||||||||||||||||||||||||
677 | - | |||||||||||||||||||||||||
678 | /*! | - | ||||||||||||||||||||||||
679 | \fn QReadLocker::~QReadLocker() | - | ||||||||||||||||||||||||
680 | - | |||||||||||||||||||||||||
681 | Destroys the QReadLocker and unlocks the lock that was passed to | - | ||||||||||||||||||||||||
682 | the constructor. | - | ||||||||||||||||||||||||
683 | - | |||||||||||||||||||||||||
684 | \sa QReadWriteLock::unlock() | - | ||||||||||||||||||||||||
685 | */ | - | ||||||||||||||||||||||||
686 | - | |||||||||||||||||||||||||
687 | /*! | - | ||||||||||||||||||||||||
688 | \fn void QReadLocker::unlock() | - | ||||||||||||||||||||||||
689 | - | |||||||||||||||||||||||||
690 | Unlocks the lock associated with this locker. | - | ||||||||||||||||||||||||
691 | - | |||||||||||||||||||||||||
692 | \sa QReadWriteLock::unlock() | - | ||||||||||||||||||||||||
693 | */ | - | ||||||||||||||||||||||||
694 | - | |||||||||||||||||||||||||
695 | /*! | - | ||||||||||||||||||||||||
696 | \fn void QReadLocker::relock() | - | ||||||||||||||||||||||||
697 | - | |||||||||||||||||||||||||
698 | Relocks an unlocked lock. | - | ||||||||||||||||||||||||
699 | - | |||||||||||||||||||||||||
700 | \sa unlock() | - | ||||||||||||||||||||||||
701 | */ | - | ||||||||||||||||||||||||
702 | - | |||||||||||||||||||||||||
703 | /*! | - | ||||||||||||||||||||||||
704 | \fn QReadWriteLock *QReadLocker::readWriteLock() const | - | ||||||||||||||||||||||||
705 | - | |||||||||||||||||||||||||
706 | Returns a pointer to the read-write lock that was passed | - | ||||||||||||||||||||||||
707 | to the constructor. | - | ||||||||||||||||||||||||
708 | */ | - | ||||||||||||||||||||||||
709 | - | |||||||||||||||||||||||||
710 | /*! | - | ||||||||||||||||||||||||
711 | \class QWriteLocker | - | ||||||||||||||||||||||||
712 | \inmodule QtCore | - | ||||||||||||||||||||||||
713 | \brief The QWriteLocker class is a convenience class that | - | ||||||||||||||||||||||||
714 | simplifies locking and unlocking read-write locks for write access. | - | ||||||||||||||||||||||||
715 | - | |||||||||||||||||||||||||
716 | \threadsafe | - | ||||||||||||||||||||||||
717 | - | |||||||||||||||||||||||||
718 | \ingroup thread | - | ||||||||||||||||||||||||
719 | - | |||||||||||||||||||||||||
720 | The purpose of QWriteLocker (and QReadLocker) is to simplify | - | ||||||||||||||||||||||||
721 | QReadWriteLock locking and unlocking. Locking and unlocking | - | ||||||||||||||||||||||||
722 | statements or in exception handling code is error-prone and | - | ||||||||||||||||||||||||
723 | difficult to debug. QWriteLocker can be used in such situations | - | ||||||||||||||||||||||||
724 | to ensure that the state of the lock is always well-defined. | - | ||||||||||||||||||||||||
725 | - | |||||||||||||||||||||||||
726 | Here's an example that uses QWriteLocker to lock and unlock a | - | ||||||||||||||||||||||||
727 | read-write lock for writing: | - | ||||||||||||||||||||||||
728 | - | |||||||||||||||||||||||||
729 | \snippet code/src_corelib_thread_qreadwritelock.cpp 3 | - | ||||||||||||||||||||||||
730 | - | |||||||||||||||||||||||||
731 | It is equivalent to the following code: | - | ||||||||||||||||||||||||
732 | - | |||||||||||||||||||||||||
733 | \snippet code/src_corelib_thread_qreadwritelock.cpp 4 | - | ||||||||||||||||||||||||
734 | - | |||||||||||||||||||||||||
735 | The QMutexLocker documentation shows examples where the use of a | - | ||||||||||||||||||||||||
736 | locker object greatly simplifies programming. | - | ||||||||||||||||||||||||
737 | - | |||||||||||||||||||||||||
738 | \sa QReadLocker, QReadWriteLock | - | ||||||||||||||||||||||||
739 | */ | - | ||||||||||||||||||||||||
740 | - | |||||||||||||||||||||||||
741 | /*! | - | ||||||||||||||||||||||||
742 | \fn QWriteLocker::QWriteLocker(QReadWriteLock *lock) | - | ||||||||||||||||||||||||
743 | - | |||||||||||||||||||||||||
744 | Constructs a QWriteLocker and locks \a lock for writing. The lock | - | ||||||||||||||||||||||||
745 | will be unlocked when the QWriteLocker is destroyed. If \c lock is | - | ||||||||||||||||||||||||
746 | zero, QWriteLocker does nothing. | - | ||||||||||||||||||||||||
747 | - | |||||||||||||||||||||||||
748 | \sa QReadWriteLock::lockForWrite() | - | ||||||||||||||||||||||||
749 | */ | - | ||||||||||||||||||||||||
750 | - | |||||||||||||||||||||||||
751 | /*! | - | ||||||||||||||||||||||||
752 | \fn QWriteLocker::~QWriteLocker() | - | ||||||||||||||||||||||||
753 | - | |||||||||||||||||||||||||
754 | Destroys the QWriteLocker and unlocks the lock that was passed to | - | ||||||||||||||||||||||||
755 | the constructor. | - | ||||||||||||||||||||||||
756 | - | |||||||||||||||||||||||||
757 | \sa QReadWriteLock::unlock() | - | ||||||||||||||||||||||||
758 | */ | - | ||||||||||||||||||||||||
759 | - | |||||||||||||||||||||||||
760 | /*! | - | ||||||||||||||||||||||||
761 | \fn void QWriteLocker::unlock() | - | ||||||||||||||||||||||||
762 | - | |||||||||||||||||||||||||
763 | Unlocks the lock associated with this locker. | - | ||||||||||||||||||||||||
764 | - | |||||||||||||||||||||||||
765 | \sa QReadWriteLock::unlock() | - | ||||||||||||||||||||||||
766 | */ | - | ||||||||||||||||||||||||
767 | - | |||||||||||||||||||||||||
768 | /*! | - | ||||||||||||||||||||||||
769 | \fn void QWriteLocker::relock() | - | ||||||||||||||||||||||||
770 | - | |||||||||||||||||||||||||
771 | Relocks an unlocked lock. | - | ||||||||||||||||||||||||
772 | - | |||||||||||||||||||||||||
773 | \sa unlock() | - | ||||||||||||||||||||||||
774 | */ | - | ||||||||||||||||||||||||
775 | - | |||||||||||||||||||||||||
776 | /*! | - | ||||||||||||||||||||||||
777 | \fn QReadWriteLock *QWriteLocker::readWriteLock() const | - | ||||||||||||||||||||||||
778 | - | |||||||||||||||||||||||||
779 | Returns a pointer to the read-write lock that was passed | - | ||||||||||||||||||||||||
780 | to the constructor. | - | ||||||||||||||||||||||||
781 | */ | - | ||||||||||||||||||||||||
782 | - | |||||||||||||||||||||||||
783 | QT_END_NAMESPACE | - | ||||||||||||||||||||||||
784 | - | |||||||||||||||||||||||||
785 | #endif // QT_NO_THREAD | - | ||||||||||||||||||||||||
Source code | Switch to Preprocessed file |