OSDN Git Service

make use of std::timed_mutex and std::recursive_timed_mutex in QMutexPrivate
authorIvailo Monev <xakepa10@laimg.moc>
Thu, 23 May 2019 20:32:36 +0000 (20:32 +0000)
committerIvailo Monev <xakepa10@laimg.moc>
Thu, 23 May 2019 20:32:36 +0000 (20:32 +0000)
Signed-off-by: Ivailo Monev <xakepa10@laimg.moc>
src/core/kernel/qobject.cpp
src/core/thread/qmutex.cpp
src/core/thread/qmutex.h
src/core/thread/qmutex_p.h
src/core/thread/qmutex_unix.cpp [deleted file]
src/core/thread/qorderedmutexlocker_p.h
src/core/thread/thread.cmake

index d44af5d..14e9ffc 100644 (file)
@@ -690,7 +690,7 @@ QObject::~QObject()
                         if (c->next) c->next->prev = c->prev;
                     }
                     if (needToUnlock)
-                        m->unlockInline();
+                        m->unlock();
 
                     connectionList.first = c->nextConnectionList;
                     delete c;
@@ -714,7 +714,7 @@ QObject::~QObject()
             bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
             //the node has maybe been removed while the mutex was unlocked in relock?
             if (!node || node->sender != sender) {
-                m->unlockInline();
+                m->unlock();
                 continue;
             }
             node->receiver = 0;
@@ -724,7 +724,7 @@ QObject::~QObject()
 
             node = node->next;
             if (needToUnlock)
-                m->unlockInline();
+                m->unlock();
         }
     }
 
@@ -2770,7 +2770,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c,
             }
 
             if (needToUnlock)
-                receiverMutex->unlockInline();
+                receiverMutex->unlock();
 
             c->receiver = 0;
 
index 57e2522..ce44a24 100644 (file)
 #include <qdebug.h>
 
 #ifndef QT_NO_THREAD
-#include "qatomic.h"
-#include "qelapsedtimer.h"
-#include "qthread.h"
 #include "qmutex_p.h"
 
 QT_BEGIN_NAMESPACE
 
+QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
+    : recursive(mode == QMutex::Recursive)
+{
+}
+
 /*!
     \class QMutex
     \brief The QMutex class provides access serialization between threads.
@@ -148,32 +150,10 @@ QMutex::~QMutex()
 void QMutex::lock()
 {
     QMutexPrivate *d = this->d;
-
     if (d->recursive) {
-        Qt::HANDLE self = QThread::currentThreadId();
-        if (d->owner == self) {
-            ++d->count;
-            Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter");
-            return;
-        }
-
-        bool isLocked = d->contenders.testAndSetAcquire(0, 1);
-        if (!isLocked) {
-            // didn't get the lock, wait for it
-            isLocked = d->wait();
-            Q_ASSERT_X(isLocked, "QMutex::lock",
-                       "Internal error, infinite wait has timed out.");
-        }
-
-        d->owner = self;
-        ++d->count;
-        Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter");
-        return;
-    }
-
-    bool isLocked = d->contenders.testAndSetAcquire(0, 1);
-    if (!isLocked) {
-        lockInternal();
+        d->mutex2.lock();
+    } else {
+        d->mutex1.lock();
     }
 }
 
@@ -197,29 +177,11 @@ void QMutex::lock()
 bool QMutex::tryLock()
 {
     QMutexPrivate *d = this->d;
-
     if (d->recursive) {
-        Qt::HANDLE self = QThread::currentThreadId();
-        if (d->owner == self) {
-            ++d->count;
-            Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
-            return true;
-        }
-
-        bool isLocked = d->contenders.testAndSetAcquire(0, 1);
-        if (!isLocked) {
-            // some other thread has the mutex locked, or we tried to
-            // recursively lock an non-recursive mutex
-            return isLocked;
-        }
-
-        d->owner = self;
-        ++d->count;
-        Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
-        return isLocked;
+        return d->mutex2.try_lock();
+    } else {
+        return d->mutex1.try_lock();
     }
-
-    return d->contenders.testAndSetAcquire(0, 1);
 }
 
 /*! \overload
@@ -248,32 +210,11 @@ bool QMutex::tryLock()
 bool QMutex::tryLock(int timeout)
 {
     QMutexPrivate *d = this->d;
-
     if (d->recursive) {
-        Qt::HANDLE self = QThread::currentThreadId();
-        if (d->owner == self) {
-            ++d->count;
-            Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
-            return true;
-        }
-
-        bool isLocked = d->contenders.testAndSetAcquire(0, 1);
-        if (!isLocked) {
-            // didn't get the lock, wait for it
-            isLocked = d->wait(timeout);
-            if (!isLocked)
-                return false;
-        }
-
-        d->owner = self;
-        ++d->count;
-        Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
-        return true;
+        return d->mutex2.try_lock_for(std::chrono::milliseconds(timeout));
+    } else {
+        return d->mutex1.try_lock_for(std::chrono::milliseconds(timeout));
     }
-
-    return (d->contenders.testAndSetAcquire(0, 1)
-            // didn't get the lock, wait for it
-            || d->wait(timeout));
 }
 
 
@@ -288,14 +229,9 @@ void QMutex::unlock()
 {
     QMutexPrivate *d = this->d;
     if (d->recursive) {
-        if (!--d->count) {
-            d->owner = 0;
-            if (!d->contenders.testAndSetRelease(1, 0))
-                d->wakeUp();
-        }
+        d->mutex2.unlock();
     } else {
-        if (!d->contenders.testAndSetRelease(1, 0))
-            d->wakeUp();
+        d->mutex1.unlock();
     }
 }
 
@@ -421,85 +357,6 @@ void QMutex::unlock()
     Use the constructor that takes a RecursionMode parameter instead.
 */
 
-/*!
-    \internal helper for lockInline()
- */
-void QMutex::lockInternal()
-{
-    QMutexPrivate *d = this->d;
-
-    if (QThread::idealThreadCount() == 1) {
-        // don't spin on single cpu machines
-        bool isLocked = d->wait();
-        Q_ASSERT_X(isLocked, "QMutex::lock",
-                   "Internal error, infinite wait has timed out.");
-        Q_UNUSED(isLocked);
-        return;
-    }
-
-    QElapsedTimer elapsedTimer;
-    elapsedTimer.start();
-    do {
-        qint64 spinTime = elapsedTimer.nsecsElapsed();
-        if (spinTime > d->maximumSpinTime) {
-            // didn't get the lock, wait for it, since we're not going to gain anything by spinning more
-            elapsedTimer.start();
-            bool isLocked = d->wait();
-            Q_ASSERT_X(isLocked, "QMutex::lock",
-                       "Internal error, infinite wait has timed out.");
-            Q_UNUSED(isLocked);
-
-            qint64 maximumSpinTime = d->maximumSpinTime;
-            qint64 averageWaitTime = d->averageWaitTime;
-            qint64 actualWaitTime = elapsedTimer.nsecsElapsed();
-            if (actualWaitTime < (QMutexPrivate::MaximumSpinTimeThreshold * 3 / 2)) {
-                // measure the wait times
-                averageWaitTime = d->averageWaitTime = qMin((averageWaitTime + actualWaitTime) / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
-            }
-
-            // adjust the spin count when spinning does not benefit contention performance
-            if ((spinTime + actualWaitTime) - qint64(QMutexPrivate::MaximumSpinTimeThreshold) >= qint64(QMutexPrivate::MaximumSpinTimeThreshold)) {
-                // long waits, stop spinning
-                d->maximumSpinTime = 0;
-            } else {
-                // allow spinning if wait times decrease, but never spin more than the average wait time (otherwise we may perform worse)
-                d->maximumSpinTime = qBound(qint64(averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
-            }
-            return;
-        }
-        // be a good citizen... yielding lets something else run if there is something to run, but may also relieve memory pressure if not
-        QThread::yieldCurrentThread();
-    } while (d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1));
-
-    // spinning is working, do not change the spin time (unless we are using much less time than allowed to spin)
-    qint64 maximumSpinTime = d->maximumSpinTime;
-    qint64 spinTime = elapsedTimer.nsecsElapsed();
-    if (spinTime < maximumSpinTime / 2) {
-        // we are using much less time than we need, adjust the limit
-        d->maximumSpinTime = qBound(qint64(d->averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
-    }
-}
-
-
-/*!
-   \fn QMutex::lockInline()
-   \internal
-   inline version of QMutex::lock()
-*/
-
-/*!
-   \fn QMutex::unlockInline()
-   \internal
-   inline version of QMutex::unlock()
-*/
-
-/*!
-   \fn QMutex::tryLockInline()
-   \internal
-   inline version of QMutex::tryLock()
-*/
-
-
 QT_END_NAMESPACE
 
 #endif // QT_NO_THREAD
index cfdffd8..0036888 100644 (file)
@@ -59,22 +59,20 @@ class Q_CORE_EXPORT QMutex
     friend class QWaitConditionPrivate;
 
 public:
-    enum RecursionMode { NonRecursive, Recursive };
+    enum RecursionMode {
+        NonRecursive,
+        Recursive
+    };
 
     explicit QMutex(RecursionMode mode = NonRecursive);
     ~QMutex();
 
     void lock();
-    inline void unlockInline() { unlock(); }
     bool tryLock();
     bool tryLock(int timeout);
-    inline bool tryLockInline() { return tryLock(); }
     void unlock();
-    inline void lockInline() { lock(); }
-
 
 private:
-    void lockInternal();
     Q_DISABLE_COPY(QMutex)
 
     QMutexPrivate *d;
@@ -138,12 +136,8 @@ public:
     inline ~QMutex() {}
 
     static inline void lock() {}
-    static inline void lockInline() {}
     static inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; }
-    static inline bool tryLockInline() { return true; }
     static inline void unlock() {}
-    static inline void unlockInline() {}
-
 
 private:
     Q_DISABLE_COPY(QMutex)
index dac7f41..58d28b5 100644 (file)
 #include <QtCore/qnamespace.h>
 #include <QtCore/qmutex.h>
 
+#include <mutex>
 
 QT_BEGIN_NAMESPACE
 
 class QMutexPrivate {
 public:
     QMutexPrivate(QMutex::RecursionMode mode);
-    ~QMutexPrivate();
 
-    bool wait(int timeout = -1);
-    void wakeUp();
-
-    // 1ms = 1000000ns
-    enum { MaximumSpinTimeThreshold = 1000000 };
-    volatile qint64 maximumSpinTime;
-    volatile qint64 averageWaitTime;
-    Qt::HANDLE owner;
-    uint count;
     const bool recursive;
-    QAtomicInt contenders;
-
-    volatile bool wakeup;
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
+    std::timed_mutex mutex1;
+    std::recursive_timed_mutex mutex2;
 };
 
 QT_END_NAMESPACE
diff --git a/src/core/thread/qmutex_unix.cpp b/src/core/thread/qmutex_unix.cpp
deleted file mode 100644 (file)
index 0c2fe62..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qplatformdefs.h"
-#include "qmutex.h"
-#include "qstring.h"
-
-#ifndef QT_NO_THREAD
-#include "qatomic.h"
-#include "qmutex_p.h"
-#include "qcorecommon_p.h"
-
-#include <errno.h>
-
-QT_BEGIN_NAMESPACE
-
-QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
-    : maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0), recursive(mode == QMutex::Recursive)
-{
-    wakeup = false;
-    report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init");
-    report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init");
-}
-
-QMutexPrivate::~QMutexPrivate()
-{
-    report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy");
-    report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy");
-}
-
-bool QMutexPrivate::wait(int timeout)
-{
-    if (contenders.fetchAndAddAcquire(1) == 0) {
-        // lock acquired without waiting
-        return true;
-    }
-    report_error(pthread_mutex_lock(&mutex), "QMutex::lock", "mutex lock");
-    int errorCode = 0;
-    while (!wakeup) {
-        if (timeout < 0) {
-            errorCode = pthread_cond_wait(&cond, &mutex);
-        } else {
-            struct timeval tv;
-            gettimeofday(&tv, Q_NULLPTR);
-
-            timespec ti;
-            ti.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000;
-            ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000);
-            ti.tv_nsec %= 1000000000;
-
-            errorCode = pthread_cond_timedwait(&cond, &mutex, &ti);
-        }
-        if (errorCode) {
-            if (errorCode == ETIMEDOUT) {
-                if (wakeup)
-                    errorCode = 0;
-                break;
-            }
-            report_error(errorCode, "QMutex::lock()", "cv wait");
-        }
-    }
-    wakeup = false;
-    report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock");
-    contenders.deref();
-    return errorCode == 0;
-}
-
-void QMutexPrivate::wakeUp()
-{
-    report_error(pthread_mutex_lock(&mutex), "QMutex::unlock", "mutex lock");
-    wakeup = true;
-    report_error(pthread_cond_signal(&cond), "QMutex::unlock", "cv signal");
-    report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock");
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_THREAD
index 41055e5..6260d84 100644 (file)
@@ -79,8 +79,8 @@ public:
     void relock()
     {
         if (!locked) {
-            if (mtx1) mtx1->lockInline();
-            if (mtx2) mtx2->lockInline();
+            if (mtx1) mtx1->lock();
+            if (mtx2) mtx2->lock();
             locked = true;
         }
     }
@@ -88,8 +88,8 @@ public:
     void unlock()
     {
         if (locked) {
-            if (mtx1) mtx1->unlockInline();
-            if (mtx2) mtx2->unlockInline();
+            if (mtx1) mtx1->unlock();
+            if (mtx2) mtx2->unlock();
             locked = false;
         }
     }
@@ -100,10 +100,10 @@ public:
         if (mtx1 == mtx2)
             return false;
         if (mtx1 < mtx2) {
-            mtx2->lockInline();
+            mtx2->lock();
             return true;
         }
-        if (!mtx2->tryLockInline()) {
+        if (!mtx2->tryLock()) {
             mtx1->unlock();
             mtx2->lock();
             mtx1->lock();
index a7edac5..9346e1d 100644 (file)
@@ -22,7 +22,6 @@ set(CORE_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/thread/qmutexpool.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/thread/qsemaphore.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/thread/qthread.cpp
-    ${CMAKE_CURRENT_SOURCE_DIR}/thread/qmutex_unix.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/thread/qthread_unix.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/thread/qwaitcondition_unix.cpp
 )