diff options
author | Liang Qi <liang.qi@qt.io> | 2017-10-17 17:24:01 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2017-10-17 18:29:37 +0000 |
commit | 7e4571b7e71736cb87cdcaa7eee1c38b18b6f5ae (patch) | |
tree | 01291174cba7d1c73b65142626f5da758941f5de /src/corelib | |
parent | 66119a07e840daae61629762ad3763abd0c16754 (diff) | |
parent | 01afc8c810201b93a12fe7030344e03566d99001 (diff) |
Merge "Merge remote-tracking branch 'origin/5.9' into 5.10" into refs/staging/5.10
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/global/global.pri | 23 | ||||
-rw-r--r-- | src/corelib/io/qurl.cpp | 31 | ||||
-rw-r--r-- | src/corelib/kernel/qcoreevent.cpp | 8 | ||||
-rw-r--r-- | src/corelib/thread/qthreadpool.cpp | 87 | ||||
-rw-r--r-- | src/corelib/thread/qthreadpool_p.h | 84 |
5 files changed, 176 insertions, 57 deletions
diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index 78b37755a4..7c31df4d6a 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -99,16 +99,13 @@ gcc:ltcg { SOURCES += $$VERSIONTAGGING_SOURCES } -# On AARCH64 the fp16 extension is mandatory, so we don't need the conversion tables. -!contains(QT_ARCH, "arm64") { - QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h - - qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables) - - qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT} - qfloat16_tables.output = global/qfloat16tables.cpp - qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES - qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE - qfloat16_tables.variable_out = SOURCES - QMAKE_EXTRA_COMPILERS += qfloat16_tables -} +QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h + +qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables) + +qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT} +qfloat16_tables.output = global/qfloat16tables.cpp +qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES +qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE +qfloat16_tables.variable_out = SOURCES +QMAKE_EXTRA_COMPILERS += qfloat16_tables diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index ac694a464a..a499dc2d30 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -499,9 +499,10 @@ public: InvalidFragmentError = Fragment << 8, - // the following two cases are only possible in combination - // with presence/absence of the authority and scheme. See validityError(). + // the following three cases are only possible in combination with + // presence/absence of the path, authority and scheme. See validityError(). AuthorityPresentAndPathIsRelative = Authority << 8 | Path << 8 | 0x10000, + AuthorityAbsentAndPathIsDoubleSlash, RelativeUrlPathContainsColonBeforeSlash = Scheme << 8 | Authority << 8 | Path << 8 | 0x10000, NoError = 0 @@ -1627,19 +1628,32 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p return error->code; } - // There are two more cases of invalid URLs that QUrl recognizes and they + // There are three more cases of invalid URLs that QUrl recognizes and they // are only possible with constructed URLs (setXXX methods), not with // parsing. Therefore, they are tested here. // - // The two cases are a non-empty path that doesn't start with a slash and: + // Two cases are a non-empty path that doesn't start with a slash and: // - with an authority // - without an authority, without scheme but the path with a colon before // the first slash + // The third case is an empty authority and a non-empty path that starts + // with "//". // Those cases are considered invalid because toString() would produce a URL // that wouldn't be parsed back to the same QUrl. - if (path.isEmpty() || path.at(0) == QLatin1Char('/')) + if (path.isEmpty()) return NoError; + if (path.at(0) == QLatin1Char('/')) { + if (sectionIsPresent & QUrlPrivate::Authority || port != -1 || + path.length() == 1 || path.at(1) != QLatin1Char('/')) + return NoError; + if (source) { + *source = path; + *position = 0; + } + return AuthorityAbsentAndPathIsDoubleSlash; + } + if (sectionIsPresent & QUrlPrivate::Host) { if (source) { *source = path; @@ -2514,10 +2528,7 @@ void QUrl::setPath(const QString &path, ParsingMode mode) mode = TolerantMode; } - int from = 0; - while (from < data.length() - 2 && data.midRef(from, 2) == QLatin1String("//")) - ++from; - d->setPath(data, from, data.length()); + d->setPath(data, 0, data.length()); // optimized out, since there is no path delimiter // if (path.isNull()) @@ -3989,6 +4000,8 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err case QUrlPrivate::AuthorityPresentAndPathIsRelative: return QStringLiteral("Path component is relative and authority is present"); + case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash: + return QStringLiteral("Path component starts with '//' and authority is absent"); case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash: return QStringLiteral("Relative URL's path component contains ':' before any '/'"); } diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index e90cd842ab..1e6b328c75 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -170,10 +170,10 @@ QT_BEGIN_NAMESPACE \value LeaveEditFocus An editor widget loses focus for editing. QT_KEYPAD_NAVIGATION must be defined. \value LeaveWhatsThisMode Send to toplevel widgets when the application leaves "What's This?" mode. \value LocaleChange The system locale has changed. - \value NonClientAreaMouseButtonDblClick A mouse double click occurred outside the client area. - \value NonClientAreaMouseButtonPress A mouse button press occurred outside the client area. - \value NonClientAreaMouseButtonRelease A mouse button release occurred outside the client area. - \value NonClientAreaMouseMove A mouse move occurred outside the client area. + \value NonClientAreaMouseButtonDblClick A mouse double click occurred outside the client area (QMouseEvent). + \value NonClientAreaMouseButtonPress A mouse button press occurred outside the client area (QMouseEvent). + \value NonClientAreaMouseButtonRelease A mouse button release occurred outside the client area (QMouseEvent). + \value NonClientAreaMouseMove A mouse move occurred outside the client area (QMouseEvent). \value MacSizeChange The user changed his widget sizes (\macos only). \value MetaCall An asynchronous method invocation via QMetaObject::invokeMethod(). \value ModifiedChange Widgets modification state has been changed. diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index ba46d98cf9..8eca3b56e4 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -73,7 +73,7 @@ public: \internal */ QThreadPoolThread::QThreadPoolThread(QThreadPoolPrivate *manager) - :manager(manager), runnable(0) + :manager(manager), runnable(nullptr) { setStackSize(manager->stackSize); } @@ -86,7 +86,7 @@ void QThreadPoolThread::run() QMutexLocker locker(&manager->mutex); for(;;) { QRunnable *r = runnable; - runnable = 0; + runnable = nullptr; do { if (r) { @@ -118,8 +118,19 @@ void QThreadPoolThread::run() if (manager->tooManyThreadsActive()) break; - r = !manager->queue.isEmpty() ? manager->queue.takeFirst().first : 0; - } while (r != 0); + if (manager->queue.isEmpty()) { + r = nullptr; + break; + } + + QueuePage *page = manager->queue.first(); + r = page->pop(); + + if (page->isFinished()) { + manager->queue.removeFirst(); + delete page; + } + } while (true); if (manager->isExiting) { registerThreadInactive(); @@ -160,6 +171,7 @@ QThreadPoolPrivate:: QThreadPoolPrivate() bool QThreadPoolPrivate::tryStart(QRunnable *task) { + Q_ASSERT(task != nullptr); if (allThreads.isEmpty()) { // always create at least one thread startThread(task); @@ -180,7 +192,7 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task) if (!expiredThreads.isEmpty()) { // restart an expired thread QThreadPoolThread *thread = expiredThreads.dequeue(); - Q_ASSERT(thread->runnable == 0); + Q_ASSERT(thread->runnable == nullptr); ++activeThreads; @@ -196,22 +208,25 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task) return true; } -inline bool operator<(int priority, const QPair<QRunnable *, int> &p) -{ return p.second < priority; } -inline bool operator<(const QPair<QRunnable *, int> &p, int priority) -{ return priority < p.second; } +inline bool comparePriority(int priority, const QueuePage *p) +{ + return p->priority() < priority; +} void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) { + Q_ASSERT(runnable != nullptr); if (runnable->autoDelete()) ++runnable->ref; - // put it on the queue - QVector<QPair<QRunnable *, int> >::const_iterator begin = queue.constBegin(); - QVector<QPair<QRunnable *, int> >::const_iterator it = queue.constEnd(); - if (it != begin && priority > (*(it - 1)).second) - it = std::upper_bound(begin, --it, priority); - queue.insert(it - begin, qMakePair(runnable, priority)); + for (QueuePage *page : qAsConst(queue)) { + if (page->priority() == priority && !page->isFull()) { + page->push(runnable); + return; + } + } + auto it = std::upper_bound(queue.constBegin(), queue.constEnd(), priority, comparePriority); + queue.insert(std::distance(queue.constBegin(), it), new QueuePage(runnable, priority)); } int QThreadPoolPrivate::activeThreadCount() const @@ -225,8 +240,18 @@ int QThreadPoolPrivate::activeThreadCount() const void QThreadPoolPrivate::tryToStartMoreThreads() { // try to push tasks on the queue to any available threads - while (!queue.isEmpty() && tryStart(queue.constFirst().first)) - queue.removeFirst(); + while (!queue.isEmpty()) { + QueuePage *page = queue.first(); + if (!tryStart(page->first())) + break; + + page->pop(); + + if (page->isFinished()) { + queue.removeFirst(); + delete page; + } + } } bool QThreadPoolPrivate::tooManyThreadsActive() const @@ -240,6 +265,7 @@ bool QThreadPoolPrivate::tooManyThreadsActive() const */ void QThreadPoolPrivate::startThread(QRunnable *runnable) { + Q_ASSERT(runnable != nullptr); QScopedPointer <QThreadPoolThread> thread(new QThreadPoolThread(this)); thread->setObjectName(QLatin1String("Thread (pooled)")); Q_ASSERT(!allThreads.contains(thread.data())); // if this assert hits, we have an ABA problem (deleted threads don't get removed here) @@ -303,12 +329,14 @@ bool QThreadPoolPrivate::waitForDone(int msecs) void QThreadPoolPrivate::clear() { QMutexLocker locker(&mutex); - for (QVector<QPair<QRunnable *, int> >::const_iterator it = queue.constBegin(); - it != queue.constEnd(); ++it) { - QRunnable* r = it->first; - if (r->autoDelete() && !--r->ref) - delete r; + for (QueuePage *page : qAsConst(queue)) { + while (!page->isFinished()) { + QRunnable *r = page->pop(); + if (r && r->autoDelete() && !--r->ref) + delete r; + } } + qDeleteAll(queue); queue.clear(); } @@ -333,22 +361,21 @@ bool QThreadPool::tryTake(QRunnable *runnable) { Q_D(QThreadPool); - if (runnable == 0) + if (runnable == nullptr) return false; { QMutexLocker locker(&d->mutex); - auto it = d->queue.begin(); - auto end = d->queue.end(); - - while (it != end) { - if (it->first == runnable) { - d->queue.erase(it); + for (QueuePage *page : qAsConst(d->queue)) { + if (page->tryTake(runnable)) { + if (page->isFinished()) { + d->queue.removeOne(page); + delete page; + } if (runnable->autoDelete()) --runnable->ref; // undo ++ref in start() return true; } - ++it; } } diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h index 8b6a8cc476..d03ba9d77f 100644 --- a/src/corelib/thread/qthreadpool_p.h +++ b/src/corelib/thread/qthreadpool_p.h @@ -63,6 +63,87 @@ QT_BEGIN_NAMESPACE +class QueuePage { +public: + enum { + MaxPageSize = 256 + }; + + QueuePage(QRunnable *runnable, int pri) + : m_priority(pri) + { + push(runnable); + } + + bool isFull() { + return m_lastIndex >= MaxPageSize - 1; + } + + bool isFinished() { + return m_firstIndex > m_lastIndex; + } + + void push(QRunnable *runnable) { + Q_ASSERT(runnable != nullptr); + Q_ASSERT(!isFull()); + m_lastIndex += 1; + m_entries[m_lastIndex] = runnable; + } + + void skipToNextOrEnd() { + while (!isFinished() && m_entries[m_firstIndex] == nullptr) { + m_firstIndex += 1; + } + } + + QRunnable *first() { + Q_ASSERT(!isFinished()); + QRunnable *runnable = m_entries[m_firstIndex]; + Q_ASSERT(runnable); + return runnable; + } + + QRunnable *pop() { + Q_ASSERT(!isFinished()); + QRunnable *runnable = first(); + Q_ASSERT(runnable); + + // clear the entry although this should not be necessary + m_entries[m_firstIndex] = nullptr; + m_firstIndex += 1; + + // make sure the next runnable returned by first() is not a nullptr + skipToNextOrEnd(); + + return runnable; + } + + bool tryTake(QRunnable *runnable) { + Q_ASSERT(!isFinished()); + for (int i = m_firstIndex; i <= m_lastIndex; i++) { + if (m_entries[i] == runnable) { + m_entries[i] = nullptr; + if (i == m_firstIndex) { + // make sure first() does not return a nullptr + skipToNextOrEnd(); + } + return true; + } + } + return false; + } + + int priority() const { + return m_priority; + } + +private: + int m_priority = 0; + int m_firstIndex = 0; + int m_lastIndex = -1; + QRunnable *m_entries[MaxPageSize]; +}; + class QThreadPoolThread; class Q_CORE_EXPORT QThreadPoolPrivate : public QObjectPrivate { @@ -84,12 +165,13 @@ public: bool waitForDone(int msecs); void clear(); void stealAndRunRunnable(QRunnable *runnable); + void deletePageIfFinished(QueuePage *page); mutable QMutex mutex; QList<QThreadPoolThread *> allThreads; QQueue<QThreadPoolThread *> waitingThreads; QQueue<QThreadPoolThread *> expiredThreads; - QVector<QPair<QRunnable *, int> > queue; + QVector<QueuePage*> queue; QWaitCondition noActiveThreads; int expiryTimeout = 30000; |