Absolute File Name: | /home/qt/qt5_coco/qt5/qtbase/src/corelib/thread/qmutex.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) 2012 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 "qmutex.h" | - | ||||||
44 | #include <qdebug.h> | - | ||||||
45 | - | |||||||
46 | #ifndef QT_NO_THREAD | - | ||||||
47 | #include "qatomic.h" | - | ||||||
48 | #include "qelapsedtimer.h" | - | ||||||
49 | #include "qthread.h" | - | ||||||
50 | #include "qmutex_p.h" | - | ||||||
51 | #include "qtypetraits.h" | - | ||||||
52 | - | |||||||
53 | #ifndef QT_LINUX_FUTEX | - | ||||||
54 | #include "private/qfreelist_p.h" | - | ||||||
55 | #endif | - | ||||||
56 | - | |||||||
57 | QT_BEGIN_NAMESPACE | - | ||||||
58 | - | |||||||
59 | static inline bool isRecursive(QMutexData *d) | - | ||||||
60 | { | - | ||||||
61 | quintptr u = quintptr(d); | - | ||||||
62 | if (Q_LIKELY(u <= 0x3))
| 9959019-30482927 | ||||||
63 | return false; executed 30482927 times by 1013 tests: return false; Executed by:
| 30482927 | ||||||
64 | #ifdef QT_LINUX_FUTEX | - | ||||||
65 | Q_ASSERT(d->recursive); | - | ||||||
66 | return true; executed 9959019 times by 765 tests: return true; Executed by:
| 9959019 | ||||||
67 | #else | - | ||||||
68 | return d->recursive; | - | ||||||
69 | #endif | - | ||||||
70 | } | - | ||||||
71 | - | |||||||
72 | class QRecursiveMutexPrivate : public QMutexData | - | ||||||
73 | { | - | ||||||
74 | public: | - | ||||||
75 | QRecursiveMutexPrivate() | - | ||||||
76 | : QMutexData(QMutex::Recursive), owner(0), count(0) {} executed 5840 times by 330 tests: end of block Executed by:
| 5840 | ||||||
77 | - | |||||||
78 | // written to by the thread that first owns 'mutex'; | - | ||||||
79 | // read during attempts to acquire ownership of 'mutex' from any other thread: | - | ||||||
80 | QAtomicPointer<QtPrivate::remove_pointer<Qt::HANDLE>::type> owner; | - | ||||||
81 | - | |||||||
82 | // only ever accessed from the thread that owns 'mutex': | - | ||||||
83 | uint count; | - | ||||||
84 | - | |||||||
85 | QMutex mutex; | - | ||||||
86 | - | |||||||
87 | bool lock(int timeout) QT_MUTEX_LOCK_NOEXCEPT; | - | ||||||
88 | void unlock() Q_DECL_NOTHROW; | - | ||||||
89 | }; | - | ||||||
90 | - | |||||||
91 | /* | - | ||||||
92 | \class QBasicMutex | - | ||||||
93 | \inmodule QtCore | - | ||||||
94 | \brief QMutex POD | - | ||||||
95 | \internal | - | ||||||
96 | - | |||||||
97 | \ingroup thread | - | ||||||
98 | - | |||||||
99 | - Can be used as global static object. | - | ||||||
100 | - Always non-recursive | - | ||||||
101 | - Do not use tryLock with timeout > 0, else you can have a leak (see the ~QMutex destructor) | - | ||||||
102 | */ | - | ||||||
103 | - | |||||||
104 | /*! | - | ||||||
105 | \class QMutex | - | ||||||
106 | \inmodule QtCore | - | ||||||
107 | \brief The QMutex class provides access serialization between threads. | - | ||||||
108 | - | |||||||
109 | \threadsafe | - | ||||||
110 | - | |||||||
111 | \ingroup thread | - | ||||||
112 | - | |||||||
113 | The purpose of a QMutex is to protect an object, data structure or | - | ||||||
114 | section of code so that only one thread can access it at a time | - | ||||||
115 | (this is similar to the Java \c synchronized keyword). It is | - | ||||||
116 | usually best to use a mutex with a QMutexLocker since this makes | - | ||||||
117 | it easy to ensure that locking and unlocking are performed | - | ||||||
118 | consistently. | - | ||||||
119 | - | |||||||
120 | For example, say there is a method that prints a message to the | - | ||||||
121 | user on two lines: | - | ||||||
122 | - | |||||||
123 | \snippet code/src_corelib_thread_qmutex.cpp 0 | - | ||||||
124 | - | |||||||
125 | If these two methods are called in succession, the following happens: | - | ||||||
126 | - | |||||||
127 | \snippet code/src_corelib_thread_qmutex.cpp 1 | - | ||||||
128 | - | |||||||
129 | If these two methods are called simultaneously from two threads then the | - | ||||||
130 | following sequence could result: | - | ||||||
131 | - | |||||||
132 | \snippet code/src_corelib_thread_qmutex.cpp 2 | - | ||||||
133 | - | |||||||
134 | If we add a mutex, we should get the result we want: | - | ||||||
135 | - | |||||||
136 | \snippet code/src_corelib_thread_qmutex.cpp 3 | - | ||||||
137 | - | |||||||
138 | Then only one thread can modify \c number at any given time and | - | ||||||
139 | the result is correct. This is a trivial example, of course, but | - | ||||||
140 | applies to any other case where things need to happen in a | - | ||||||
141 | particular sequence. | - | ||||||
142 | - | |||||||
143 | When you call lock() in a thread, other threads that try to call | - | ||||||
144 | lock() in the same place will block until the thread that got the | - | ||||||
145 | lock calls unlock(). A non-blocking alternative to lock() is | - | ||||||
146 | tryLock(). | - | ||||||
147 | - | |||||||
148 | QMutex is optimized to be fast in the non-contended case. A non-recursive | - | ||||||
149 | QMutex will not allocate memory if there is no contention on that mutex. | - | ||||||
150 | It is constructed and destroyed with almost no overhead, | - | ||||||
151 | which means it is fine to have many mutexes as part of other classes. | - | ||||||
152 | - | |||||||
153 | \sa QMutexLocker, QReadWriteLock, QSemaphore, QWaitCondition | - | ||||||
154 | */ | - | ||||||
155 | - | |||||||
156 | /*! | - | ||||||
157 | \enum QMutex::RecursionMode | - | ||||||
158 | - | |||||||
159 | \value Recursive In this mode, a thread can lock the same mutex | - | ||||||
160 | multiple times and the mutex won't be unlocked | - | ||||||
161 | until a corresponding number of unlock() calls | - | ||||||
162 | have been made. | - | ||||||
163 | - | |||||||
164 | \value NonRecursive In this mode, a thread may only lock a mutex | - | ||||||
165 | once. | - | ||||||
166 | - | |||||||
167 | \sa QMutex() | - | ||||||
168 | */ | - | ||||||
169 | - | |||||||
170 | /*! | - | ||||||
171 | Constructs a new mutex. The mutex is created in an unlocked state. | - | ||||||
172 | - | |||||||
173 | If \a mode is QMutex::Recursive, a thread can lock the same mutex | - | ||||||
174 | multiple times and the mutex won't be unlocked until a | - | ||||||
175 | corresponding number of unlock() calls have been made. Otherwise | - | ||||||
176 | a thread may only lock a mutex once. The default is | - | ||||||
177 | QMutex::NonRecursive. | - | ||||||
178 | - | |||||||
179 | Recursive mutexes are slower and take more memory than non-recursive ones. | - | ||||||
180 | - | |||||||
181 | \sa lock(), unlock() | - | ||||||
182 | */ | - | ||||||
183 | QMutex::QMutex(RecursionMode mode) | - | ||||||
184 | { | - | ||||||
185 | d_ptr.store(mode == Recursive ? new QRecursiveMutexPrivate : 0); | - | ||||||
186 | } executed 2696437 times by 909 tests: end of block Executed by:
| 2696437 | ||||||
187 | - | |||||||
188 | /*! | - | ||||||
189 | Destroys the mutex. | - | ||||||
190 | - | |||||||
191 | \warning Destroying a locked mutex may result in undefined behavior. | - | ||||||
192 | */ | - | ||||||
193 | QMutex::~QMutex() | - | ||||||
194 | { | - | ||||||
195 | QMutexData *d = d_ptr.load(); | - | ||||||
196 | if (isRecursive()) {
| 5435-2691914 | ||||||
197 | delete static_cast<QRecursiveMutexPrivate *>(d); | - | ||||||
198 | } else if (d) { executed 5435 times by 552 tests: end of block Executed by:
| 0-2691914 | ||||||
199 | #ifndef QT_LINUX_FUTEX | - | ||||||
200 | if (d != dummyLocked() && static_cast<QMutexPrivate *>(d)->possiblyUnlocked.load() | - | ||||||
201 | && tryLock()) { | - | ||||||
202 | unlock(); | - | ||||||
203 | return; | - | ||||||
204 | } | - | ||||||
205 | #endif | - | ||||||
206 | qWarning("QMutex: destroying locked mutex"); | - | ||||||
207 | } never executed: end of block | 0 | ||||||
208 | } executed 2697349 times by 756 tests: end of block Executed by:
| 2697349 | ||||||
209 | - | |||||||
210 | /*! \fn void QMutex::lock() | - | ||||||
211 | Locks the mutex. If another thread has locked the mutex then this | - | ||||||
212 | call will block until that thread has unlocked it. | - | ||||||
213 | - | |||||||
214 | Calling this function multiple times on the same mutex from the | - | ||||||
215 | same thread is allowed if this mutex is a | - | ||||||
216 | \l{QMutex::Recursive}{recursive mutex}. If this mutex is a | - | ||||||
217 | \l{QMutex::NonRecursive}{non-recursive mutex}, this function will | - | ||||||
218 | \e dead-lock when the mutex is locked recursively. | - | ||||||
219 | - | |||||||
220 | \sa unlock() | - | ||||||
221 | */ | - | ||||||
222 | void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT | - | ||||||
223 | { | - | ||||||
224 | QMutexData *current; | - | ||||||
225 | if (fastTryLock(current))
| 8853562-56203761 | ||||||
226 | return; executed 56203762 times by 1013 tests: return; Executed by:
| 56203762 | ||||||
227 | if (QT_PREPEND_NAMESPACE(isRecursive)(current))
| 3882585-4970977 | ||||||
228 | static_cast<QRecursiveMutexPrivate *>(current)->lock(-1); executed 4970977 times by 548 tests: static_cast<QRecursiveMutexPrivate *>(current)->lock(-1); Executed by:
| 4970977 | ||||||
229 | else | - | ||||||
230 | lockInternal(); executed 3882585 times by 934 tests: lockInternal(); Executed by:
| 3882585 | ||||||
231 | } | - | ||||||
232 | - | |||||||
233 | /*! \fn bool QMutex::tryLock(int timeout) | - | ||||||
234 | - | |||||||
235 | Attempts to lock the mutex. This function returns \c true if the lock | - | ||||||
236 | was obtained; otherwise it returns \c false. If another thread has | - | ||||||
237 | locked the mutex, this function will wait for at most \a timeout | - | ||||||
238 | milliseconds for the mutex to become available. | - | ||||||
239 | - | |||||||
240 | Note: Passing a negative number as the \a timeout is equivalent to | - | ||||||
241 | calling lock(), i.e. this function will wait forever until mutex | - | ||||||
242 | can be locked if \a timeout is negative. | - | ||||||
243 | - | |||||||
244 | If the lock was obtained, the mutex must be unlocked with unlock() | - | ||||||
245 | before another thread can successfully lock it. | - | ||||||
246 | - | |||||||
247 | Calling this function multiple times on the same mutex from the | - | ||||||
248 | same thread is allowed if this mutex is a | - | ||||||
249 | \l{QMutex::Recursive}{recursive mutex}. If this mutex is a | - | ||||||
250 | \l{QMutex::NonRecursive}{non-recursive mutex}, this function will | - | ||||||
251 | \e always return false when attempting to lock the mutex | - | ||||||
252 | recursively. | - | ||||||
253 | - | |||||||
254 | \sa lock(), unlock() | - | ||||||
255 | */ | - | ||||||
256 | bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT | - | ||||||
257 | { | - | ||||||
258 | QMutexData *current; | - | ||||||
259 | if (fastTryLock(current))
| 275292-2843175 | ||||||
260 | return true; executed 2843175 times by 476 tests: return true; Executed by:
| 2843175 | ||||||
261 | if (QT_PREPEND_NAMESPACE(isRecursive)(current))
| 10819-264473 | ||||||
262 | return static_cast<QRecursiveMutexPrivate *>(current)->lock(timeout); executed 10819 times by 2 tests: return static_cast<QRecursiveMutexPrivate *>(current)->lock(timeout); Executed by:
| 10819 | ||||||
263 | else | - | ||||||
264 | return lockInternal(timeout); executed 264473 times by 22 tests: return lockInternal(timeout); Executed by:
| 264473 | ||||||
265 | } | - | ||||||
266 | - | |||||||
267 | /*! \fn void QMutex::unlock() | - | ||||||
268 | Unlocks the mutex. Attempting to unlock a mutex in a different | - | ||||||
269 | thread to the one that locked it results in an error. Unlocking a | - | ||||||
270 | mutex that is not locked results in undefined behavior. | - | ||||||
271 | - | |||||||
272 | \sa lock() | - | ||||||
273 | */ | - | ||||||
274 | void QMutex::unlock() Q_DECL_NOTHROW | - | ||||||
275 | { | - | ||||||
276 | QMutexData *current; | - | ||||||
277 | if (fastTryUnlock(current))
| 12735038-55159975 | ||||||
278 | return; executed 55166884 times by 1013 tests: return; Executed by:
| 55166884 | ||||||
279 | if (QT_PREPEND_NAMESPACE(isRecursive)(current))
| 4971788-7763250 | ||||||
280 | static_cast<QRecursiveMutexPrivate *>(current)->unlock(); executed 4971788 times by 548 tests: static_cast<QRecursiveMutexPrivate *>(current)->unlock(); Executed by:
| 4971788 | ||||||
281 | else | - | ||||||
282 | unlockInternal(); executed 7763250 times by 934 tests: unlockInternal(); Executed by:
| 7763250 | ||||||
283 | } | - | ||||||
284 | - | |||||||
285 | bool QBasicMutex::isRecursive() Q_DECL_NOTHROW | - | ||||||
286 | { | - | ||||||
287 | return QT_PREPEND_NAMESPACE(isRecursive)(d_ptr.loadAcquire()); executed 11911224 times by 934 tests: return ::isRecursive(d_ptr.loadAcquire()); Executed by:
| 11911224 | ||||||
288 | } | - | ||||||
289 | - | |||||||
290 | /*! | - | ||||||
291 | \overload | - | ||||||
292 | \since 5.7 | - | ||||||
293 | - | |||||||
294 | Returns \c true if the mutex is recursive | - | ||||||
295 | */ | - | ||||||
296 | bool QBasicMutex::isRecursive() const Q_DECL_NOTHROW | - | ||||||
297 | { | - | ||||||
298 | return QT_PREPEND_NAMESPACE(isRecursive)(d_ptr.loadAcquire()); executed 6666830 times by 1013 tests: return ::isRecursive(d_ptr.loadAcquire()); Executed by:
| 6666830 | ||||||
299 | } | - | ||||||
300 | - | |||||||
301 | /*! | - | ||||||
302 | \class QMutexLocker | - | ||||||
303 | \inmodule QtCore | - | ||||||
304 | \brief The QMutexLocker class is a convenience class that simplifies | - | ||||||
305 | locking and unlocking mutexes. | - | ||||||
306 | - | |||||||
307 | \threadsafe | - | ||||||
308 | - | |||||||
309 | \ingroup thread | - | ||||||
310 | - | |||||||
311 | Locking and unlocking a QMutex in complex functions and | - | ||||||
312 | statements or in exception handling code is error-prone and | - | ||||||
313 | difficult to debug. QMutexLocker can be used in such situations | - | ||||||
314 | to ensure that the state of the mutex is always well-defined. | - | ||||||
315 | - | |||||||
316 | QMutexLocker should be created within a function where a | - | ||||||
317 | QMutex needs to be locked. The mutex is locked when QMutexLocker | - | ||||||
318 | is created. You can unlock and relock the mutex with \c unlock() | - | ||||||
319 | and \c relock(). If locked, the mutex will be unlocked when the | - | ||||||
320 | QMutexLocker is destroyed. | - | ||||||
321 | - | |||||||
322 | For example, this complex function locks a QMutex upon entering | - | ||||||
323 | the function and unlocks the mutex at all the exit points: | - | ||||||
324 | - | |||||||
325 | \snippet code/src_corelib_thread_qmutex.cpp 4 | - | ||||||
326 | - | |||||||
327 | This example function will get more complicated as it is | - | ||||||
328 | developed, which increases the likelihood that errors will occur. | - | ||||||
329 | - | |||||||
330 | Using QMutexLocker greatly simplifies the code, and makes it more | - | ||||||
331 | readable: | - | ||||||
332 | - | |||||||
333 | \snippet code/src_corelib_thread_qmutex.cpp 5 | - | ||||||
334 | - | |||||||
335 | Now, the mutex will always be unlocked when the QMutexLocker | - | ||||||
336 | object is destroyed (when the function returns since \c locker is | - | ||||||
337 | an auto variable). | - | ||||||
338 | - | |||||||
339 | The same principle applies to code that throws and catches | - | ||||||
340 | exceptions. An exception that is not caught in the function that | - | ||||||
341 | has locked the mutex has no way of unlocking the mutex before the | - | ||||||
342 | exception is passed up the stack to the calling function. | - | ||||||
343 | - | |||||||
344 | QMutexLocker also provides a \c mutex() member function that returns | - | ||||||
345 | the mutex on which the QMutexLocker is operating. This is useful | - | ||||||
346 | for code that needs access to the mutex, such as | - | ||||||
347 | QWaitCondition::wait(). For example: | - | ||||||
348 | - | |||||||
349 | \snippet code/src_corelib_thread_qmutex.cpp 6 | - | ||||||
350 | - | |||||||
351 | \sa QReadLocker, QWriteLocker, QMutex | - | ||||||
352 | */ | - | ||||||
353 | - | |||||||
354 | /*! | - | ||||||
355 | \fn QMutexLocker::QMutexLocker(QMutex *mutex) | - | ||||||
356 | - | |||||||
357 | Constructs a QMutexLocker and locks \a mutex. The mutex will be | - | ||||||
358 | unlocked when the QMutexLocker is destroyed. If \a mutex is zero, | - | ||||||
359 | QMutexLocker does nothing. | - | ||||||
360 | - | |||||||
361 | \sa QMutex::lock() | - | ||||||
362 | */ | - | ||||||
363 | - | |||||||
364 | /*! | - | ||||||
365 | \fn QMutexLocker::~QMutexLocker() | - | ||||||
366 | - | |||||||
367 | Destroys the QMutexLocker and unlocks the mutex that was locked | - | ||||||
368 | in the constructor. | - | ||||||
369 | - | |||||||
370 | \sa QMutex::unlock() | - | ||||||
371 | */ | - | ||||||
372 | - | |||||||
373 | /*! | - | ||||||
374 | \fn void QMutexLocker::unlock() | - | ||||||
375 | - | |||||||
376 | Unlocks this mutex locker. You can use \c relock() to lock | - | ||||||
377 | it again. It does not need to be locked when destroyed. | - | ||||||
378 | - | |||||||
379 | \sa relock() | - | ||||||
380 | */ | - | ||||||
381 | - | |||||||
382 | /*! | - | ||||||
383 | \fn void QMutexLocker::relock() | - | ||||||
384 | - | |||||||
385 | Relocks an unlocked mutex locker. | - | ||||||
386 | - | |||||||
387 | \sa unlock() | - | ||||||
388 | */ | - | ||||||
389 | - | |||||||
390 | /*! | - | ||||||
391 | \fn QMutex *QMutexLocker::mutex() const | - | ||||||
392 | - | |||||||
393 | Returns the mutex on which the QMutexLocker is operating. | - | ||||||
394 | - | |||||||
395 | */ | - | ||||||
396 | - | |||||||
397 | #ifndef QT_LINUX_FUTEX //linux implementation is in qmutex_linux.cpp | - | ||||||
398 | - | |||||||
399 | /* | - | ||||||
400 | For a rough introduction on how this works, refer to | - | ||||||
401 | http://woboq.com/blog/internals-of-qmutex-in-qt5.html | - | ||||||
402 | which explains a slightly simplified version of it. | - | ||||||
403 | The differences are that here we try to work with timeout (requires the | - | ||||||
404 | possiblyUnlocked flag) and that we only wake one thread when unlocking | - | ||||||
405 | (requires maintaining the waiters count) | - | ||||||
406 | We also support recursive mutexes which always have a valid d_ptr. | - | ||||||
407 | - | |||||||
408 | The waiters flag represents the number of threads that are waiting or about | - | ||||||
409 | to wait on the mutex. There are two tricks to keep in mind: | - | ||||||
410 | We don't want to increment waiters after we checked no threads are waiting | - | ||||||
411 | (waiters == 0). That's why we atomically set the BigNumber flag on waiters when | - | ||||||
412 | we check waiters. Similarly, if waiters is decremented right after we checked, | - | ||||||
413 | the mutex would be unlocked (d->wakeUp() has (or will) be called), but there is | - | ||||||
414 | no thread waiting. This is only happening if there was a timeout in tryLock at the | - | ||||||
415 | same time as the mutex is unlocked. So when there was a timeout, we set the | - | ||||||
416 | possiblyUnlocked flag. | - | ||||||
417 | */ | - | ||||||
418 | - | |||||||
419 | /*! | - | ||||||
420 | \internal helper for lock() | - | ||||||
421 | */ | - | ||||||
422 | void QBasicMutex::lockInternal() QT_MUTEX_LOCK_NOEXCEPT | - | ||||||
423 | { | - | ||||||
424 | lockInternal(-1); | - | ||||||
425 | } | - | ||||||
426 | - | |||||||
427 | /*! | - | ||||||
428 | \internal helper for lock(int) | - | ||||||
429 | */ | - | ||||||
430 | bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT | - | ||||||
431 | { | - | ||||||
432 | Q_ASSERT(!isRecursive()); | - | ||||||
433 | - | |||||||
434 | while (!fastTryLock()) { | - | ||||||
435 | QMutexData *copy = d_ptr.loadAcquire(); | - | ||||||
436 | if (!copy) // if d is 0, the mutex is unlocked | - | ||||||
437 | continue; | - | ||||||
438 | - | |||||||
439 | if (copy == dummyLocked()) { | - | ||||||
440 | if (timeout == 0) | - | ||||||
441 | return false; | - | ||||||
442 | // The mutex is locked but does not have a QMutexPrivate yet. | - | ||||||
443 | // we need to allocate a QMutexPrivate | - | ||||||
444 | QMutexPrivate *newD = QMutexPrivate::allocate(); | - | ||||||
445 | if (!d_ptr.testAndSetOrdered(dummyLocked(), newD)) { | - | ||||||
446 | //Either the mutex is already unlocked, or another thread already set it. | - | ||||||
447 | newD->deref(); | - | ||||||
448 | continue; | - | ||||||
449 | } | - | ||||||
450 | copy = newD; | - | ||||||
451 | //the d->refCount is already 1 the deref will occurs when we unlock | - | ||||||
452 | } | - | ||||||
453 | - | |||||||
454 | QMutexPrivate *d = static_cast<QMutexPrivate *>(copy); | - | ||||||
455 | if (timeout == 0 && !d->possiblyUnlocked.load()) | - | ||||||
456 | return false; | - | ||||||
457 | - | |||||||
458 | // At this point we have a pointer to a QMutexPrivate. But the other thread | - | ||||||
459 | // may unlock the mutex at any moment and release the QMutexPrivate to the pool. | - | ||||||
460 | // We will try to reference it to avoid unlock to release it to the pool to make | - | ||||||
461 | // sure it won't be released. But if the refcount is already 0 it has been released. | - | ||||||
462 | if (!d->ref()) | - | ||||||
463 | continue; //that QMutexData was already released | - | ||||||
464 | - | |||||||
465 | // We now hold a reference to the QMutexPrivate. It won't be released and re-used. | - | ||||||
466 | // But it is still possible that it was already re-used by another QMutex right before | - | ||||||
467 | // we did the ref(). So check if we still hold a pointer to the right mutex. | - | ||||||
468 | if (d != d_ptr.loadAcquire()) { | - | ||||||
469 | //Either the mutex is already unlocked, or relocked with another mutex | - | ||||||
470 | d->deref(); | - | ||||||
471 | continue; | - | ||||||
472 | } | - | ||||||
473 | - | |||||||
474 | // In this part, we will try to increment the waiters count. | - | ||||||
475 | // We just need to take care of the case in which the old_waiters | - | ||||||
476 | // is set to the BigNumber magic value set in unlockInternal() | - | ||||||
477 | int old_waiters; | - | ||||||
478 | do { | - | ||||||
479 | old_waiters = d->waiters.load(); | - | ||||||
480 | if (old_waiters == -QMutexPrivate::BigNumber) { | - | ||||||
481 | // we are unlocking, and the thread that unlocks is about to change d to 0 | - | ||||||
482 | // we try to acquire the mutex by changing to dummyLocked() | - | ||||||
483 | if (d_ptr.testAndSetAcquire(d, dummyLocked())) { | - | ||||||
484 | // Mutex acquired | - | ||||||
485 | d->deref(); | - | ||||||
486 | return true; | - | ||||||
487 | } else { | - | ||||||
488 | Q_ASSERT(d != d_ptr.load()); //else testAndSetAcquire should have succeeded | - | ||||||
489 | // Mutex is likely to bo 0, we should continue the outer-loop, | - | ||||||
490 | // set old_waiters to the magic value of BigNumber | - | ||||||
491 | old_waiters = QMutexPrivate::BigNumber; | - | ||||||
492 | break; | - | ||||||
493 | } | - | ||||||
494 | } | - | ||||||
495 | } while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1)); | - | ||||||
496 | - | |||||||
497 | if (d != d_ptr.loadAcquire()) { | - | ||||||
498 | // The mutex was unlocked before we incremented waiters. | - | ||||||
499 | if (old_waiters != QMutexPrivate::BigNumber) { | - | ||||||
500 | //we did not break the previous loop | - | ||||||
501 | Q_ASSERT(d->waiters.load() >= 1); | - | ||||||
502 | d->waiters.deref(); | - | ||||||
503 | } | - | ||||||
504 | d->deref(); | - | ||||||
505 | continue; | - | ||||||
506 | } | - | ||||||
507 | - | |||||||
508 | if (d->wait(timeout)) { | - | ||||||
509 | // reset the possiblyUnlocked flag if needed (and deref its corresponding reference) | - | ||||||
510 | if (d->possiblyUnlocked.load() && d->possiblyUnlocked.testAndSetRelaxed(true, false)) | - | ||||||
511 | d->deref(); | - | ||||||
512 | d->derefWaiters(1); | - | ||||||
513 | //we got the lock. (do not deref) | - | ||||||
514 | Q_ASSERT(d == d_ptr.load()); | - | ||||||
515 | return true; | - | ||||||
516 | } else { | - | ||||||
517 | Q_ASSERT(timeout >= 0); | - | ||||||
518 | //timeout | - | ||||||
519 | d->derefWaiters(1); | - | ||||||
520 | //There may be a race in which the mutex is unlocked right after we timed out, | - | ||||||
521 | // and before we deref the waiters, so maybe the mutex is actually unlocked. | - | ||||||
522 | // Set the possiblyUnlocked flag to indicate this possibility. | - | ||||||
523 | if (!d->possiblyUnlocked.testAndSetRelaxed(false, true)) { | - | ||||||
524 | // We keep a reference when possiblyUnlocked is true. | - | ||||||
525 | // but if possiblyUnlocked was already true, we don't need to keep the reference. | - | ||||||
526 | d->deref(); | - | ||||||
527 | } | - | ||||||
528 | return false; | - | ||||||
529 | } | - | ||||||
530 | } | - | ||||||
531 | Q_ASSERT(d_ptr.load() != 0); | - | ||||||
532 | return true; | - | ||||||
533 | } | - | ||||||
534 | - | |||||||
535 | /*! | - | ||||||
536 | \internal | - | ||||||
537 | */ | - | ||||||
538 | void QBasicMutex::unlockInternal() Q_DECL_NOTHROW | - | ||||||
539 | { | - | ||||||
540 | QMutexData *copy = d_ptr.loadAcquire(); | - | ||||||
541 | Q_ASSERT(copy); //we must be locked | - | ||||||
542 | Q_ASSERT(copy != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed | - | ||||||
543 | Q_ASSERT(!isRecursive()); | - | ||||||
544 | - | |||||||
545 | QMutexPrivate *d = reinterpret_cast<QMutexPrivate *>(copy); | - | ||||||
546 | - | |||||||
547 | // If no one is waiting for the lock anymore, we should reset d to 0x0. | - | ||||||
548 | // Using fetchAndAdd, we atomically check that waiters was equal to 0, and add a flag | - | ||||||
549 | // to the waiters variable (BigNumber). That way, we avoid the race in which waiters is | - | ||||||
550 | // incremented right after we checked, because we won't increment waiters if is | - | ||||||
551 | // equal to -BigNumber | - | ||||||
552 | if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) { | - | ||||||
553 | //there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0) | - | ||||||
554 | if (d_ptr.testAndSetRelease(d, 0)) { | - | ||||||
555 | // reset the possiblyUnlocked flag if needed (and deref its corresponding reference) | - | ||||||
556 | if (d->possiblyUnlocked.load() && d->possiblyUnlocked.testAndSetRelaxed(true, false)) | - | ||||||
557 | d->deref(); | - | ||||||
558 | } | - | ||||||
559 | d->derefWaiters(0); | - | ||||||
560 | } else { | - | ||||||
561 | d->derefWaiters(0); | - | ||||||
562 | //there are thread waiting, transfer the lock. | - | ||||||
563 | d->wakeUp(); | - | ||||||
564 | } | - | ||||||
565 | d->deref(); | - | ||||||
566 | } | - | ||||||
567 | - | |||||||
568 | //The freelist management | - | ||||||
569 | namespace { | - | ||||||
570 | struct FreeListConstants : QFreeListDefaultConstants { | - | ||||||
571 | enum { BlockCount = 4, MaxIndex=0xffff }; | - | ||||||
572 | static const int Sizes[BlockCount]; | - | ||||||
573 | }; | - | ||||||
574 | const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = { | - | ||||||
575 | 16, | - | ||||||
576 | 128, | - | ||||||
577 | 1024, | - | ||||||
578 | FreeListConstants::MaxIndex - (16-128-1024) | - | ||||||
579 | }; | - | ||||||
580 | - | |||||||
581 | typedef QFreeList<QMutexPrivate, FreeListConstants> FreeList; | - | ||||||
582 | // We cannot use Q_GLOBAL_STATIC because it uses QMutex | - | ||||||
583 | static FreeList freeList_; | - | ||||||
584 | FreeList *freelist() | - | ||||||
585 | { | - | ||||||
586 | return &freeList_; | - | ||||||
587 | } | - | ||||||
588 | } | - | ||||||
589 | - | |||||||
590 | QMutexPrivate *QMutexPrivate::allocate() | - | ||||||
591 | { | - | ||||||
592 | int i = freelist()->next(); | - | ||||||
593 | QMutexPrivate *d = &(*freelist())[i]; | - | ||||||
594 | d->id = i; | - | ||||||
595 | Q_ASSERT(d->refCount.load() == 0); | - | ||||||
596 | Q_ASSERT(!d->recursive); | - | ||||||
597 | Q_ASSERT(!d->possiblyUnlocked.load()); | - | ||||||
598 | Q_ASSERT(d->waiters.load() == 0); | - | ||||||
599 | d->refCount.store(1); | - | ||||||
600 | return d; | - | ||||||
601 | } | - | ||||||
602 | - | |||||||
603 | void QMutexPrivate::release() | - | ||||||
604 | { | - | ||||||
605 | Q_ASSERT(!recursive); | - | ||||||
606 | Q_ASSERT(refCount.load() == 0); | - | ||||||
607 | Q_ASSERT(!possiblyUnlocked.load()); | - | ||||||
608 | Q_ASSERT(waiters.load() == 0); | - | ||||||
609 | freelist()->release(id); | - | ||||||
610 | } | - | ||||||
611 | - | |||||||
612 | // atomically subtract "value" to the waiters, and remove the QMutexPrivate::BigNumber flag | - | ||||||
613 | void QMutexPrivate::derefWaiters(int value) Q_DECL_NOTHROW | - | ||||||
614 | { | - | ||||||
615 | int old_waiters; | - | ||||||
616 | int new_waiters; | - | ||||||
617 | do { | - | ||||||
618 | old_waiters = waiters.load(); | - | ||||||
619 | new_waiters = old_waiters; | - | ||||||
620 | if (new_waiters < 0) { | - | ||||||
621 | new_waiters += QMutexPrivate::BigNumber; | - | ||||||
622 | } | - | ||||||
623 | new_waiters -= value; | - | ||||||
624 | } while (!waiters.testAndSetRelaxed(old_waiters, new_waiters)); | - | ||||||
625 | } | - | ||||||
626 | #endif | - | ||||||
627 | - | |||||||
628 | /*! | - | ||||||
629 | \internal | - | ||||||
630 | */ | - | ||||||
631 | inline bool QRecursiveMutexPrivate::lock(int timeout) QT_MUTEX_LOCK_NOEXCEPT | - | ||||||
632 | { | - | ||||||
633 | Qt::HANDLE self = QThread::currentThreadId(); | - | ||||||
634 | if (owner.load() == self) {
| 18490-4963306 | ||||||
635 | ++count; | - | ||||||
636 | Q_ASSERT_X(count != 0, "QMutex::lock", "Overflow in recursion counter"); | - | ||||||
637 | return true; executed 18490 times by 347 tests: return true; Executed by:
| 18490 | ||||||
638 | } | - | ||||||
639 | bool success = true; | - | ||||||
640 | if (timeout == -1) {
| 10216-4953090 | ||||||
641 | mutex.QBasicMutex::lock(); | - | ||||||
642 | } else { executed 4953090 times by 548 tests: end of block Executed by:
| 4953090 | ||||||
643 | success = mutex.tryLock(timeout); | - | ||||||
644 | } executed 10216 times by 2 tests: end of block Executed by:
| 10216 | ||||||
645 | - | |||||||
646 | if (success)
| 10008-4953298 | ||||||
647 | owner.store(self); executed 4953298 times by 548 tests: owner.store(self); Executed by:
| 4953298 | ||||||
648 | return success; executed 4963306 times by 548 tests: return success; Executed by:
| 4963306 | ||||||
649 | } | - | ||||||
650 | - | |||||||
651 | /*! | - | ||||||
652 | \internal | - | ||||||
653 | */ | - | ||||||
654 | inline void QRecursiveMutexPrivate::unlock() Q_DECL_NOTHROW | - | ||||||
655 | { | - | ||||||
656 | if (count > 0) {
| 18490-4953298 | ||||||
657 | count--; | - | ||||||
658 | } else { executed 18490 times by 347 tests: end of block Executed by:
| 18490 | ||||||
659 | owner.store(0); | - | ||||||
660 | mutex.QBasicMutex::unlock(); | - | ||||||
661 | } executed 4953298 times by 548 tests: end of block Executed by:
| 4953298 | ||||||
662 | } | - | ||||||
663 | - | |||||||
664 | QT_END_NAMESPACE | - | ||||||
665 | - | |||||||
666 | #ifdef QT_LINUX_FUTEX | - | ||||||
667 | # include "qmutex_linux.cpp" | - | ||||||
668 | #elif defined(Q_OS_MAC) | - | ||||||
669 | # include "qmutex_mac.cpp" | - | ||||||
670 | #elif defined(Q_OS_WIN) | - | ||||||
671 | # include "qmutex_win.cpp" | - | ||||||
672 | #else | - | ||||||
673 | # include "qmutex_unix.cpp" | - | ||||||
674 | #endif | - | ||||||
675 | - | |||||||
676 | #endif // QT_NO_THREAD | - | ||||||
Source code | Switch to Preprocessed file |