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