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 */
640void QBasicMutex::lockInternal() QT_MUTEX_LOCK_NOEXCEPT
641{
642 if (futexAvailable()) {
643 // note we must set to dummyFutexValue because there could be other threads
644 // also waiting
645 while (d_ptr.fetchAndStoreAcquire(newValue: dummyFutexValue()) != nullptr) {
646 // successfully set the waiting bit, now sleep
647 futexWait(futex&: d_ptr, expectedValue: dummyFutexValue());
648
649 // we got woken up, so try to acquire the mutex
650 }
651 Q_ASSERT(d_ptr.loadRelaxed());
652 } else {
653 lockInternal(timeout: -1);
654 }
655}
656
657/*!
658 \internal helper for lock(int)
659 */
660#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
661bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
662{
663 if (timeout == 0)
664 return false;
665
666 return lockInternal(timeout: QDeadlineTimer(timeout));
667}
668#endif
669
670/*!
671 \internal helper for tryLock(QDeadlineTimer)
672 */
673bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT
674{
675 if (deadlineTimer.hasExpired())
676 return false;
677
678 if (futexAvailable()) {
679 if (Q_UNLIKELY(deadlineTimer.isForever())) {
680 lockInternal();
681 return true;
682 }
683
684 // The mutex is already locked, set a bit indicating we're waiting.
685 // Note we must set to dummyFutexValue because there could be other threads
686 // also waiting.
687 if (d_ptr.fetchAndStoreAcquire(newValue: dummyFutexValue()) == nullptr)
688 return true;
689
690 for (;;) {
691 if (!futexWait(futex&: d_ptr, expectedValue: dummyFutexValue(), deadline: deadlineTimer))
692 return false;
693
694 // We got woken up, so must try to acquire the mutex. We must set
695 // to dummyFutexValue() again because there could be other threads
696 // waiting.
697 if (d_ptr.fetchAndStoreAcquire(newValue: dummyFutexValue()) == nullptr)
698 return true;
699
700 if (deadlineTimer.hasExpired())
701 return false;
702 }
703 }
704
705#if !defined(QT_ALWAYS_USE_FUTEX)
706 while (!fastTryLock()) {
707 QMutexPrivate *copy = d_ptr.loadAcquire();
708 if (!copy) // if d is 0, the mutex is unlocked
709 continue;
710
711 if (copy == dummyLocked()) {
712 if (deadlineTimer.hasExpired())
713 return false;
714 // The mutex is locked but does not have a QMutexPrivate yet.
715 // we need to allocate a QMutexPrivate
716 QMutexPrivate *newD = QMutexPrivate::allocate();
717 if (!d_ptr.testAndSetOrdered(dummyLocked(), newD)) {
718 //Either the mutex is already unlocked, or another thread already set it.
719 newD->deref();
720 continue;
721 }
722 copy = newD;
723 //the d->refCount is already 1 the deref will occurs when we unlock
724 }
725
726 QMutexPrivate *d = static_cast<QMutexPrivate *>(copy);
727 if (deadlineTimer.hasExpired() && !d->possiblyUnlocked.loadRelaxed())
728 return false;
729
730 // At this point we have a pointer to a QMutexPrivate. But the other thread
731 // may unlock the mutex at any moment and release the QMutexPrivate to the pool.
732 // We will try to reference it to avoid unlock to release it to the pool to make
733 // sure it won't be released. But if the refcount is already 0 it has been released.
734 if (!d->ref())
735 continue; //that QMutexPrivate was already released
736
737 // We now hold a reference to the QMutexPrivate. It won't be released and re-used.
738 // But it is still possible that it was already re-used by another QMutex right before
739 // we did the ref(). So check if we still hold a pointer to the right mutex.
740 if (d != d_ptr.loadAcquire()) {
741 //Either the mutex is already unlocked, or relocked with another mutex
742 d->deref();
743 continue;
744 }
745
746 // In this part, we will try to increment the waiters count.
747 // We just need to take care of the case in which the old_waiters
748 // is set to the BigNumber magic value set in unlockInternal()
749 int old_waiters;
750 do {
751 old_waiters = d->waiters.loadAcquire();
752 if (old_waiters == -QMutexPrivate::BigNumber) {
753 // we are unlocking, and the thread that unlocks is about to change d to 0
754 // we try to acquire the mutex by changing to dummyLocked()
755 if (d_ptr.testAndSetAcquire(d, dummyLocked())) {
756 // Mutex acquired
757 d->deref();
758 return true;
759 } else {
760 Q_ASSERT(d != d_ptr.loadRelaxed()); //else testAndSetAcquire should have succeeded
761 // Mutex is likely to bo 0, we should continue the outer-loop,
762 // set old_waiters to the magic value of BigNumber
763 old_waiters = QMutexPrivate::BigNumber;
764 break;
765 }
766 }
767 } while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1));
768
769 if (d != d_ptr.loadAcquire()) {
770 // The mutex was unlocked before we incremented waiters.
771 if (old_waiters != QMutexPrivate::BigNumber) {
772 //we did not break the previous loop
773 Q_ASSERT(d->waiters.loadRelaxed() >= 1);
774 d->waiters.deref();
775 }
776 d->deref();
777 continue;
778 }
779
780 if (d->wait(deadlineTimer)) {
781 // reset the possiblyUnlocked flag if needed (and deref its corresponding reference)
782 if (d->possiblyUnlocked.loadRelaxed() && d->possiblyUnlocked.testAndSetRelaxed(true, false))
783 d->deref();
784 d->derefWaiters(1);
785 //we got the lock. (do not deref)
786 Q_ASSERT(d == d_ptr.loadRelaxed());
787 return true;
788 } else {
789 // timed out
790 d->derefWaiters(1);
791 //There may be a race in which the mutex is unlocked right after we timed out,
792 // and before we deref the waiters, so maybe the mutex is actually unlocked.
793 // Set the possiblyUnlocked flag to indicate this possibility.
794 if (!d->possiblyUnlocked.testAndSetRelaxed(false, true)) {
795 // We keep a reference when possiblyUnlocked is true.
796 // but if possiblyUnlocked was already true, we don't need to keep the reference.
797 d->deref();
798 }
799 return false;
800 }
801 }
802 Q_ASSERT(d_ptr.loadRelaxed() != 0);
803 return true;
804#else
805 Q_UNREACHABLE();
806#endif
807}
808
809/*!
810 \internal
811*/
812void QBasicMutex::unlockInternal() noexcept
813{
814 QMutexPrivate *copy = d_ptr.loadAcquire();
815 Q_ASSERT(copy); //we must be locked
816 Q_ASSERT(copy != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed
817
818 if (futexAvailable()) {
819 d_ptr.storeRelease(newValue: nullptr);
820 return futexWakeOne(futex&: d_ptr);
821 }
822
823#if !defined(QT_ALWAYS_USE_FUTEX)
824 QMutexPrivate *d = reinterpret_cast<QMutexPrivate *>(copy);
825
826 // If no one is waiting for the lock anymore, we should reset d to 0x0.
827 // Using fetchAndAdd, we atomically check that waiters was equal to 0, and add a flag
828 // to the waiters variable (BigNumber). That way, we avoid the race in which waiters is
829 // incremented right after we checked, because we won't increment waiters if is
830 // equal to -BigNumber
831 if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) {
832 //there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0)
833 if (d_ptr.testAndSetRelease(d, 0)) {
834 // reset the possiblyUnlocked flag if needed (and deref its corresponding reference)
835 if (d->possiblyUnlocked.loadRelaxed() && d->possiblyUnlocked.testAndSetRelaxed(true, false))
836 d->deref();
837 }
838 d->derefWaiters(0);
839 } else {
840 d->derefWaiters(0);
841 //there are thread waiting, transfer the lock.
842 d->wakeUp();
843 }
844 d->deref();
845#else
846 Q_UNUSED(copy);
847#endif
848}
849
850#if !defined(QT_ALWAYS_USE_FUTEX)
851//The freelist management
852namespace {
853struct FreeListConstants : QFreeListDefaultConstants {
854 enum { BlockCount = 4, MaxIndex=0xffff };
855 static const int Sizes[BlockCount];
856};
857Q_CONSTINIT const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = {
858 16,
859 128,
860 1024,
861 FreeListConstants::MaxIndex - (16 + 128 + 1024)
862};
863
864typedef QFreeList<QMutexPrivate, FreeListConstants> FreeList;
865// We cannot use Q_GLOBAL_STATIC because it uses QMutex
866Q_CONSTINIT static FreeList freeList_;
867FreeList *freelist()
868{
869 return &freeList_;
870}
871}
872
873QMutexPrivate *QMutexPrivate::allocate()
874{
875 int i = freelist()->next();
876 QMutexPrivate *d = &(*freelist())[i];
877 d->id = i;
878 Q_ASSERT(d->refCount.loadRelaxed() == 0);
879 Q_ASSERT(!d->possiblyUnlocked.loadRelaxed());
880 Q_ASSERT(d->waiters.loadRelaxed() == 0);
881 d->refCount.storeRelaxed(1);
882 return d;
883}
884
885void QMutexPrivate::release()
886{
887 Q_ASSERT(refCount.loadRelaxed() == 0);
888 Q_ASSERT(!possiblyUnlocked.loadRelaxed());
889 Q_ASSERT(waiters.loadRelaxed() == 0);
890 freelist()->release(id);
891}
892
893// atomically subtract "value" to the waiters, and remove the QMutexPrivate::BigNumber flag
894void QMutexPrivate::derefWaiters(int value) noexcept
895{
896 int old_waiters;
897 int new_waiters;
898 do {
899 old_waiters = waiters.loadRelaxed();
900 new_waiters = old_waiters;
901 if (new_waiters < 0) {
902 new_waiters += QMutexPrivate::BigNumber;
903 }
904 new_waiters -= value;
905 } while (!waiters.testAndSetRelaxed(old_waiters, new_waiters));
906}
907#endif
908
909QT_END_NAMESPACE
910
911#if defined(QT_ALWAYS_USE_FUTEX)
912// nothing
913#elif defined(Q_OS_DARWIN)
914# include "qmutex_mac.cpp"
915#else
916# include "qmutex_unix.cpp"
917#endif
918

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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