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