diff options
| -rw-r--r-- | src/corelib/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | src/corelib/io/qiooperation_p_p.h | 4 | ||||
| -rw-r--r-- | src/corelib/io/qrandomaccessasyncfile_p_p.h | 14 | ||||
| -rw-r--r-- | src/corelib/io/qrandomaccessasyncfile_qioring.cpp | 438 | ||||
| -rw-r--r-- | src/corelib/tools/qlist.h | 23 | ||||
| -rw-r--r-- | src/plugins/platforms/wayland/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/plugins/platforms/wayland/qwaylanddisplay.cpp | 2 | ||||
| -rw-r--r-- | src/plugins/platforms/wayland/qwaylandeventdispatcher.cpp | 55 | ||||
| -rw-r--r-- | src/plugins/platforms/wayland/qwaylandeventdispatcher_p.h | 68 | ||||
| -rw-r--r-- | src/plugins/platforms/wayland/qwaylandintegration.cpp | 4 | ||||
| -rw-r--r-- | tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp | 22 | ||||
| -rw-r--r-- | tests/auto/corelib/tools/qlist/tst_qlist.cpp | 33 |
12 files changed, 532 insertions, 139 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index eda3152d9b7..e12d824cebb 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -583,6 +583,13 @@ if(QT_FEATURE_async_io) SOURCES io/qrandomaccessasyncfile_darwin.mm ) + elseif(LINUX AND QT_FEATURE_liburing) + qt_internal_extend_target(Core + SOURCES + io/qrandomaccessasyncfile_qioring.cpp + DEFINES + QT_RANDOMACCESSASYNCFILE_QIORING + ) elseif(QT_FEATURE_thread AND QT_FEATURE_future) # TODO: This should become the last (fallback) condition later. # We migth also want to rewrite it so that it does not depend on diff --git a/src/corelib/io/qiooperation_p_p.h b/src/corelib/io/qiooperation_p_p.h index 470e0858fd3..be780d4c785 100644 --- a/src/corelib/io/qiooperation_p_p.h +++ b/src/corelib/io/qiooperation_p_p.h @@ -24,6 +24,10 @@ #include <QtCore/qspan.h> #include <QtCore/qvarlengtharray.h> +#ifdef QT_RANDOMACCESSASYNCFILE_QIORING +#include <QtCore/private/qioring_p.h> +#endif + #include <variant> QT_BEGIN_NAMESPACE diff --git a/src/corelib/io/qrandomaccessasyncfile_p_p.h b/src/corelib/io/qrandomaccessasyncfile_p_p.h index 924c9f9ed83..11ad788c884 100644 --- a/src/corelib/io/qrandomaccessasyncfile_p_p.h +++ b/src/corelib/io/qrandomaccessasyncfile_p_p.h @@ -43,6 +43,11 @@ #endif // Q_OS_DARWIN +#ifdef QT_RANDOMACCESSASYNCFILE_QIORING +#include <QtCore/private/qioring_p.h> +#include <QtCore/qlist.h> +#endif + QT_BEGIN_NAMESPACE class QRandomAccessAsyncFilePrivate : public QObjectPrivate @@ -114,6 +119,15 @@ private: void processFlush(); void processOpen(); void operationComplete(); +#elif defined(QT_RANDOMACCESSASYNCFILE_QIORING) + void queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error); + void startReadIntoSingle(QIOOperation *op, const QSpan<std::byte> &to); + void startWriteFromSingle(QIOOperation *op, const QSpan<const std::byte> &from); + QIORing::RequestHandle cancel(QIORing::RequestHandle handle); + QIORing *m_ioring = nullptr; + qintptr m_fd = -1; + QList<QPointer<QIOOperation>> m_operations; + QHash<QIOOperation *, QIORing::RequestHandle> m_opHandleMap; #endif #ifdef Q_OS_DARWIN using OperationId = quint64; diff --git a/src/corelib/io/qrandomaccessasyncfile_qioring.cpp b/src/corelib/io/qrandomaccessasyncfile_qioring.cpp new file mode 100644 index 00000000000..c9783ea2856 --- /dev/null +++ b/src/corelib/io/qrandomaccessasyncfile_qioring.cpp @@ -0,0 +1,438 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default + +#include "qrandomaccessasyncfile_p_p.h" + +#include "qiooperation_p.h" +#include "qiooperation_p_p.h" + +#include <QtCore/qfile.h> // QtPrivate::toFilesystemPath +#include <QtCore/qtypes.h> +#include <QtCore/private/qioring_p.h> + +#include <QtCore/q26numeric.h> + +QT_BEGIN_NAMESPACE + +Q_STATIC_LOGGING_CATEGORY(lcQRandomAccessIORing, "qt.core.qrandomaccessasyncfile.ioring", + QtCriticalMsg); + +QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() = default; + +QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() = default; + +void QRandomAccessAsyncFilePrivate::init() +{ + m_ioring = QIORing::sharedInstance(); + if (!m_ioring) + qCCritical(lcQRandomAccessIORing, "QRandomAccessAsyncFile: ioring failed to initialize"); +} + +QIORing::RequestHandle QRandomAccessAsyncFilePrivate::cancel(QIORing::RequestHandle handle) +{ + if (handle) { + QIORingRequest<QIORing::Operation::Cancel> cancelRequest; + cancelRequest.handle = handle; + return m_ioring->queueRequest(std::move(cancelRequest)); + } + return nullptr; +} + +void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) +{ + auto *opHandle = m_opHandleMap.value(op); + if (auto *handle = cancel(opHandle)) { + m_ioring->waitForRequest(handle); + m_ioring->waitForRequest(opHandle); + } +} + +void QRandomAccessAsyncFilePrivate::queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error) +{ + // Remove the handle now in case the user cancels or deletes the io-operation + // before operationComplete is called - the null-handle will protect from + // nasty issues that may occur when trying to cancel an operation that's no + // longer in the queue: + m_opHandleMap.remove(priv->q_func()); + // @todo: Look into making it emit only if synchronously completed + QMetaObject::invokeMethod(priv->q_ptr, [priv, error](){ + priv->operationComplete(error); + }, Qt::QueuedConnection); +} + +QIOOperation *QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode) +{ + auto *dataStorage = new QtPrivate::QIOOperationDataStorage(); + + auto *priv = new QIOOperationPrivate(dataStorage); + priv->type = QIOOperation::Type::Open; + + auto *op = new QIOOperation(*priv, q_ptr); + if (m_fileState != FileState::Closed) { + queueCompletion(priv, QIOOperation::Error::Open); + return op; + } + m_operations.append(op); + m_fileState = FileState::OpenPending; + + QIORingRequest<QIORing::Operation::Open> openOperation; + openOperation.path = QtPrivate::toFilesystemPath(path); + openOperation.flags = mode; + openOperation.setCallback([this, op, + priv](const QIORingRequest<QIORing::Operation::Open> &request) { + if (const auto *err = std::get_if<QFileDevice::FileError>(&request.result)) { + if (m_fileState != FileState::Opened) { + // We assume there was only one pending open() in flight. + m_fd = -1; + m_fileState = FileState::Closed; + } + if (priv->error == QIOOperation::Error::Aborted || *err == QFileDevice::AbortError) + queueCompletion(priv, QIOOperation::Error::Aborted); + else + queueCompletion(priv, QIOOperation::Error::Open); + } else if (const auto *result = std::get_if<QIORingResult<QIORing::Operation::Open>>( + &request.result)) { + if (m_fileState == FileState::OpenPending) { + m_fileState = FileState::Opened; + m_fd = result->fd; + queueCompletion(priv, QIOOperation::Error::None); + } else { // Something went wrong, we did not expect a callback: + // So we close the new handle: + QIORingRequest<QIORing::Operation::Close> closeRequest; + closeRequest.fd = result->fd; + QIORing::RequestHandle handle = m_ioring->queueRequest(std::move(closeRequest)); + // Since the user issued multiple open() calls they get to wait for the close() to + // finish: + m_ioring->waitForRequest(handle); + queueCompletion(priv, QIOOperation::Error::Open); + } + } + m_operations.removeOne(op); + }); + m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(openOperation))); + + return op; +} + +void QRandomAccessAsyncFilePrivate::close() +{ + // all the operations should be aborted + const auto ops = std::exchange(m_operations, {}); + QList<QIORing::RequestHandle> tasksToAwait; + // Request to cancel all of the in-flight operations: + for (const auto &op : ops) { + if (op) { + op->d_func()->error = QIOOperation::Error::Aborted; + if (auto *opHandle = m_opHandleMap.value(op)) { + tasksToAwait.append(cancel(opHandle)); + tasksToAwait.append(opHandle); + } + } + } + + QIORingRequest<QIORing::Operation::Close> closeRequest; + closeRequest.fd = m_fd; + tasksToAwait.append(m_ioring->queueRequest(std::move(closeRequest))); + + // Wait for completion: + for (const QIORing::RequestHandle &handle : tasksToAwait) + m_ioring->waitForRequest(handle); + m_fileState = FileState::Closed; + m_fd = -1; +} + +qint64 QRandomAccessAsyncFilePrivate::size() const +{ + QIORingRequest<QIORing::Operation::Stat> statRequest; + statRequest.fd = m_fd; + qint64 finalSize = 0; + statRequest.setCallback([&finalSize](const QIORingRequest<QIORing::Operation::Stat> &request) { + if (const auto *err = std::get_if<QFileDevice::FileError>(&request.result)) { + Q_UNUSED(err); + finalSize = -1; + } else if (const auto *res = std::get_if<QIORingResult<QIORing::Operation::Stat>>(&request.result)) { + finalSize = q26::saturate_cast<qint64>(res->size); + } + }); + auto *handle = m_ioring->queueRequest(std::move(statRequest)); + m_ioring->waitForRequest(handle); + + return finalSize; +} + +QIOOperation *QRandomAccessAsyncFilePrivate::flush() +{ + auto *dataStorage = new QtPrivate::QIOOperationDataStorage(); + + auto *priv = new QIOOperationPrivate(dataStorage); + priv->type = QIOOperation::Type::Flush; + + auto *op = new QIOOperation(*priv, q_ptr); + m_operations.append(op); + + QIORingRequest<QIORing::Operation::Flush> flushRequest; + flushRequest.fd = m_fd; + flushRequest.setCallback([this, op](const QIORingRequest<QIORing::Operation::Flush> &request) { + auto *priv = QIOOperationPrivate::get(op); + if (const auto *err = std::get_if<QFileDevice::FileError>(&request.result)) { + if (priv->error == QIOOperation::Error::Aborted || *err == QFileDevice::AbortError) + queueCompletion(priv, QIOOperation::Error::Aborted); + else if (*err == QFileDevice::OpenError) + queueCompletion(priv, QIOOperation::Error::FileNotOpen); + else + queueCompletion(priv, QIOOperation::Error::Flush); + } else if (std::get_if<QIORingResult<QIORing::Operation::Flush>>(&request.result)) { + queueCompletion(priv, QIOOperation::Error::None); + } + m_operations.removeOne(op); + }); + m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(flushRequest))); + + return op; +} + +void QRandomAccessAsyncFilePrivate::startReadIntoSingle(QIOOperation *op, + const QSpan<std::byte> &to) +{ + QIORingRequest<QIORing::Operation::Read> readRequest; + readRequest.fd = m_fd; + auto *priv = QIOOperationPrivate::get(op); + if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now + queueCompletion(priv, QIOOperation::Error::IncorrectOffset); + m_operations.removeOne(op); + return; + } + readRequest.offset = priv->offset; + readRequest.destination = to; + readRequest.setCallback([this, op](const QIORingRequest<QIORing::Operation::Read> &request) { + auto *priv = QIOOperationPrivate::get(op); + if (const auto *err = std::get_if<QFileDevice::FileError>(&request.result)) { + if (priv->error == QIOOperation::Error::Aborted || *err == QFileDevice::AbortError) + queueCompletion(priv, QIOOperation::Error::Aborted); + else if (*err == QFileDevice::OpenError) + queueCompletion(priv, QIOOperation::Error::FileNotOpen); + else if (*err == QFileDevice::PositionError) + queueCompletion(priv, QIOOperation::Error::IncorrectOffset); + else + queueCompletion(priv, QIOOperation::Error::Read); + } else if (const auto *result = std::get_if<QIORingResult<QIORing::Operation::Read>>( + &request.result)) { + priv->appendBytesProcessed(result->bytesRead); + if (priv->dataStorage->containsReadSpans()) + priv->dataStorage->getReadSpans().first().slice(0, result->bytesRead); + else + priv->dataStorage->getByteArray().slice(0, result->bytesRead); + + queueCompletion(priv, QIOOperation::Error::None); + } + m_operations.removeOne(op); + }); + m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(readRequest))); +} + +QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize) +{ + QByteArray array; + array.resizeForOverwrite(maxSize); + auto *dataStorage = new QtPrivate::QIOOperationDataStorage(std::move(array)); + + auto *priv = new QIOOperationPrivate(dataStorage); + priv->offset = offset; + priv->type = QIOOperation::Type::Read; + + auto *op = new QIOReadOperation(*priv, q_ptr); + m_operations.append(op); + + startReadIntoSingle(op, as_writable_bytes(QSpan(dataStorage->getByteArray()))); + + return op; +} + +QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) +{ + return write(offset, QByteArray(data)); +} + +void QRandomAccessAsyncFilePrivate::startWriteFromSingle(QIOOperation *op, + const QSpan<const std::byte> &from) +{ + QIORingRequest<QIORing::Operation::Write> writeRequest; + writeRequest.fd = m_fd; + auto *priv = QIOOperationPrivate::get(op); + if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now + queueCompletion(priv, QIOOperation::Error::IncorrectOffset); + m_operations.removeOne(op); + return; + } + writeRequest.offset = priv->offset; + writeRequest.source = from; + writeRequest.setCallback([this, op](const QIORingRequest<QIORing::Operation::Write> &request) { + auto *priv = QIOOperationPrivate::get(op); + if (const auto *err = std::get_if<QFileDevice::FileError>(&request.result)) { + if (priv->error == QIOOperation::Error::Aborted || *err == QFileDevice::AbortError) + queueCompletion(priv, QIOOperation::Error::Aborted); + else if (*err == QFileDevice::OpenError) + queueCompletion(priv, QIOOperation::Error::FileNotOpen); + else if (*err == QFileDevice::PositionError) + queueCompletion(priv, QIOOperation::Error::IncorrectOffset); + else + queueCompletion(priv, QIOOperation::Error::Write); + } else if (const auto *result = std::get_if<QIORingResult<QIORing::Operation::Write>>( + &request.result)) { + priv->appendBytesProcessed(result->bytesWritten); + queueCompletion(priv, QIOOperation::Error::None); + } + m_operations.removeOne(op); + }); + m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(writeRequest))); +} + +QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) +{ + auto *dataStorage = new QtPrivate::QIOOperationDataStorage(std::move(data)); + + auto *priv = new QIOOperationPrivate(dataStorage); + priv->offset = offset; + priv->type = QIOOperation::Type::Write; + + auto *op = new QIOWriteOperation(*priv, q_ptr); + m_operations.append(op); + + startWriteFromSingle(op, as_bytes(QSpan(dataStorage->getByteArray()))); + + return op; +} + +QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset, + QSpan<std::byte> buffer) +{ + auto *dataStorage = new QtPrivate::QIOOperationDataStorage( + QSpan<const QSpan<std::byte>>{ buffer }); + + auto *priv = new QIOOperationPrivate(dataStorage); + priv->offset = offset; + priv->type = QIOOperation::Type::Read; + + auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + m_operations.append(op); + + startReadIntoSingle(op, dataStorage->getReadSpans().first()); + + return op; +} + +QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, + QSpan<const std::byte> buffer) +{ + auto *dataStorage = new QtPrivate::QIOOperationDataStorage( + QSpan<const QSpan<const std::byte>>{ buffer }); + + auto *priv = new QIOOperationPrivate(dataStorage); + priv->offset = offset; + priv->type = QIOOperation::Type::Write; + + auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + m_operations.append(op); + + startWriteFromSingle(op, dataStorage->getWriteSpans().first()); + + return op; +} + +QIOVectoredReadOperation * +QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) +{ + if (!QIORing::supportsOperation(QtPrivate::Operation::VectoredRead)) + return nullptr; + auto *dataStorage = new QtPrivate::QIOOperationDataStorage(buffers); + + auto *priv = new QIOOperationPrivate(dataStorage); + priv->offset = offset; + priv->type = QIOOperation::Type::Read; + + auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now + queueCompletion(priv, QIOOperation::Error::IncorrectOffset); + return op; + } + m_operations.append(op); + + QIORingRequest<QIORing::Operation::VectoredRead> readRequest; + readRequest.fd = m_fd; + readRequest.offset = priv->offset; + readRequest.destinations = dataStorage->getReadSpans(); + readRequest.setCallback([this, + op](const QIORingRequest<QIORing::Operation::VectoredRead> &request) { + auto *priv = QIOOperationPrivate::get(op); + if (const auto *err = std::get_if<QFileDevice::FileError>(&request.result)) { + if (priv->error == QIOOperation::Error::Aborted || *err == QFileDevice::AbortError) + queueCompletion(priv, QIOOperation::Error::Aborted); + else + queueCompletion(priv, QIOOperation::Error::Read); + } else if (const auto + *result = std::get_if<QIORingResult<QIORing::Operation::VectoredRead>>( + &request.result)) { + priv->appendBytesProcessed(result->bytesRead); + qint64 processed = result->bytesRead; + for (auto &span : priv->dataStorage->getReadSpans()) { + if (span.size() < processed) { + processed -= span.size(); + } else { // span.size >= processed + span.slice(0, processed); + processed = 0; + } + } + queueCompletion(priv, QIOOperation::Error::None); + } + m_operations.removeOne(op); + }); + m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(readRequest))); + + return op; +} + +QIOVectoredWriteOperation * +QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) +{ + if (!QIORing::supportsOperation(QtPrivate::Operation::VectoredWrite)) + return nullptr; + auto *dataStorage = new QtPrivate::QIOOperationDataStorage(buffers); + + auto *priv = new QIOOperationPrivate(dataStorage); + priv->offset = offset; + priv->type = QIOOperation::Type::Write; + + auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now + queueCompletion(priv, QIOOperation::Error::IncorrectOffset); + return op; + } + m_operations.append(op); + + QIORingRequest<QIORing::Operation::VectoredWrite> writeRequest; + writeRequest.fd = m_fd; + writeRequest.offset = priv->offset; + writeRequest.sources = dataStorage->getWriteSpans(); + writeRequest.setCallback( + [this, op](const QIORingRequest<QIORing::Operation::VectoredWrite> &request) { + auto *priv = QIOOperationPrivate::get(op); + if (const auto *err = std::get_if<QFileDevice::FileError>(&request.result)) { + if (priv->error == QIOOperation::Error::Aborted || *err == QFileDevice::AbortError) + queueCompletion(priv, QIOOperation::Error::Aborted); + else + queueCompletion(priv, QIOOperation::Error::Write); + } else if (const auto *result = std::get_if< + QIORingResult<QIORing::Operation::VectoredWrite>>( + &request.result)) { + priv->appendBytesProcessed(result->bytesWritten); + queueCompletion(priv, QIOOperation::Error::None); + } + m_operations.removeOne(op); + }); + m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(writeRequest))); + + return op; +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index a11f7913dc7..e69b9aebabb 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -301,21 +301,27 @@ public: explicit QList(qsizetype size) : d(size) { - if (size) + if (size) { + Q_CHECK_PTR(d.data()); d->appendInitialize(size); + } } QList(qsizetype size, parameter_type t) : d(size) { - if (size) + if (size) { + Q_CHECK_PTR(d.data()); d->copyAppend(size, t); + } } inline QList(std::initializer_list<T> args) : d(qsizetype(args.size())) { - if (args.size()) + if (args.size()) { + Q_CHECK_PTR(d.data()); d->copyAppend(args.begin(), args.end()); + } } QList<T> &operator=(std::initializer_list<T> args) @@ -332,6 +338,7 @@ public: const auto distance = std::distance(i1, i2); if (distance) { d = DataPointer(qsizetype(distance)); + Q_CHECK_PTR(d.data()); // appendIteratorRange can deal with contiguous iterators on its own, // this is an optimization for C++17 code. if constexpr (std::is_same_v<std::decay_t<InputIterator>, iterator> || @@ -352,8 +359,10 @@ public: QList(qsizetype size, Qt::Initialization) : d(size) { - if (size) + if (size) { + Q_CHECK_PTR(d.data()); d->appendUninitialized(size); + } } // compiler-generated special member functions are fine! @@ -823,7 +832,10 @@ void QList<T>::reserve(qsizetype asize) } } - DataPointer detached(qMax(asize, size())); + qsizetype newSize = qMax(asize, size()); + DataPointer detached(newSize); + if (newSize) + Q_CHECK_PTR(detached.data()); detached->copyAppend(d->begin(), d->end()); if (detached.d_ptr()) detached->setFlag(Data::CapacityReserved); @@ -839,6 +851,7 @@ inline void QList<T>::squeeze() // must allocate memory DataPointer detached(size()); if (size()) { + Q_CHECK_PTR(detached.data()); if (d.needsDetach()) detached->copyAppend(d.data(), d.data() + d.size); else diff --git a/src/plugins/platforms/wayland/CMakeLists.txt b/src/plugins/platforms/wayland/CMakeLists.txt index d9415f0a011..9a5db541a42 100644 --- a/src/plugins/platforms/wayland/CMakeLists.txt +++ b/src/plugins/platforms/wayland/CMakeLists.txt @@ -78,7 +78,6 @@ qt_internal_add_module(WaylandClient qwaylandviewport.cpp qwaylandviewport_p.h qwaylandwindow.cpp qwaylandwindow_p.h qwaylandwindowmanagerintegration.cpp qwaylandwindowmanagerintegration_p.h - qwaylandeventdispatcher.cpp qwaylandeventdispatcher_p.h shellintegration/qwaylandclientshellapi_p.h shellintegration/qwaylandshellintegration_p.h shellintegration/qwaylandshellintegration.cpp shellintegration/qwaylandshellintegrationfactory.cpp shellintegration/qwaylandshellintegrationfactory_p.h diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 1fc5e5c30a0..f20b0c5a7dc 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -32,7 +32,6 @@ #include "qwaylandtextinputv3_p.h" #include "qwaylandinputcontext_p.h" #include "qwaylandinputmethodcontext_p.h" -#include "qwaylandeventdispatcher_p.h" #include "qwaylandwindowmanagerintegration_p.h" #include "qwaylandshellintegration_p.h" @@ -525,7 +524,6 @@ void QWaylandDisplay::reconnect() void QWaylandDisplay::flushRequests() { m_eventThread->readAndDispatchEvents(); - QWindowSystemInterface::flushWindowSystemEvents(QWaylandEventDispatcher::eventDispatcher->flags()); } // We have to wait until we have an eventDispatcher before creating the eventThread, diff --git a/src/plugins/platforms/wayland/qwaylandeventdispatcher.cpp b/src/plugins/platforms/wayland/qwaylandeventdispatcher.cpp deleted file mode 100644 index f5f14f29824..00000000000 --- a/src/plugins/platforms/wayland/qwaylandeventdispatcher.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2025 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#include "qwaylandeventdispatcher_p.h" - -QT_BEGIN_NAMESPACE - -namespace QtWaylandClient { - -QWaylandEventDispatcher *QWaylandEventDispatcher::eventDispatcher = nullptr; - -QAbstractEventDispatcher *QWaylandEventDispatcher::createEventDispatcher() -{ -#if !defined(QT_NO_GLIB) && !defined(Q_OS_WIN) - if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && QEventDispatcherGlib::versionSupported()) - return new QWaylandGlibEventDispatcher(); -#endif - return new QWaylandUnixEventDispatcher(); -} - -QWaylandEventDispatcher::QWaylandEventDispatcher() -{ - Q_ASSERT(!eventDispatcher); - eventDispatcher = this; -} - -QWaylandEventDispatcher::~QWaylandEventDispatcher() -{ - Q_ASSERT(eventDispatcher == this); - eventDispatcher = nullptr; -} - -bool QWaylandUnixEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) -{ - m_flags = flags; - return QUnixEventDispatcherQPA::processEvents(flags); -} - -QEventLoop::ProcessEventsFlags QWaylandUnixEventDispatcher::flags() const -{ - return m_flags; -} - -#if !defined(QT_NO_GLIB) && !defined(Q_OS_WIN) - -QEventLoop::ProcessEventsFlags QWaylandGlibEventDispatcher::flags() const -{ - return m_flags; -} - -#endif - -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandeventdispatcher_p.h b/src/plugins/platforms/wayland/qwaylandeventdispatcher_p.h deleted file mode 100644 index a0426d44a21..00000000000 --- a/src/plugins/platforms/wayland/qwaylandeventdispatcher_p.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2025 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#ifndef QWAYLANDEVENTDISPATCHER_P_H -#define QWAYLANDEVENTDISPATCHER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qunixeventdispatcher_qpa_p.h> -#if !defined(QT_NO_GLIB) && !defined(Q_OS_WIN) -#include <QtGui/private/qeventdispatcher_glib_p.h> -#endif - -QT_BEGIN_NAMESPACE - -namespace QtWaylandClient { - -class QWaylandEventDispatcher -{ -public: - static QAbstractEventDispatcher *createEventDispatcher(); - - static QWaylandEventDispatcher *eventDispatcher; - -public: - QWaylandEventDispatcher(); - virtual ~QWaylandEventDispatcher(); - - virtual QEventLoop::ProcessEventsFlags flags() const = 0; -}; - -class QWaylandUnixEventDispatcher : public QUnixEventDispatcherQPA, QWaylandEventDispatcher -{ - Q_OBJECT -public: - bool processEvents(QEventLoop::ProcessEventsFlags flags) override; - - QEventLoop::ProcessEventsFlags flags() const override; - -private: - QEventLoop::ProcessEventsFlags m_flags; -}; - -#if !defined(QT_NO_GLIB) && !defined(Q_OS_WIN) - -class QWaylandGlibEventDispatcher : public QPAEventDispatcherGlib, QWaylandEventDispatcher -{ - Q_OBJECT -public: - QEventLoop::ProcessEventsFlags flags() const override; -}; - -#endif - -} - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index b16a97d4c77..28a0cca9e55 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -18,7 +18,6 @@ #include "qwaylandplatformservices_p.h" #include "qwaylandscreen_p.h" #include "qwaylandcursor_p.h" -#include "qwaylandeventdispatcher_p.h" #if defined(Q_OS_MACOS) # include <QtGui/private/qcoretextfontdatabase_p.h> @@ -26,6 +25,7 @@ #else # include <QtGui/private/qgenericunixfontdatabase_p.h> #endif +#include <QtGui/private/qgenericunixeventdispatcher_p.h> #include <QtGui/private/qgenericunixtheme_p.h> #include <QtGui/private/qguiapplication_p.h> @@ -182,7 +182,7 @@ QPlatformBackingStore *QWaylandIntegration::createPlatformBackingStore(QWindow * QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const { - return QWaylandEventDispatcher::createEventDispatcher(); + return createUnixEventDispatcher(); } QPlatformNativeInterface *QWaylandIntegration::createPlatformNativeInterface() diff --git a/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp b/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp index 6dceb583469..bcc30f98700 100644 --- a/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp +++ b/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp @@ -78,8 +78,9 @@ void tst_QRandomAccessAsyncFile::initTestCase() QVERIFY(m_file.open()); QByteArray data(FileSize, Qt::Uninitialized); + auto *ptr = data.data(); for (qsizetype i = 0; i < FileSize; ++i) - data[i] = char(i % 256); + ptr[i] = char(i % 256); qint64 written = m_file.write(data); QCOMPARE_EQ(written, FileSize); @@ -88,7 +89,13 @@ void tst_QRandomAccessAsyncFile::initTestCase() void tst_QRandomAccessAsyncFile::cleanupTestCase() { m_file.close(); - QVERIFY(m_file.remove()); + using namespace std::chrono_literals; + QDeadlineTimer dt(10s); + // Loop a little bit in case there is an access race on Windows: + bool success = false; + while (!(success = m_file.remove()) && !dt.hasExpired()) + QThread::msleep(100); + QVERIFY2(success, qPrintable(m_file.errorString())); } void tst_QRandomAccessAsyncFile::size() @@ -586,13 +593,16 @@ void tst_QRandomAccessAsyncFile::fileClosedInProgress() } file.close(); - auto isAbortedOrComplete = [](QIOOperation *op) { - return op->error() == QIOOperation::Error::Aborted - || op->error() == QIOOperation::Error::None; + auto isAbortedOrCompleteOrFailedToOpen = [](QIOOperation *op) { + return op->error() == QIOOperation::Error::Aborted // Aborted + || op->error() == QIOOperation::Error::Open // Failed, because other op is in progress + || op->error() == QIOOperation::Error::None; // Completed }; for (auto op : operations) { QTRY_VERIFY(op->isFinished()); - QVERIFY(isAbortedOrComplete(op)); + QVERIFY2(isAbortedOrCompleteOrFailedToOpen(op), + qPrintable("Expected Aborted, Open or None, got %1"_L1.arg( + QDebug::toString(op->error())))); } } diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp index b91665f55da..a93079b33de 100644 --- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp +++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp @@ -301,6 +301,7 @@ private slots: void constructors_emptyReserveZero() const; void constructors_emptyReserve() const; void constructors_reserveAndInitialize() const; + void constructorsThrowOnSillySize() const; void copyConstructorInt() const { copyConstructor<int>(); } void copyConstructorMovable() const { copyConstructor<Movable>(); } void copyConstructorNoexceptMovable() const { copyConstructor<NoexceptMovable>(); } @@ -704,6 +705,38 @@ void tst_QList::constructors_reserveAndInitialize() const QCOMPARE(meaningoflife.i, 'n'); } +void tst_QList::constructorsThrowOnSillySize() const +{ +#ifdef QT_NO_EXCEPTIONS + QSKIP("Compiled without exception support"); +#else + // Only testing primitives for this; it should be enough. + using T = int; + QList<T> dummy(4, 1); + + // This should cause QArrayData::allocate() to overflow and thus return + // nullptr. + constexpr size_t MaxMemory = std::numeric_limits<size_t>::max() / 4 * 3; + static_assert(MaxMemory > size_t(std::numeric_limits<ptrdiff_t>::max())); + static_assert(MaxMemory / sizeof(T) < size_t(std::numeric_limits<ptrdiff_t>::max() - 1)); + constexpr qsizetype NumElements = MaxMemory / sizeof(T); + + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l(NumElements)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l(NumElements, 0)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l(NumElements, Qt::Uninitialized)); + + // Since we're here, we might as well test resize() and reserve(). + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l; l.reserve(NumElements)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l; l.resize(NumElements)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l; l.resize(NumElements, 0)); + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l; l.resizeForOverwrite(NumElements)); + + // The reversed iterators will cause QList to pass a negative size to + // QArrayData::allocate(), which is also silly. + QVERIFY_THROWS_EXCEPTION(std::bad_alloc, QList<T> l(dummy.constEnd(), dummy.constBegin())); +#endif +} + template<typename T> void tst_QList::copyConstructor() const { |
