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