Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qmutex.cpp
Go to the documentation of this file.
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 "qelapsedtimer.h"
12#include "qfutex_p.h"
13#include "qthread.h"
14#include "qmutex_p.h"
15
16#ifndef QT_ALWAYS_USE_FUTEX
17#include "private/qfreelist_p.h"
18#endif
19
21
22using namespace QtFutex;
24{
25 return reinterpret_cast<QMutexPrivate *>(quintptr(3));
26}
27
28/*
29 \class QBasicMutex
30 \inmodule QtCore
31 \brief QMutex POD
32 \internal
33
34 \ingroup thread
35
36 - Can be used as global static object.
37 - Always non-recursive
38 - Do not use tryLock with timeout > 0, else you can have a leak (see the ~QMutex destructor)
39*/
40
105void QBasicMutex::destroyInternal(QMutexPrivate *d)
106{
107 if (!d)
108 return;
109 if (!futexAvailable()) {
110 if (d != dummyLocked() && d->possiblyUnlocked.loadRelaxed() && tryLock()) {
111 unlock();
112 return;
113 }
114 }
115 qWarning("QMutex: destroying locked mutex");
116}
117
283QRecursiveMutex::~QRecursiveMutex()
284{
285}
286
335bool QRecursiveMutex::tryLock(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT
336{
337 unsigned tsanFlags = QtTsan::MutexWriteReentrant | QtTsan::TryLock;
338 QtTsan::mutexPreLock(this, tsanFlags);
339
341 if (owner.loadRelaxed() == self) {
342 ++count;
343 Q_ASSERT_X(count != 0, "QMutex::lock", "Overflow in recursion counter");
344 QtTsan::mutexPostLock(this, tsanFlags, 0);
345 return true;
346 }
347 bool success = true;
348 if (timeout.isForever()) {
349 mutex.lock();
350 } else {
351 success = mutex.tryLock(timeout);
352 }
353
354 if (success)
355 owner.storeRelaxed(self);
356 else
357 tsanFlags |= QtTsan::TryLockFailed;
358
359 QtTsan::mutexPostLock(this, tsanFlags, 0);
360
361 return success;
362}
363
421void QRecursiveMutex::unlock() noexcept
422{
423 Q_ASSERT(owner.loadRelaxed() == QThread::currentThreadId());
424 QtTsan::mutexPreUnlock(this, 0u);
425
426 if (count > 0) {
427 count--;
428 } else {
429 owner.storeRelaxed(nullptr);
430 mutex.unlock();
431 }
432
433 QtTsan::mutexPostUnlock(this, 0u);
434}
435
436
575/*
576 For a rough introduction on how this works, refer to
577 http://woboq.com/blog/internals-of-qmutex-in-qt5.html
578 which explains a slightly simplified version of it.
579 The differences are that here we try to work with timeout (requires the
580 possiblyUnlocked flag) and that we only wake one thread when unlocking
581 (requires maintaining the waiters count)
582 We also support recursive mutexes which always have a valid d_ptr.
583
584 The waiters flag represents the number of threads that are waiting or about
585 to wait on the mutex. There are two tricks to keep in mind:
586 We don't want to increment waiters after we checked no threads are waiting
587 (waiters == 0). That's why we atomically set the BigNumber flag on waiters when
588 we check waiters. Similarly, if waiters is decremented right after we checked,
589 the mutex would be unlocked (d->wakeUp() has (or will) be called), but there is
590 no thread waiting. This is only happening if there was a timeout in tryLock at the
591 same time as the mutex is unlocked. So when there was a timeout, we set the
592 possiblyUnlocked flag.
593*/
594
595/*
596 * QBasicMutex implementation with futexes (Linux, Windows 10)
597 *
598 * QBasicMutex contains one pointer value, which can contain one of four
599 * different values:
600 * 0x0 unlocked
601 * 0x1 locked, no waiters
602 * 0x3 locked, at least one waiter
603 *
604 * LOCKING:
605 *
606 * A starts in the 0x0 state, indicating that it's unlocked. When the first
607 * thread attempts to lock it, it will perform a testAndSetAcquire
608 * from 0x0 to 0x1. If that succeeds, the caller concludes that it
609 * successfully locked the mutex. That happens in fastTryLock().
610 *
611 * If that testAndSetAcquire fails, QBasicMutex::lockInternal is called.
612 *
613 * lockInternal will examine the value of the pointer. Otherwise, it will use
614 * futexes to sleep and wait for another thread to unlock. To do that, it needs
615 * to set a pointer value of 0x3, which indicates that thread is waiting. It
616 * does that by a simple fetchAndStoreAcquire operation.
617 *
618 * If the pointer value was 0x0, it means we succeeded in acquiring the mutex.
619 * For other values, it will then call FUTEX_WAIT and with an expected value of
620 * 0x3.
621 *
622 * If the pointer value changed before futex(2) managed to sleep, it will
623 * return -1 / EWOULDBLOCK, in which case we have to start over. And even if we
624 * are woken up directly by a FUTEX_WAKE, we need to acquire the mutex, so we
625 * start over again.
626 *
627 * UNLOCKING:
628 *
629 * To unlock, we need to set a value of 0x0 to indicate it's unlocked. The
630 * first attempt is a testAndSetRelease operation from 0x1 to 0x0. If that
631 * succeeds, we're done.
632 *
633 * If it fails, unlockInternal() is called. The only possibility is that the
634 * mutex value was 0x3, which indicates some other thread is waiting or was
635 * waiting in the past. We then set the mutex to 0x0 and perform a FUTEX_WAKE.
636 */
637
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(dummyFutexValue()) != nullptr) {
647 // successfully set the waiting bit, now sleep
648 futexWait(d_ptr, dummyFutexValue());
649
650 // we got woken up, so try to acquire the mutex
651 }
652 Q_ASSERT(d_ptr.loadRelaxed());
653 } else {
654 lockInternal(-1);
655 }
656}
657
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(QDeadlineTimer(timeout));
668}
669#endif
670
674bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT
675{
676 if (deadlineTimer.hasExpired())
677 return false;
678
679 if (futexAvailable()) {
680 if (Q_UNLIKELY(deadlineTimer.isForever())) {
681 lockInternal();
682 return true;
683 }
684
685 // The mutex is already locked, set a bit indicating we're waiting.
686 // Note we must set to dummyFutexValue because there could be other threads
687 // also waiting.
688 if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr)
689 return true;
690
691 for (;;) {
692 if (!futexWait(d_ptr, dummyFutexValue(), deadlineTimer))
693 return false;
694
695 // We got woken up, so must try to acquire the mutex. We must set
696 // to dummyFutexValue() again because there could be other threads
697 // waiting.
698 if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr)
699 return true;
700
701 if (deadlineTimer.hasExpired())
702 return false;
703 }
704 }
705
706#if !defined(QT_ALWAYS_USE_FUTEX)
707 while (!fastTryLock()) {
708 QMutexPrivate *copy = d_ptr.loadAcquire();
709 if (!copy) // if d is 0, the mutex is unlocked
710 continue;
711
712 if (copy == dummyLocked()) {
713 if (deadlineTimer.hasExpired())
714 return false;
715 // The mutex is locked but does not have a QMutexPrivate yet.
716 // we need to allocate a QMutexPrivate
718 if (!d_ptr.testAndSetOrdered(dummyLocked(), newD)) {
719 //Either the mutex is already unlocked, or another thread already set it.
720 newD->deref();
721 continue;
722 }
723 copy = newD;
724 //the d->refCount is already 1 the deref will occurs when we unlock
725 }
726
727 QMutexPrivate *d = static_cast<QMutexPrivate *>(copy);
728 if (deadlineTimer.hasExpired() && !d->possiblyUnlocked.loadRelaxed())
729 return false;
730
731 // At this point we have a pointer to a QMutexPrivate. But the other thread
732 // may unlock the mutex at any moment and release the QMutexPrivate to the pool.
733 // We will try to reference it to avoid unlock to release it to the pool to make
734 // sure it won't be released. But if the refcount is already 0 it has been released.
735 if (!d->ref())
736 continue; //that QMutexPrivate was already released
737
738 // We now hold a reference to the QMutexPrivate. It won't be released and re-used.
739 // But it is still possible that it was already re-used by another QMutex right before
740 // we did the ref(). So check if we still hold a pointer to the right mutex.
741 if (d != d_ptr.loadAcquire()) {
742 //Either the mutex is already unlocked, or relocked with another mutex
743 d->deref();
744 continue;
745 }
746
747 // In this part, we will try to increment the waiters count.
748 // We just need to take care of the case in which the old_waiters
749 // is set to the BigNumber magic value set in unlockInternal()
750 int old_waiters;
751 do {
752 old_waiters = d->waiters.loadAcquire();
753 if (old_waiters == -QMutexPrivate::BigNumber) {
754 // we are unlocking, and the thread that unlocks is about to change d to 0
755 // we try to acquire the mutex by changing to dummyLocked()
756 if (d_ptr.testAndSetAcquire(d, dummyLocked())) {
757 // Mutex acquired
758 d->deref();
759 return true;
760 } else {
761 Q_ASSERT(d != d_ptr.loadRelaxed()); //else testAndSetAcquire should have succeeded
762 // Mutex is likely to bo 0, we should continue the outer-loop,
763 // set old_waiters to the magic value of BigNumber
764 old_waiters = QMutexPrivate::BigNumber;
765 break;
766 }
767 }
768 } while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1));
769
770 if (d != d_ptr.loadAcquire()) {
771 // The mutex was unlocked before we incremented waiters.
772 if (old_waiters != QMutexPrivate::BigNumber) {
773 //we did not break the previous loop
774 Q_ASSERT(d->waiters.loadRelaxed() >= 1);
775 d->waiters.deref();
776 }
777 d->deref();
778 continue;
779 }
780
781 if (d->wait(deadlineTimer)) {
782 // reset the possiblyUnlocked flag if needed (and deref its corresponding reference)
783 if (d->possiblyUnlocked.loadRelaxed() && d->possiblyUnlocked.testAndSetRelaxed(true, false))
784 d->deref();
785 d->derefWaiters(1);
786 //we got the lock. (do not deref)
787 Q_ASSERT(d == d_ptr.loadRelaxed());
788 return true;
789 } else {
790 // timed out
791 d->derefWaiters(1);
792 //There may be a race in which the mutex is unlocked right after we timed out,
793 // and before we deref the waiters, so maybe the mutex is actually unlocked.
794 // Set the possiblyUnlocked flag to indicate this possibility.
795 if (!d->possiblyUnlocked.testAndSetRelaxed(false, true)) {
796 // We keep a reference when possiblyUnlocked is true.
797 // but if possiblyUnlocked was already true, we don't need to keep the reference.
798 d->deref();
799 }
800 return false;
801 }
802 }
803 Q_ASSERT(d_ptr.loadRelaxed() != 0);
804 return true;
805#else
806 Q_UNREACHABLE();
807#endif
808}
809
813void QBasicMutex::unlockInternal() noexcept
814{
815 QMutexPrivate *copy = d_ptr.loadAcquire();
816 Q_ASSERT(copy); //we must be locked
817 Q_ASSERT(copy != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed
818
819 if (futexAvailable()) {
820 d_ptr.storeRelease(nullptr);
821 return futexWakeOne(d_ptr);
822 }
823
824#if !defined(QT_ALWAYS_USE_FUTEX)
825 QMutexPrivate *d = reinterpret_cast<QMutexPrivate *>(copy);
826
827 // If no one is waiting for the lock anymore, we should reset d to 0x0.
828 // Using fetchAndAdd, we atomically check that waiters was equal to 0, and add a flag
829 // to the waiters variable (BigNumber). That way, we avoid the race in which waiters is
830 // incremented right after we checked, because we won't increment waiters if is
831 // equal to -BigNumber
832 if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) {
833 //there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0)
834 if (d_ptr.testAndSetRelease(d, 0)) {
835 // reset the possiblyUnlocked flag if needed (and deref its corresponding reference)
836 if (d->possiblyUnlocked.loadRelaxed() && d->possiblyUnlocked.testAndSetRelaxed(true, false))
837 d->deref();
838 }
839 d->derefWaiters(0);
840 } else {
841 d->derefWaiters(0);
842 //there are thread waiting, transfer the lock.
843 d->wakeUp();
844 }
845 d->deref();
846#else
847 Q_UNUSED(copy);
848#endif
849}
850
851#if !defined(QT_ALWAYS_USE_FUTEX)
852//The freelist management
853namespace {
854struct FreeListConstants : QFreeListDefaultConstants {
855 enum { BlockCount = 4, MaxIndex=0xffff };
856 static const int Sizes[BlockCount];
857};
858Q_CONSTINIT const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = {
859 16,
860 128,
861 1024,
862 FreeListConstants::MaxIndex - (16 + 128 + 1024)
863};
864
866// We cannot use Q_GLOBAL_STATIC because it uses QMutex
867Q_CONSTINIT static FreeList freeList_;
868FreeList *freelist()
869{
870 return &freeList_;
871}
872}
873
875{
876 int i = freelist()->next();
877 QMutexPrivate *d = &(*freelist())[i];
878 d->id = i;
879 Q_ASSERT(d->refCount.loadRelaxed() == 0);
880 Q_ASSERT(!d->possiblyUnlocked.loadRelaxed());
881 Q_ASSERT(d->waiters.loadRelaxed() == 0);
882 d->refCount.storeRelaxed(1);
883 return d;
884}
885
887{
891 freelist()->release(id);
892}
893
894// atomically subtract "value" to the waiters, and remove the QMutexPrivate::BigNumber flag
896{
897 int old_waiters;
898 int new_waiters;
899 do {
900 old_waiters = waiters.loadRelaxed();
901 new_waiters = old_waiters;
902 if (new_waiters < 0) {
903 new_waiters += QMutexPrivate::BigNumber;
904 }
905 new_waiters -= value;
906 } while (!waiters.testAndSetRelaxed(old_waiters, new_waiters));
907}
908#endif
909
911
912#if defined(QT_ALWAYS_USE_FUTEX)
913// nothing
914#elif defined(Q_OS_DARWIN)
915# include "qmutex_mac.cpp"
916#else
917# include "qmutex_unix.cpp"
918#endif
T loadRelaxed() const noexcept
\inmodule QtCore
void deref()
Definition qmutex_p.h:65
QAtomicInt waiters
Definition qmutex_p.h:75
void derefWaiters(int value) noexcept
Definition qmutex.cpp:895
static QMutexPrivate * allocate()
Definition qmutex.cpp:874
QAtomicInt possiblyUnlocked
Definition qmutex_p.h:76
QAtomicInt refCount
Definition qmutex_p.h:50
void release()
Definition qmutex.cpp:886
bool tryLock(int timeout=0) noexcept
Attempts to lock the mutex.
Definition qmutex.h:291
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:293
void lock() noexcept
Locks the mutex.
Definition qmutex.h:290
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition qthread.h:154
Combined button and popup list for selecting options.
void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
void futexWakeOne(Atomic &futex)
constexpr bool futexAvailable()
void mutexPostUnlock(void *, unsigned)
Definition qtsan_impl.h:73
void mutexPreUnlock(void *, unsigned)
Definition qtsan_impl.h:72
void mutexPreLock(void *, unsigned)
Definition qtsan_impl.h:70
void mutexPostLock(void *, unsigned, int)
Definition qtsan_impl.h:71
@ MutexWriteReentrant
Definition qtsan_impl.h:66
@ TryLockFailed
Definition qtsan_impl.h:68
@ TryLock
Definition qtsan_impl.h:67
void * HANDLE
QString self
Definition language.cpp:57
static jboolean copy(JNIEnv *, jobject)
#define Q_UNLIKELY(x)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:162
static QMutexPrivate * dummyFutexValue()
Definition qmutex.cpp:23
GLenum GLenum GLsizei count
GLbitfield GLuint64 timeout
[4]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define Q_UNUSED(x)
size_t quintptr
Definition qtypes.h:72
QMutex mutex
[2]