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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/corelib/thread/qmutex.cpp