diff options
| -rw-r--r-- | src/corelib/CMakeLists.txt | 17 | ||||
| -rw-r--r-- | src/corelib/configure.cmake | 2 | ||||
| -rw-r--r-- | src/corelib/global/qcompilerdetection.h | 2 | ||||
| -rw-r--r-- | src/corelib/io/qiooperation_p.h | 20 | ||||
| -rw-r--r-- | src/corelib/io/qrandomaccessasyncfile.cpp | 25 | ||||
| -rw-r--r-- | src/corelib/io/qrandomaccessasyncfile_darwin.mm | 79 | ||||
| -rw-r--r-- | src/corelib/io/qrandomaccessasyncfile_p_p.h | 241 | ||||
| -rw-r--r-- | src/corelib/io/qrandomaccessasyncfile_qioring.cpp | 61 | ||||
| -rw-r--r-- | src/corelib/io/qrandomaccessasyncfile_threadpool.cpp | 79 | ||||
| -rw-r--r-- | src/corelib/tools/qeasingcurve.cpp | 10 | ||||
| -rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 25 |
11 files changed, 377 insertions, 184 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index ea8cf7b9c8e..539ad753ca6 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -590,17 +590,14 @@ if(QT_FEATURE_async_io) 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 - # QT_FEATURE_future. - qt_internal_extend_target(Core - SOURCES - io/qrandomaccessasyncfile_threadpool.cpp - DEFINES - QT_RANDOMACCESSASYNCFILE_THREAD - ) endif() + # This is the fallback condition that should be always available. + # TODO: try to rewrite it so that it does not depend on + # QT_FEATURE_future. + qt_internal_extend_target(Core + SOURCES + io/qrandomaccessasyncfile_threadpool.cpp + ) endif() # This needs to be done before one below adds kernel32 because the symbols we use diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index 90a0e359c9f..a186b65f24f 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -1284,7 +1284,7 @@ qt_feature("openssl-hash" PRIVATE qt_feature("async-io" PRIVATE LABEL "Async File I/O" PURPOSE "Provides support for asynchronous file I/O." - CONDITION (QT_FEATURE_thread AND QT_FEATURE_future) OR APPLE OR (LINUX AND QT_FEATURE_liburing) OR (WIN32 AND QT_FEATURE_windows_ioring) + CONDITION QT_FEATURE_thread AND QT_FEATURE_future ) qt_configure_add_summary_section(NAME "Qt Core") diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index 0b42af7686c..b2d79cca603 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -1404,7 +1404,7 @@ static_assert(!std::is_convertible_v<std::nullptr_t, bool>, #if defined(__cplusplus) #ifdef __cpp_constinit -# if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) +# if defined(Q_CC_MSVC) && _MSC_VER < 1940 && !defined(Q_CC_CLANG) // https://developercommunity.visualstudio.com/t/C:-constinit-for-an-optional-fails-if-/1406069 # define Q_CONSTINIT # else diff --git a/src/corelib/io/qiooperation_p.h b/src/corelib/io/qiooperation_p.h index 56845167ede..1486719a7e8 100644 --- a/src/corelib/io/qiooperation_p.h +++ b/src/corelib/io/qiooperation_p.h @@ -72,6 +72,9 @@ protected: Q_DECLARE_PRIVATE(QIOOperation) friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOReadWriteOperationBase : public QIOOperation @@ -86,6 +89,11 @@ protected: QIOReadWriteOperationBase() = delete; Q_DISABLE_COPY_MOVE(QIOReadWriteOperationBase) explicit QIOReadWriteOperationBase(QIOOperationPrivate &dd, QObject *parent = nullptr); + + friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOReadOperation : public QIOReadWriteOperationBase @@ -101,6 +109,9 @@ protected: explicit QIOReadOperation(QIOOperationPrivate &dd, QObject *parent = nullptr); friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOWriteOperation : public QIOReadWriteOperationBase @@ -116,6 +127,9 @@ protected: explicit QIOWriteOperation(QIOOperationPrivate &dd, QObject *parent = nullptr); friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOVectoredReadOperation : public QIOReadWriteOperationBase @@ -131,6 +145,9 @@ protected: explicit QIOVectoredReadOperation(QIOOperationPrivate &dd, QObject *parent = nullptr); friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOVectoredWriteOperation : public QIOReadWriteOperationBase @@ -146,6 +163,9 @@ protected: explicit QIOVectoredWriteOperation(QIOOperationPrivate &dd, QObject *parent = nullptr); friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; QT_END_NAMESPACE diff --git a/src/corelib/io/qrandomaccessasyncfile.cpp b/src/corelib/io/qrandomaccessasyncfile.cpp index c544585de9d..34e216efe27 100644 --- a/src/corelib/io/qrandomaccessasyncfile.cpp +++ b/src/corelib/io/qrandomaccessasyncfile.cpp @@ -7,6 +7,31 @@ QT_BEGIN_NAMESPACE +QRandomAccessAsyncFileBackend::QRandomAccessAsyncFileBackend(QRandomAccessAsyncFile *owner) + : m_owner(owner) +{ +} +QRandomAccessAsyncFileBackend::~QRandomAccessAsyncFileBackend() = default; +QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() = default; +QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() = default; + +void QRandomAccessAsyncFilePrivate::init() +{ + Q_Q(QRandomAccessAsyncFile); + +#if defined(QT_RANDOMACCESSASYNCFILE_QIORING) || defined(Q_OS_DARWIN) + m_backend = std::make_unique<QRandomAccessAsyncFileNativeBackend>(q); +#endif + if (!m_backend || !m_backend->init()) { +#if QT_CONFIG(thread) && QT_CONFIG(future) + m_backend = std::make_unique<QRandomAccessAsyncFileThreadPoolBackend>(q); + [[maybe_unused]] + bool result = m_backend->init(); + Q_ASSERT(result); // it always succeeds +#endif + } +} + QRandomAccessAsyncFile::QRandomAccessAsyncFile(QObject *parent) : QObject{*new QRandomAccessAsyncFilePrivate, parent} { diff --git a/src/corelib/io/qrandomaccessasyncfile_darwin.mm b/src/corelib/io/qrandomaccessasyncfile_darwin.mm index fca225263ba..80c1affa642 100644 --- a/src/corelib/io/qrandomaccessasyncfile_darwin.mm +++ b/src/corelib/io/qrandomaccessasyncfile_darwin.mm @@ -27,14 +27,14 @@ static bool isBarrierOperation(QIOOperation::Type type) // only! template <typename Operation, typename ...Args> Operation * -QRandomAccessAsyncFilePrivate::addOperation(QIOOperation::Type type, qint64 offset, Args &&...args) +QRandomAccessAsyncFileNativeBackend::addOperation(QIOOperation::Type type, qint64 offset, Args &&...args) { auto dataStorage = new QtPrivate::QIOOperationDataStorage(std::forward<Args>(args)...); auto *priv = new QIOOperationPrivate(dataStorage); priv->offset = offset; priv->type = type; - Operation *op = new Operation(*priv, q_ptr); + Operation *op = new Operation(*priv, m_owner); auto opId = getNextId(); m_operations.push_back(OperationInfo(opId, op)); startOperationsUntilBarrier(); @@ -42,19 +42,20 @@ QRandomAccessAsyncFilePrivate::addOperation(QIOOperation::Type type, qint64 offs return op; } -QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() - : QObjectPrivate() +QRandomAccessAsyncFileNativeBackend::QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner) + : QRandomAccessAsyncFileBackend(owner) { } -QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() +QRandomAccessAsyncFileNativeBackend::~QRandomAccessAsyncFileNativeBackend() = default; -void QRandomAccessAsyncFilePrivate::init() +bool QRandomAccessAsyncFileNativeBackend::init() { + return true; } -void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) +void QRandomAccessAsyncFileNativeBackend::cancelAndWait(QIOOperation *op) { auto it = std::find_if(m_operations.cbegin(), m_operations.cend(), [op](const auto &opInfo) { @@ -87,7 +88,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) startOperationsUntilBarrier(); } -void QRandomAccessAsyncFilePrivate::close() +void QRandomAccessAsyncFileNativeBackend::close() { if (m_fileState == FileState::Closed) return; @@ -125,7 +126,7 @@ void QRandomAccessAsyncFilePrivate::close() m_fileState = FileState::Closed; } -qint64 QRandomAccessAsyncFilePrivate::size() const +qint64 QRandomAccessAsyncFileNativeBackend::size() const { if (m_fileState != FileState::Opened) return -1; @@ -138,7 +139,7 @@ qint64 QRandomAccessAsyncFilePrivate::size() const } QIOOperation * -QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode) +QRandomAccessAsyncFileNativeBackend::open(const QString &path, QIODeviceBase::OpenMode mode) { if (m_fileState == FileState::Closed) { m_filePath = path; @@ -151,44 +152,44 @@ QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode return addOperation<QIOOperation>(QIOOperation::Type::Open, 0); } -QIOOperation *QRandomAccessAsyncFilePrivate::flush() +QIOOperation *QRandomAccessAsyncFileNativeBackend::flush() { return addOperation<QIOOperation>(QIOOperation::Type::Flush, 0); } -QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize) +QIOReadOperation *QRandomAccessAsyncFileNativeBackend::read(qint64 offset, qint64 maxSize) { QByteArray array(maxSize, Qt::Uninitialized); return addOperation<QIOReadOperation>(QIOOperation::Type::Read, offset, std::move(array)); } -QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) +QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, const QByteArray &data) { QByteArray copy = data; return write(offset, std::move(copy)); } -QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) +QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, QByteArray &&data) { return addOperation<QIOWriteOperation>(QIOOperation::Type::Write, offset, std::move(data)); } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer) +QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<std::byte> buffer) { return addOperation<QIOVectoredReadOperation>(QIOOperation::Type::Read, offset, QSpan<const QSpan<std::byte>>{buffer}); } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> buffer) +QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const std::byte> buffer) { return addOperation<QIOVectoredWriteOperation>(QIOOperation::Type::Write, offset, QSpan<const QSpan<const std::byte>>{buffer}); } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) +QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) { // GCD implementation does not have vectored read. Spawning several read // operations (each with an updated offset), is not ideal, because some @@ -202,12 +203,12 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) +QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) { return addOperation<QIOVectoredWriteOperation>(QIOOperation::Type::Write, offset, buffers); } -void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted() +void QRandomAccessAsyncFileNativeBackend::notifyIfOperationsAreCompleted() { QMutexLocker locker(&m_mutex); --m_numChannelsToClose; @@ -217,7 +218,7 @@ void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted() } } -dispatch_io_t QRandomAccessAsyncFilePrivate::createMainChannel(int fd) +dispatch_io_t QRandomAccessAsyncFileNativeBackend::createMainChannel(int fd) { auto sharedThis = this; auto channel = @@ -235,7 +236,7 @@ dispatch_io_t QRandomAccessAsyncFilePrivate::createMainChannel(int fd) return channel; } -dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId) +dispatch_io_t QRandomAccessAsyncFileNativeBackend::duplicateIoChannel(OperationId opId) { if (!m_ioChannel) return nullptr; @@ -258,13 +259,13 @@ dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId return channel; } -void QRandomAccessAsyncFilePrivate::closeIoChannel(dispatch_io_t channel) +void QRandomAccessAsyncFileNativeBackend::closeIoChannel(dispatch_io_t channel) { if (channel) dispatch_io_close(channel, DISPATCH_IO_STOP); } -void QRandomAccessAsyncFilePrivate::releaseIoChannel(dispatch_io_t channel) +void QRandomAccessAsyncFileNativeBackend::releaseIoChannel(dispatch_io_t channel) { if (channel) { dispatch_release(channel); @@ -272,7 +273,7 @@ void QRandomAccessAsyncFilePrivate::releaseIoChannel(dispatch_io_t channel) } } -void QRandomAccessAsyncFilePrivate::handleOperationComplete(const OperationResult &opResult) +void QRandomAccessAsyncFileNativeBackend::handleOperationComplete(const OperationResult &opResult) { // try to start next operations on return auto onReturn = qScopeGuard([this] { @@ -379,15 +380,15 @@ void QRandomAccessAsyncFilePrivate::handleOperationComplete(const OperationResul } } -void QRandomAccessAsyncFilePrivate::queueCompletion(OperationId opId, int error) +void QRandomAccessAsyncFileNativeBackend::queueCompletion(OperationId opId, int error) { const OperationResult res = { opId, 0LL, error }; - QMetaObject::invokeMethod(q_ptr, [this, res] { + QMetaObject::invokeMethod(m_owner, [this, res] { handleOperationComplete(res); }, Qt::QueuedConnection); } -void QRandomAccessAsyncFilePrivate::startOperationsUntilBarrier() +void QRandomAccessAsyncFileNativeBackend::startOperationsUntilBarrier() { // starts all operations until barrier, or a barrier operation if it's the // first one @@ -421,7 +422,7 @@ void QRandomAccessAsyncFilePrivate::startOperationsUntilBarrier() } } -void QRandomAccessAsyncFilePrivate::executeRead(OperationInfo &opInfo) +void QRandomAccessAsyncFileNativeBackend::executeRead(OperationInfo &opInfo) { opInfo.channel = duplicateIoChannel(opInfo.opId); if (!opInfo.channel) { @@ -452,7 +453,7 @@ void QRandomAccessAsyncFilePrivate::executeRead(OperationInfo &opInfo) } } -void QRandomAccessAsyncFilePrivate::executeWrite(OperationInfo &opInfo) +void QRandomAccessAsyncFileNativeBackend::executeWrite(OperationInfo &opInfo) { opInfo.channel = duplicateIoChannel(opInfo.opId); if (!opInfo.channel) { @@ -501,7 +502,7 @@ void QRandomAccessAsyncFilePrivate::executeWrite(OperationInfo &opInfo) } } -void QRandomAccessAsyncFilePrivate::executeFlush(OperationInfo &opInfo) +void QRandomAccessAsyncFileNativeBackend::executeFlush(OperationInfo &opInfo) { opInfo.channel = duplicateIoChannel(opInfo.opId); if (!opInfo.channel) { @@ -530,7 +531,7 @@ void QRandomAccessAsyncFilePrivate::executeFlush(OperationInfo &opInfo) } } } else { - auto context = sharedThis->q_ptr; + auto context = sharedThis->m_owner; const OperationResult res = { opId, 0LL, err }; QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) { sharedThis->handleOperationComplete(r); @@ -562,7 +563,7 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode) return oflags; } -void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo) +void QRandomAccessAsyncFileNativeBackend::executeOpen(OperationInfo &opInfo) { if (m_fileState != FileState::OpenPending) { queueCompletion(opInfo.opId, EINVAL); @@ -603,7 +604,7 @@ void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo) Q_ASSERT(sharedThis->m_numChannelsToClose == 0); sharedThis->m_cancellationCondition.wakeOne(); } else { - auto context = sharedThis->q_ptr; + auto context = sharedThis->m_owner; const OperationResult res = { opId, qint64(fd), err }; QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) { @@ -613,7 +614,7 @@ void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo) }); } -void QRandomAccessAsyncFilePrivate::readOneBuffer(OperationId opId, qsizetype bufferIdx, +void QRandomAccessAsyncFileNativeBackend::readOneBuffer(OperationId opId, qsizetype bufferIdx, qint64 alreadyRead) { // we need to lookup the operation again, because it could have beed removed @@ -650,7 +651,7 @@ void QRandomAccessAsyncFilePrivate::readOneBuffer(OperationId opId, qsizetype bu readBuffers.size(), alreadyRead); } -void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispatch_io_t channel, +void QRandomAccessAsyncFileNativeBackend::readOneBufferHelper(OperationId opId, dispatch_io_t channel, qint64 offset, void *bytesPtr, qint64 maxSize, qsizetype currentBufferIdx, qsizetype totalBuffers, qint64 alreadyRead) @@ -698,7 +699,7 @@ void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispat } } else { sharedThis->m_runningOps.remove(opId); - auto context = sharedThis->q_ptr; + auto context = sharedThis->m_owner; // if error, or last buffer, or read less than expected, // report operation completion qint64 totalRead = qint64(readFromBuffer) + alreadyRead; @@ -721,7 +722,7 @@ void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispat }); } -void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t channel, +void QRandomAccessAsyncFileNativeBackend::writeHelper(OperationId opId, dispatch_io_t channel, qint64 offset, dispatch_data_t dataToWrite, qint64 dataSize) { @@ -760,7 +761,7 @@ void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t const size_t written = dataSize - toBeWritten; [dataToWrite release]; - auto context = sharedThis->q_ptr; + auto context = sharedThis->m_owner; const OperationResult res = { opId, qint64(written), error }; QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) { @@ -770,7 +771,7 @@ void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t }); } -QRandomAccessAsyncFilePrivate::OperationId QRandomAccessAsyncFilePrivate::getNextId() +QRandomAccessAsyncFileNativeBackend::OperationId QRandomAccessAsyncFileNativeBackend::getNextId() { // never return reserved values static OperationId opId = kInvalidOperationId; diff --git a/src/corelib/io/qrandomaccessasyncfile_p_p.h b/src/corelib/io/qrandomaccessasyncfile_p_p.h index 11ad788c884..2eb53058780 100644 --- a/src/corelib/io/qrandomaccessasyncfile_p_p.h +++ b/src/corelib/io/qrandomaccessasyncfile_p_p.h @@ -22,7 +22,7 @@ #include <QtCore/qstring.h> -#ifdef QT_RANDOMACCESSASYNCFILE_THREAD +#if QT_CONFIG(future) && QT_CONFIG(thread) #include <QtCore/private/qfsfileengine_p.h> @@ -30,7 +30,7 @@ #include <QtCore/qmutex.h> #include <QtCore/qqueue.h> -#endif // QT_RANDOMACCESSASYNCFILE_THREAD +#endif // future && thread #ifdef Q_OS_DARWIN @@ -50,41 +50,36 @@ QT_BEGIN_NAMESPACE -class QRandomAccessAsyncFilePrivate : public QObjectPrivate +class QRandomAccessAsyncFileBackend { - Q_DECLARE_PUBLIC(QRandomAccessAsyncFile) - Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFilePrivate) + Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileBackend) public: - QRandomAccessAsyncFilePrivate(); - ~QRandomAccessAsyncFilePrivate() override; - - static QRandomAccessAsyncFilePrivate *get(QRandomAccessAsyncFile *file) - { return file->d_func(); } + explicit QRandomAccessAsyncFileBackend(QRandomAccessAsyncFile *owner); + virtual ~QRandomAccessAsyncFileBackend(); - void init(); - void cancelAndWait(QIOOperation *op); + virtual bool init() = 0; + virtual void cancelAndWait(QIOOperation *op) = 0; - void close(); - qint64 size() const; + virtual void close() = 0; + virtual qint64 size() const = 0; - [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode); - [[nodiscard]] QIOOperation *flush(); + [[nodiscard]] virtual QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) = 0; + [[nodiscard]] virtual QIOOperation *flush() = 0; - [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize); - [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data); - [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data); + [[nodiscard]] virtual QIOReadOperation *read(qint64 offset, qint64 maxSize) = 0; + [[nodiscard]] virtual QIOWriteOperation *write(qint64 offset, const QByteArray &data) = 0; + [[nodiscard]] virtual QIOWriteOperation *write(qint64 offset, QByteArray &&data) = 0; - [[nodiscard]] QIOVectoredReadOperation * - readInto(qint64 offset, QSpan<std::byte> buffer); - [[nodiscard]] QIOVectoredWriteOperation * - writeFrom(qint64 offset, QSpan<const std::byte> buffer); - - [[nodiscard]] QIOVectoredReadOperation * - readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers); - [[nodiscard]] QIOVectoredWriteOperation * - writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers); + [[nodiscard]] virtual QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<std::byte> buffer) = 0; + [[nodiscard]] virtual QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const std::byte> buffer) = 0; -private: + [[nodiscard]] virtual QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) = 0; + [[nodiscard]] virtual QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) = 0; +protected: // common for all backends enum class FileState : quint8 { @@ -94,32 +89,131 @@ private: }; QString m_filePath; + QRandomAccessAsyncFile *m_owner = nullptr; QIODeviceBase::OpenMode m_openMode; FileState m_fileState = FileState::Closed; +}; -#ifdef QT_RANDOMACCESSASYNCFILE_THREAD +class QRandomAccessAsyncFilePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QRandomAccessAsyncFile) + Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFilePrivate) public: - struct OperationResult + QRandomAccessAsyncFilePrivate(); + ~QRandomAccessAsyncFilePrivate() override; + + static QRandomAccessAsyncFilePrivate *get(QRandomAccessAsyncFile *file) + { return file->d_func(); } + + void init(); + void cancelAndWait(QIOOperation *op) { - qint64 bytesProcessed; // either read or written - QIOOperation::Error error; - }; + checkValid(); + m_backend->cancelAndWait(op); + } + + void close() + { + checkValid(); + m_backend->close(); + } + qint64 size() const + { + checkValid(); + return m_backend->size(); + } + + [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) + { + checkValid(); + return m_backend->open(path, mode); + } + [[nodiscard]] QIOOperation *flush() + { + checkValid(); + return m_backend->flush(); + } + + [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) + { + checkValid(); + return m_backend->read(offset, maxSize); + } + [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data) + { + checkValid(); + return m_backend->write(offset, data); + } + [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) + { + checkValid(); + return m_backend->write(offset, std::move(data)); + } + + [[nodiscard]] QIOVectoredReadOperation *readInto(qint64 offset, QSpan<std::byte> buffer) + { + checkValid(); + return m_backend->readInto(offset, buffer); + } + [[nodiscard]] QIOVectoredWriteOperation *writeFrom(qint64 offset, QSpan<const std::byte> buffer) + { + checkValid(); + return m_backend->writeFrom(offset, buffer); + } + + [[nodiscard]] QIOVectoredReadOperation *readInto(qint64 offset, + QSpan<const QSpan<std::byte>> buffers) + { + checkValid(); + return m_backend->readInto(offset, buffers); + } + [[nodiscard]] QIOVectoredWriteOperation *writeFrom(qint64 offset, + QSpan<const QSpan<const std::byte>> buffers) + { + checkValid(); + return m_backend->writeFrom(offset, buffers); + } private: - mutable QBasicMutex m_engineMutex; - std::unique_ptr<QFSFileEngine> m_engine; - QFutureWatcher<OperationResult> m_watcher; + void checkValid() const { Q_ASSERT(m_backend); } + std::unique_ptr<QRandomAccessAsyncFileBackend> m_backend; - QQueue<QPointer<QIOOperation>> m_operations; - QPointer<QIOOperation> m_currentOperation; - qsizetype numProcessedBuffers = 0; +}; - void executeNextOperation(); - void processBufferAt(qsizetype idx); - void processFlush(); - void processOpen(); - void operationComplete(); -#elif defined(QT_RANDOMACCESSASYNCFILE_QIORING) + +#if defined(QT_RANDOMACCESSASYNCFILE_QIORING) || defined(Q_OS_DARWIN) +class QRandomAccessAsyncFileNativeBackend final : public QRandomAccessAsyncFileBackend +{ + Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileNativeBackend) +public: + explicit QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner); + ~QRandomAccessAsyncFileNativeBackend(); + + bool init() override; + void cancelAndWait(QIOOperation *op) override; + + void close() override; + qint64 size() const override; + + [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) override; + [[nodiscard]] QIOOperation *flush() override; + + [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) override; + [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data) override; + [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) override; + + [[nodiscard]] QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<std::byte> buffer) override; + [[nodiscard]] QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const std::byte> buffer) override; + + [[nodiscard]] QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) override; + [[nodiscard]] QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) override; + +private: +#if 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); @@ -210,6 +304,61 @@ private: dispatch_data_t dataToWrite, qint64 dataSize); #endif }; +#endif // QIORing || macOS + +#if QT_CONFIG(future) && QT_CONFIG(thread) +class QRandomAccessAsyncFileThreadPoolBackend : public QRandomAccessAsyncFileBackend +{ + Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileThreadPoolBackend) +public: + explicit QRandomAccessAsyncFileThreadPoolBackend(QRandomAccessAsyncFile *owner); + ~QRandomAccessAsyncFileThreadPoolBackend(); + + bool init() override; + void cancelAndWait(QIOOperation *op) override; + + void close() override; + qint64 size() const override; + + [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) override; + [[nodiscard]] QIOOperation *flush() override; + + [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) override; + [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data) override; + [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) override; + + [[nodiscard]] QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<std::byte> buffer) override; + [[nodiscard]] QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const std::byte> buffer) override; + + [[nodiscard]] QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) override; + [[nodiscard]] QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) override; + + struct OperationResult + { + qint64 bytesProcessed; // either read or written + QIOOperation::Error error; + }; +private: + + mutable QBasicMutex m_engineMutex; + std::unique_ptr<QFSFileEngine> m_engine; + QFutureWatcher<OperationResult> m_watcher; + + QQueue<QPointer<QIOOperation>> m_operations; + QPointer<QIOOperation> m_currentOperation; + qsizetype numProcessedBuffers = 0; + + void executeNextOperation(); + void processBufferAt(qsizetype idx); + void processFlush(); + void processOpen(); + void operationComplete(); +}; +#endif // future && thread QT_END_NAMESPACE diff --git a/src/corelib/io/qrandomaccessasyncfile_qioring.cpp b/src/corelib/io/qrandomaccessasyncfile_qioring.cpp index c9783ea2856..8e1145325d8 100644 --- a/src/corelib/io/qrandomaccessasyncfile_qioring.cpp +++ b/src/corelib/io/qrandomaccessasyncfile_qioring.cpp @@ -18,18 +18,21 @@ QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcQRandomAccessIORing, "qt.core.qrandomaccessasyncfile.ioring", QtCriticalMsg); -QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() = default; +QRandomAccessAsyncFileNativeBackend::QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner) + : QRandomAccessAsyncFileBackend(owner) +{} -QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() = default; +QRandomAccessAsyncFileNativeBackend::~QRandomAccessAsyncFileNativeBackend() = default; -void QRandomAccessAsyncFilePrivate::init() +bool QRandomAccessAsyncFileNativeBackend::init() { m_ioring = QIORing::sharedInstance(); if (!m_ioring) - qCCritical(lcQRandomAccessIORing, "QRandomAccessAsyncFile: ioring failed to initialize"); + qCWarning(lcQRandomAccessIORing, "QRandomAccessAsyncFile: ioring failed to initialize"); + return m_ioring != nullptr; } -QIORing::RequestHandle QRandomAccessAsyncFilePrivate::cancel(QIORing::RequestHandle handle) +QIORing::RequestHandle QRandomAccessAsyncFileNativeBackend::cancel(QIORing::RequestHandle handle) { if (handle) { QIORingRequest<QIORing::Operation::Cancel> cancelRequest; @@ -39,7 +42,7 @@ QIORing::RequestHandle QRandomAccessAsyncFilePrivate::cancel(QIORing::RequestHan return nullptr; } -void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) +void QRandomAccessAsyncFileNativeBackend::cancelAndWait(QIOOperation *op) { auto *opHandle = m_opHandleMap.value(op); if (auto *handle = cancel(opHandle)) { @@ -48,7 +51,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) } } -void QRandomAccessAsyncFilePrivate::queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error) +void QRandomAccessAsyncFileNativeBackend::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 @@ -61,14 +64,14 @@ void QRandomAccessAsyncFilePrivate::queueCompletion(QIOOperationPrivate *priv, Q }, Qt::QueuedConnection); } -QIOOperation *QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode) +QIOOperation *QRandomAccessAsyncFileNativeBackend::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); + auto *op = new QIOOperation(*priv, m_owner); if (m_fileState != FileState::Closed) { queueCompletion(priv, QIOOperation::Error::Open); return op; @@ -115,7 +118,7 @@ QIOOperation *QRandomAccessAsyncFilePrivate::open(const QString &path, QIODevice return op; } -void QRandomAccessAsyncFilePrivate::close() +void QRandomAccessAsyncFileNativeBackend::close() { // all the operations should be aborted const auto ops = std::exchange(m_operations, {}); @@ -123,7 +126,7 @@ void QRandomAccessAsyncFilePrivate::close() // Request to cancel all of the in-flight operations: for (const auto &op : ops) { if (op) { - op->d_func()->error = QIOOperation::Error::Aborted; + QIOOperationPrivate::get(op)->error = QIOOperation::Error::Aborted; if (auto *opHandle = m_opHandleMap.value(op)) { tasksToAwait.append(cancel(opHandle)); tasksToAwait.append(opHandle); @@ -142,7 +145,7 @@ void QRandomAccessAsyncFilePrivate::close() m_fd = -1; } -qint64 QRandomAccessAsyncFilePrivate::size() const +qint64 QRandomAccessAsyncFileNativeBackend::size() const { QIORingRequest<QIORing::Operation::Stat> statRequest; statRequest.fd = m_fd; @@ -161,14 +164,14 @@ qint64 QRandomAccessAsyncFilePrivate::size() const return finalSize; } -QIOOperation *QRandomAccessAsyncFilePrivate::flush() +QIOOperation *QRandomAccessAsyncFileNativeBackend::flush() { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(); auto *priv = new QIOOperationPrivate(dataStorage); priv->type = QIOOperation::Type::Flush; - auto *op = new QIOOperation(*priv, q_ptr); + auto *op = new QIOOperation(*priv, m_owner); m_operations.append(op); QIORingRequest<QIORing::Operation::Flush> flushRequest; @@ -192,7 +195,7 @@ QIOOperation *QRandomAccessAsyncFilePrivate::flush() return op; } -void QRandomAccessAsyncFilePrivate::startReadIntoSingle(QIOOperation *op, +void QRandomAccessAsyncFileNativeBackend::startReadIntoSingle(QIOOperation *op, const QSpan<std::byte> &to) { QIORingRequest<QIORing::Operation::Read> readRequest; @@ -231,7 +234,7 @@ void QRandomAccessAsyncFilePrivate::startReadIntoSingle(QIOOperation *op, m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(readRequest))); } -QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize) +QIOReadOperation *QRandomAccessAsyncFileNativeBackend::read(qint64 offset, qint64 maxSize) { QByteArray array; array.resizeForOverwrite(maxSize); @@ -241,7 +244,7 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOReadOperation(*priv, q_ptr); + auto *op = new QIOReadOperation(*priv, m_owner); m_operations.append(op); startReadIntoSingle(op, as_writable_bytes(QSpan(dataStorage->getByteArray()))); @@ -249,12 +252,12 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS return op; } -QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) +QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, const QByteArray &data) { return write(offset, QByteArray(data)); } -void QRandomAccessAsyncFilePrivate::startWriteFromSingle(QIOOperation *op, +void QRandomAccessAsyncFileNativeBackend::startWriteFromSingle(QIOOperation *op, const QSpan<const std::byte> &from) { QIORingRequest<QIORing::Operation::Write> writeRequest; @@ -288,7 +291,7 @@ void QRandomAccessAsyncFilePrivate::startWriteFromSingle(QIOOperation *op, m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(writeRequest))); } -QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) +QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, QByteArray &&data) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(std::move(data)); @@ -296,7 +299,7 @@ QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArra priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOWriteOperation(*priv, q_ptr); + auto *op = new QIOWriteOperation(*priv, m_owner); m_operations.append(op); startWriteFromSingle(op, as_bytes(QSpan(dataStorage->getByteArray()))); @@ -304,7 +307,7 @@ QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArra return op; } -QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset, +QIOVectoredReadOperation *QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<std::byte> buffer) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage( @@ -314,7 +317,7 @@ QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset, priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + auto *op = new QIOVectoredReadOperation(*priv, m_owner); m_operations.append(op); startReadIntoSingle(op, dataStorage->getReadSpans().first()); @@ -322,7 +325,7 @@ QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset, return op; } -QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, +QIOVectoredWriteOperation *QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const std::byte> buffer) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage( @@ -332,7 +335,7 @@ QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offse priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + auto *op = new QIOVectoredWriteOperation(*priv, m_owner); m_operations.append(op); startWriteFromSingle(op, dataStorage->getWriteSpans().first()); @@ -341,7 +344,7 @@ QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offse } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) +QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) { if (!QIORing::supportsOperation(QtPrivate::Operation::VectoredRead)) return nullptr; @@ -351,7 +354,7 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + auto *op = new QIOVectoredReadOperation(*priv, m_owner); if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now queueCompletion(priv, QIOOperation::Error::IncorrectOffset); return op; @@ -393,7 +396,7 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) +QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) { if (!QIORing::supportsOperation(QtPrivate::Operation::VectoredWrite)) return nullptr; @@ -403,7 +406,7 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + auto *op = new QIOVectoredWriteOperation(*priv, m_owner); if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now queueCompletion(priv, QIOOperation::Error::IncorrectOffset); return op; diff --git a/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp b/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp index 4ebcf554655..774fbadc5ad 100644 --- a/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp +++ b/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp @@ -64,28 +64,29 @@ static SharedThreadPool asyncFileThreadPool; } // anonymous namespace -QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() : - QObjectPrivate() +QRandomAccessAsyncFileThreadPoolBackend::QRandomAccessAsyncFileThreadPoolBackend(QRandomAccessAsyncFile *owner) : + QRandomAccessAsyncFileBackend(owner) { asyncFileThreadPool.ref(); } -QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() +QRandomAccessAsyncFileThreadPoolBackend::~QRandomAccessAsyncFileThreadPoolBackend() { asyncFileThreadPool.deref(); } -void QRandomAccessAsyncFilePrivate::init() +bool QRandomAccessAsyncFileThreadPoolBackend::init() { - QObject::connect(&m_watcher, &QFutureWatcherBase::finished, q_ptr, [this]{ + QObject::connect(&m_watcher, &QFutureWatcherBase::finished, m_owner, [this]{ operationComplete(); }); - QObject::connect(&m_watcher, &QFutureWatcherBase::canceled, q_ptr, [this]{ + QObject::connect(&m_watcher, &QFutureWatcherBase::canceled, m_owner, [this]{ operationComplete(); }); + return true; } -void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) +void QRandomAccessAsyncFileThreadPoolBackend::cancelAndWait(QIOOperation *op) { if (op == m_currentOperation) { m_currentOperation = nullptr; // to discard the result @@ -97,7 +98,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) } QIOOperation * -QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode) +QRandomAccessAsyncFileThreadPoolBackend::open(const QString &path, QIODeviceBase::OpenMode mode) { // We generate the command in any case. But if the file is already opened, // it will finish with an error @@ -112,14 +113,14 @@ QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode auto *priv = new QIOOperationPrivate(dataStorage); priv->type = QIOOperation::Type::Open; - auto *op = new QIOOperation(*priv, q_ptr); + auto *op = new QIOOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } -void QRandomAccessAsyncFilePrivate::close() +void QRandomAccessAsyncFileThreadPoolBackend::close() { // all the operations should be aborted for (const auto &op : std::as_const(m_operations)) { @@ -148,7 +149,7 @@ void QRandomAccessAsyncFilePrivate::close() m_fileState = FileState::Closed; } -qint64 QRandomAccessAsyncFilePrivate::size() const +qint64 QRandomAccessAsyncFileThreadPoolBackend::size() const { QMutexLocker locker(&m_engineMutex); if (m_engine) @@ -156,20 +157,20 @@ qint64 QRandomAccessAsyncFilePrivate::size() const return -1; } -QIOOperation *QRandomAccessAsyncFilePrivate::flush() +QIOOperation *QRandomAccessAsyncFileThreadPoolBackend::flush() { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(); auto *priv = new QIOOperationPrivate(dataStorage); priv->type = QIOOperation::Type::Flush; - auto *op = new QIOOperation(*priv, q_ptr); + auto *op = new QIOOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } -QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize) +QIOReadOperation *QRandomAccessAsyncFileThreadPoolBackend::read(qint64 offset, qint64 maxSize) { QByteArray array; array.resizeForOverwrite(maxSize); @@ -179,14 +180,14 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOReadOperation(*priv, q_ptr); + auto *op = new QIOReadOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOWriteOperation * -QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) +QRandomAccessAsyncFileThreadPoolBackend::write(qint64 offset, const QByteArray &data) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(data); @@ -194,14 +195,14 @@ QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOWriteOperation(*priv, q_ptr); + auto *op = new QIOWriteOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOWriteOperation * -QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) +QRandomAccessAsyncFileThreadPoolBackend::write(qint64 offset, QByteArray &&data) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(std::move(data)); @@ -209,14 +210,14 @@ QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOWriteOperation(*priv, q_ptr); + auto *op = new QIOWriteOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer) +QRandomAccessAsyncFileThreadPoolBackend::readInto(qint64 offset, QSpan<std::byte> buffer) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(QSpan<const QSpan<std::byte>>{buffer}); @@ -225,14 +226,14 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer) priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + auto *op = new QIOVectoredReadOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> buffer) +QRandomAccessAsyncFileThreadPoolBackend::writeFrom(qint64 offset, QSpan<const std::byte> buffer) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(QSpan<const QSpan<const std::byte>>{buffer}); @@ -241,14 +242,14 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> b priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + auto *op = new QIOVectoredWriteOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) +QRandomAccessAsyncFileThreadPoolBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(buffers); @@ -256,14 +257,14 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + auto *op = new QIOVectoredReadOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) +QRandomAccessAsyncFileThreadPoolBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(buffers); @@ -271,16 +272,16 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + auto *op = new QIOVectoredWriteOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } -static QRandomAccessAsyncFilePrivate::OperationResult +static QRandomAccessAsyncFileThreadPoolBackend::OperationResult executeRead(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, char *buffer, qint64 maxSize) { - QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None}; + QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None}; QMutexLocker locker(mutex); if (engine) { @@ -299,11 +300,11 @@ executeRead(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, char *buff return result; } -static QRandomAccessAsyncFilePrivate::OperationResult +static QRandomAccessAsyncFileThreadPoolBackend::OperationResult executeWrite(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, const char *buffer, qint64 size) { - QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None}; + QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None}; QMutexLocker locker(mutex); if (engine) { @@ -322,7 +323,7 @@ executeWrite(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, return result; } -void QRandomAccessAsyncFilePrivate::executeNextOperation() +void QRandomAccessAsyncFileThreadPoolBackend::executeNextOperation() { if (m_currentOperation.isNull()) { // start next @@ -351,7 +352,7 @@ void QRandomAccessAsyncFilePrivate::executeNextOperation() } } -void QRandomAccessAsyncFilePrivate::processBufferAt(qsizetype idx) +void QRandomAccessAsyncFileThreadPoolBackend::processBufferAt(qsizetype idx) { Q_ASSERT(!m_currentOperation.isNull()); auto *priv = QIOOperationPrivate::get(m_currentOperation.get()); @@ -417,7 +418,7 @@ void QRandomAccessAsyncFilePrivate::processBufferAt(qsizetype idx) } } -void QRandomAccessAsyncFilePrivate::processFlush() +void QRandomAccessAsyncFileThreadPoolBackend::processFlush() { Q_ASSERT(!m_currentOperation.isNull()); auto *priv = QIOOperationPrivate::get(m_currentOperation.get()); @@ -427,7 +428,7 @@ void QRandomAccessAsyncFilePrivate::processFlush() QBasicMutex *mutexPtr = &m_engineMutex; auto op = [engine = m_engine.get(), mutexPtr] { QMutexLocker locker(mutexPtr); - QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None}; + QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None}; if (engine) { if (!engine->flush()) result.error = QIOOperation::Error::Flush; @@ -442,7 +443,7 @@ void QRandomAccessAsyncFilePrivate::processFlush() m_watcher.setFuture(f); } -void QRandomAccessAsyncFilePrivate::processOpen() +void QRandomAccessAsyncFileThreadPoolBackend::processOpen() { Q_ASSERT(!m_currentOperation.isNull()); auto *priv = QIOOperationPrivate::get(m_currentOperation.get()); @@ -457,7 +458,7 @@ void QRandomAccessAsyncFilePrivate::processOpen() m_engineMutex.unlock(); QBasicMutex *mutexPtr = &m_engineMutex; auto op = [engine = m_engine.get(), mutexPtr, mode = m_openMode] { - QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None}; + QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None}; QMutexLocker locker(mutexPtr); const bool res = engine && engine->open(mode | QIODeviceBase::Unbuffered, std::nullopt); @@ -468,13 +469,13 @@ void QRandomAccessAsyncFilePrivate::processOpen() f = QtFuture::makeReadyVoidFuture().then(asyncFileThreadPool(), op); } else { f = QtFuture::makeReadyVoidFuture().then(asyncFileThreadPool(), [] { - return QRandomAccessAsyncFilePrivate::OperationResult{0, QIOOperation::Error::Open}; + return QRandomAccessAsyncFileThreadPoolBackend::OperationResult{0, QIOOperation::Error::Open}; }); } m_watcher.setFuture(f); } -void QRandomAccessAsyncFilePrivate::operationComplete() +void QRandomAccessAsyncFileThreadPoolBackend::operationComplete() { // TODO: if one of the buffers was read/written with an error, // stop processing immediately diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index ce35e8ccffe..1e647a83dc0 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -333,12 +333,12 @@ struct TCBPoint qreal _b; - bool operator==(const TCBPoint &other) const + friend bool operator==(const TCBPoint &lhs, const TCBPoint &rhs) noexcept { - return _point == other._point && - qFuzzyCompare(_t, other._t) && - qFuzzyCompare(_c, other._c) && - qFuzzyCompare(_b, other._b); + return qFuzzyCompare(lhs._point, rhs._point) + && QtPrivate::fuzzyCompare(lhs._t, rhs._t) + && QtPrivate::fuzzyCompare(lhs._c, rhs._c) + && QtPrivate::fuzzyCompare(lhs._b, rhs._b); } }; Q_DECLARE_TYPEINFO(TCBPoint, Q_PRIMITIVE_TYPE); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 0905ba3e644..1b34490e358 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -330,6 +330,13 @@ QMargins QCocoaWindow::safeAreaMargins() const // merge them. auto screenRect = m_view.window.screen.frame; auto screenInsets = m_view.window.screen.safeAreaInsets; + auto screenSafeArea = QCocoaScreen::mapFromNative(NSMakeRect( + NSMinX(screenRect) + screenInsets.left, + NSMinY(screenRect) + screenInsets.bottom, // Non-flipped + NSWidth(screenRect) - screenInsets.left - screenInsets.right, + NSHeight(screenRect) - screenInsets.top - screenInsets.bottom + )); + auto screenRelativeViewBounds = QCocoaScreen::mapFromNative( [m_view.window convertRectToScreen: [m_view convertRect:m_view.bounds toView:nil]] @@ -339,20 +346,10 @@ QMargins QCocoaWindow::safeAreaMargins() const // Note that we do not want represent the area outside of the // screen as being outside of the safe area. QMarginsF screenSafeAreaMargins = { - screenInsets.left ? - qMax(0.0f, screenInsets.left - screenRelativeViewBounds.left()) - : 0.0f, - screenInsets.top ? - qMax(0.0f, screenInsets.top - screenRelativeViewBounds.top()) - : 0.0f, - screenInsets.right ? - qMax(0.0f, screenInsets.right - - (screenRect.size.width - screenRelativeViewBounds.right())) - : 0.0f, - screenInsets.bottom ? - qMax(0.0f, screenInsets.bottom - - (screenRect.size.height - screenRelativeViewBounds.bottom())) - : 0.0f + qMin(screenSafeArea.left() - screenRelativeViewBounds.left(), screenInsets.left), + qMin(screenSafeArea.top() - screenRelativeViewBounds.top(), screenInsets.top), + qMin(screenRelativeViewBounds.right() - screenSafeArea.right(), screenInsets.right), + qMin(screenRelativeViewBounds.bottom() - screenSafeArea.bottom(), screenInsets.bottom) }; return (screenSafeAreaMargins | viewSafeAreaMargins).toMargins(); |
