| 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 blockExecuted 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 blockExecuted 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 blockExecuted 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 blockExecuted 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 blockExecuted by:
| 4953090 | ||||||
| 643 | success = mutex.tryLock(timeout); | - | ||||||
| 644 | } executed 10216 times by 2 tests: end of blockExecuted 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 blockExecuted by:
| 18490 | ||||||
| 659 | owner.store(0); | - | ||||||
| 660 | mutex.QBasicMutex::unlock(); | - | ||||||
| 661 | } executed 4953298 times by 548 tests: end of blockExecuted 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 |