diff options
41 files changed, 582 insertions, 328 deletions
diff --git a/cmake/QtInitProject.cmake b/cmake/QtInitProject.cmake index 8860b3578ed..c2a21202108 100644 --- a/cmake/QtInitProject.cmake +++ b/cmake/QtInitProject.cmake @@ -209,5 +209,5 @@ message("The project file is successfully generated. To build the project run:" "\nmkdir build" "\ncd build" "\nqt-cmake ${project_abs_dir}" - "\ncmake --build ${project_abs_dir}" + "\ncmake --build ." ) diff --git a/cmake/QtPublicAppleHelpers.cmake b/cmake/QtPublicAppleHelpers.cmake index 3ffe53c6f34..b8f3fb4818e 100644 --- a/cmake/QtPublicAppleHelpers.cmake +++ b/cmake/QtPublicAppleHelpers.cmake @@ -1028,7 +1028,6 @@ function(_qt_internal_check_apple_sdk_and_xcode_versions) endif() _qt_internal_get_cached_apple_sdk_version(sdk_version) - _qt_internal_get_cached_xcode_version(xcode_version) if(NOT max_sdk_version MATCHES "^[0-9]+$") message(FATAL_ERROR @@ -1075,12 +1074,15 @@ function(_qt_internal_check_apple_sdk_and_xcode_versions) ) endif() - if(xcode_version VERSION_LESS min_xcode_version AND NOT QT_NO_XCODE_MIN_VERSION_CHECK) - message(${message_type} - "Qt requires at least version ${min_xcode_version} of Xcode, " - "you're building against version ${xcode_version}. Please upgrade." - ${extra_message} - ) + if(NOT QT_NO_XCODE_MIN_VERSION_CHECK) + _qt_internal_get_cached_xcode_version(xcode_version) + if(xcode_version VERSION_LESS min_xcode_version) + message(${message_type} + "Qt requires at least version ${min_xcode_version} of Xcode, " + "you're building against version ${xcode_version}. Please upgrade." + ${extra_message} + ) + endif() endif() if(QT_NO_APPLE_SDK_MAX_VERSION_CHECK) diff --git a/configure.cmake b/configure.cmake index e89922f76f8..0d4e5b04688 100644 --- a/configure.cmake +++ b/configure.cmake @@ -621,7 +621,7 @@ qt_feature("private_tests" PRIVATE ) qt_feature("doc_snippets" PRIVATE LABEL "Developer build: doc_snippets" - AUTODETECT QT_FEATURE_developer_build + AUTODETECT QT_BUILD_DOC_SNIPPETS CONDITION QT_FEATURE_shared ) qt_feature_definition("developer-build" "QT_BUILD_INTERNAL") diff --git a/mkspecs/common/msvc-based-version.conf b/mkspecs/common/msvc-based-version.conf index adc893836a9..a687fa5f449 100644 --- a/mkspecs/common/msvc-based-version.conf +++ b/mkspecs/common/msvc-based-version.conf @@ -42,4 +42,10 @@ greaterThan(QMAKE_MSC_VER, 1929) { MSVC_TOOLSET_VER = 143 } +greaterThan(QMAKE_MSC_VER, 1949) { + # Visual Studio 2026 (18.0) / Visual C++ 19.50 and up + MSVC_VER = 18.0 + MSVC_TOOLSET_VER = 145 +} + !isEmpty(COMPAT_MKSPEC):!$$COMPAT_MKSPEC: CONFIG += $$COMPAT_MKSPEC diff --git a/mkspecs/common/msvc-version.conf b/mkspecs/common/msvc-version.conf index 0130542ddb9..8270f02e890 100644 --- a/mkspecs/common/msvc-version.conf +++ b/mkspecs/common/msvc-version.conf @@ -147,4 +147,10 @@ greaterThan(QMAKE_MSC_VER, 1929) { MSVC_TOOLSET_VER = 143 } +greaterThan(QMAKE_MSC_VER, 1949) { + # Visual Studio 2026 (18.0) / Visual C++ 19.50 and up + MSVC_VER = 18.0 + MSVC_TOOLSET_VER = 145 +} + !isEmpty(COMPAT_MKSPEC):!$$COMPAT_MKSPEC: CONFIG += $$COMPAT_MKSPEC diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 6517e5c4516..0776a4a5267 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -25,6 +25,8 @@ DotNET vsVersionFromString(const ProString &versionString) int versionMajor = versionView.left(idx).toInt(); int versionMinor = versionView.mid(idx + 1).toInt(); + if (versionMajor == 18) + return NET2026; if (versionMajor == 17) return NET2022; if (versionMajor == 16) diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h index 190d6c727fa..58f818a3bc5 100644 --- a/qmake/generators/win32/msvc_objectmodel.h +++ b/qmake/generators/win32/msvc_objectmodel.h @@ -29,7 +29,8 @@ enum DotNET { NET2015 = 0xd0, NET2017 = 0xe0, NET2019, - NET2022 + NET2022, + NET2026 }; DotNET vsVersionFromString(const ProString &versionString); diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 1566f72ba66..7c2e0562aa7 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -56,6 +56,8 @@ const char _slnHeader142[] = "Microsoft Visual Studio Solution File, Format "\n# Visual Studio Version 16"; const char _slnHeader143[] = "Microsoft Visual Studio Solution File, Format Version 12.00" "\n# Visual Studio Version 17"; +const char _slnHeader145[] = "Microsoft Visual Studio Solution File, Format Version 12.00" + "\n# Visual Studio Version 18"; // The following UUID _may_ change for later servicepacks... // If so we need to search through the registry at // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\Projects @@ -502,6 +504,9 @@ void VcprojGenerator::writeSubDirs(QTextStream &t) } switch (vcProject.Configuration.CompilerVersion) { + case NET2026: + t << _slnHeader145; + break; case NET2022: t << _slnHeader143; break; @@ -882,6 +887,9 @@ void VcprojGenerator::initProject() // Own elements ----------------------------- vcProject.Name = project->first("QMAKE_ORIG_TARGET").toQString(); switch (vcProject.Configuration.CompilerVersion) { + case NET2026: + vcProject.Version = "18.00"; + break; case NET2022: vcProject.Version = "17.00"; break; diff --git a/src/3rdparty/libjpeg/COPYRIGHT.txt b/src/3rdparty/libjpeg/COPYRIGHT.txt index f5eae868466..ce9d95bfebc 100644 --- a/src/3rdparty/libjpeg/COPYRIGHT.txt +++ b/src/3rdparty/libjpeg/COPYRIGHT.txt @@ -1,4 +1,4 @@ -Copyright (C) 2009-2025 D. R. Commander +Copyright (C) 2009-2024 D. R. Commander Copyright (C) 2015, 2020 Google, Inc. Copyright (C) 2019-2020 Arm Limited Copyright (C) 2015-2016, 2018 Matthieu Darbois diff --git a/src/3rdparty/libjpeg/ChangeLog.md b/src/3rdparty/libjpeg/ChangeLog.md index 4bdbf53dd34..17390d80bd0 100644 --- a/src/3rdparty/libjpeg/ChangeLog.md +++ b/src/3rdparty/libjpeg/ChangeLog.md @@ -1,3 +1,34 @@ +3.1.3 +===== + +### Significant changes relative to 3.1.2: + +1. Hardened the TurboJPEG API against hypothetical applications that may +erroneously call `tj*Compress*()` or `tj*Transform()` with a reused JPEG +destination buffer pointer while specifying a destination buffer size of 0. + +2. Hardened the TurboJPEG API against hypothetical applications that may +erroneously set `TJPARAM_LOSSLESS` or `TJPARAM_COLORSPACE` prior to calling +`tj3EncodeYUV*8()` or `tj3CompressFromYUV*8()`. `tj3EncodeYUV*8()` and +`tj3CompressFromYUV*8()` now ignore `TJPARAM_LOSSLESS` and +`TJPARAM_COLORSPACE`. + +3. Hardened the TurboJPEG Java API against hypothetical applications that may +erroneously pass huge X or Y offsets to one of the compression, YUV encoding, +decompression, or YUV decoding methods, leading to signed integer overflow in +the JNI wrapper's buffer size checks that rendered those checks ineffective. + +4. Fixed an issue in the TurboJPEG Java API whereby +`TJCompressor.getSourceBuf()` sometimes returned the buffer from a previous +invocation of `TJCompressor.loadSourceImage()` if the target data precision was +changed before the most recent invocation. + +5. Fixed an issue in the PPM reader that caused incorrect pixels to be +generated when using `tj3LoadImage*()` or `TJCompressor.loadSourceImage()` to +load a PBMPLUS (PPM/PGM) file into a CMYK buffer with a different data +precision than that of the file. + + 3.1.2 ===== @@ -962,9 +993,9 @@ storage. 64-bit libjpeg-turbo SDK for Visual C++ were installed on the same system, only one of them could be uninstalled. -2. Fixed a signed integer overflow and subsequent segfault that occurred when -attempting to decompress images with more than 715827882 pixels using the -64-bit C version of TJBench. +2. Fixed a signed integer overflow and subsequent segfault (CVE-2019-2201) that +occurred when attempting to decompress images with more than 715827882 pixels +using the 64-bit C version of TJBench. 3. Fixed out-of-bounds write in `tjDecompressToYUV2()` and `tjDecompressToYUVPlanes()` (sometimes manifesting as a double free) that @@ -1016,9 +1047,9 @@ regardless of whether a 4:2:2 JPEG image is rotated or transposed prior to decompression (in the frequency domain) or after decompression (in the spatial domain), the final image will be similar. -4. Fixed an integer overflow and subsequent segfault that occurred when -attempting to compress or decompress images with more than 1 billion pixels -using the TurboJPEG API. +4. Fixed an integer overflow and subsequent segfault (CVE-2019-2201) that +occurred when attempting to compress or decompress images with more than 1 +billion pixels using the TurboJPEG API. 5. Fixed a regression introduced by 2.0 beta1[15] whereby attempting to generate a progressive JPEG image on an SSE2-capable CPU using a scan script diff --git a/src/3rdparty/libjpeg/qt_attribution.json b/src/3rdparty/libjpeg/qt_attribution.json index fe38aec1f68..5ac811a12b4 100644 --- a/src/3rdparty/libjpeg/qt_attribution.json +++ b/src/3rdparty/libjpeg/qt_attribution.json @@ -7,8 +7,8 @@ "Description": "The Independent JPEG Group's JPEG software", "Homepage": "http://libjpeg-turbo.virtualgl.org/", - "Version": "3.1.2", - "DownloadLocation": "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.1.2/libjpeg-turbo-3.1.2.tar.gz", + "Version": "3.1.3", + "DownloadLocation": "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.1.3/libjpeg-turbo-3.1.3.tar.gz", "PURL": "pkg:github/libjpeg-turbo/libjpeg-turbo@$<VERSION>", "CPE": "cpe:2.3:a:libjpeg-turbo:libjpeg-turbo:$<VERSION>:*:*:*:*:*:*:*", diff --git a/src/3rdparty/libjpeg/src/jconfig.h b/src/3rdparty/libjpeg/src/jconfig.h index e81574b9a48..85a1509fb68 100644 --- a/src/3rdparty/libjpeg/src/jconfig.h +++ b/src/3rdparty/libjpeg/src/jconfig.h @@ -2,9 +2,9 @@ #define JPEG_LIB_VERSION 80 -#define LIBJPEG_TURBO_VERSION 3.0.3 +#define LIBJPEG_TURBO_VERSION 3.1.3 -#define LIBJPEG_TURBO_VERSION_NUMBER 3000003 +#define LIBJPEG_TURBO_VERSION_NUMBER 3001003 #define C_ARITH_CODING_SUPPORTED 1 diff --git a/src/3rdparty/libjpeg/src/jconfigint.h b/src/3rdparty/libjpeg/src/jconfigint.h index 6e7dbd75a1e..6d5f9633928 100644 --- a/src/3rdparty/libjpeg/src/jconfigint.h +++ b/src/3rdparty/libjpeg/src/jconfigint.h @@ -10,7 +10,7 @@ #define PACKAGE_NAME "libjpeg-turbo" -#define VERSION "3.0.3" +#define VERSION "3.1.3" #if SIZE_MAX == 0xffffffff #define SIZEOF_SIZE_T 4 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..7274b51cc0a 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -620,6 +620,10 @@ int main(void) HRESULT hr = CreateIoRing(IORING_VERSION_3, flags, 1, 1, &ioRingHandle); if (hr == IORING_E_SUBMISSION_QUEUE_FULL) // not valid, but test that this #define exists return 0; + IORING_HANDLE_REF ref(HANDLE(nullptr)); + IORING_BUFFER_REF bufRef(nullptr); + // The newest API addition that we require: + BuildIoRingWriteFile(ioRingHandle, ref, bufRef, -1, 0, FILE_WRITE_FLAGS_NONE, 0, IOSQE_FLAGS_NONE); /* END TEST: */ return 0; } @@ -806,7 +810,7 @@ qt_feature("winsdkicu" PRIVATE CONDITION TEST_winsdkicu DISABLE QT_FEATURE_icu ) -qt_feature("windows_ioring" PRIVATE +qt_feature("windows-ioring" PRIVATE LABEL "Windows I/O Ring" AUTODETECT WIN32 AND CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 10.0.22000 CONDITION TEST_windows_ioring @@ -1284,7 +1288,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") @@ -1297,7 +1301,7 @@ qt_configure_add_summary_entry(ARGS "glib") qt_configure_add_summary_entry(ARGS "icu") qt_configure_add_summary_entry(ARGS "jemalloc") qt_configure_add_summary_entry(ARGS "liburing") -qt_configure_add_summary_entry(ARGS "windows_ioring") +qt_configure_add_summary_entry(ARGS "windows-ioring") qt_configure_add_summary_entry(ARGS "timezone_tzdb") qt_configure_add_summary_entry(ARGS "system-libb2") qt_configure_add_summary_entry(ARGS "mimetype-database") diff --git a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc index b8e5e038a33..7cd3f91b901 100644 --- a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc +++ b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc @@ -525,7 +525,6 @@ To prevent this, set \c QT_NO_SET_XCODE_BUNDLE_IDENTIFIER to \c TRUE. \summary {Enables verbose mode of deployment tools.} \cmakevariablesince 6.3 -\preliminarycmakevariable Enables verbose mode of the \l androiddeployqt deployment tool when it is called internally at build time, usually during target finalization. @@ -545,7 +544,6 @@ must be set before the first \c{find_package(Qt6)} call to have that effect. \summary {Name of the file to include for setting up deployment support.} \cmakevariablesince 6.3 -\preliminarycmakevariable \note The value of this variable should never be modified by project code. This configure-phase variable is set by the Core package. It is intended to be diff --git a/src/corelib/doc/src/cmake/cmake-properties.qdoc b/src/corelib/doc/src/cmake/cmake-properties.qdoc index 821862494a2..c7b1a27a4b4 100644 --- a/src/corelib/doc/src/cmake/cmake-properties.qdoc +++ b/src/corelib/doc/src/cmake/cmake-properties.qdoc @@ -665,7 +665,6 @@ UTF-8 input). Use the \l QT_NO_CAST_FROM_ASCII and \summary {Specifies the default Qt resource prefix.} \cmakepropertysince 6.0 -\preliminarycmakeproperty When using \l{qt6_add_resources}{qt_add_resources} without a \c PREFIX argument, then the value of this target property will be used as @@ -773,7 +772,6 @@ CMake properties: \brief Sets the FOLDER property for Qt-internal targets. \cmakepropertysince 6.5 -\preliminarycmakeproperty Name of the \l FOLDER for internal targets that are added by Qt's CMake commands. diff --git a/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc b/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc index 43ff23a35a1..e6d3edbbdc4 100644 --- a/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc +++ b/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc @@ -17,7 +17,6 @@ can only be called from a deployment script. It cannot be called directly by the project during the configure stage. \cmakecommandsince 6.5 -\preliminarycmakecommand \note This command does not usually need to be called directly. It is used internally by other higher level commands, but projects wishing to implement more customized deployment logic may find it useful. diff --git a/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc b/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc index 7ec8d90f9b1..24112b1cf87 100644 --- a/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc +++ b/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc @@ -11,7 +11,6 @@ \summary {Extracts metatypes from a Qt target and generates an associated metatypes.json file.} \cmakecommandsince 6.0 -\preliminarycmakecommand \section1 Synopsis diff --git a/src/corelib/doc/src/cmake/qt_finalize_project.qdoc b/src/corelib/doc/src/cmake/qt_finalize_project.qdoc index 5506712691e..f60b850fcdb 100644 --- a/src/corelib/doc/src/cmake/qt_finalize_project.qdoc +++ b/src/corelib/doc/src/cmake/qt_finalize_project.qdoc @@ -9,7 +9,6 @@ \keyword qt6_finalize_project \summary {Handles various common platform-specific tasks associated with a Qt project.} -\preliminarycmakecommand \include cmake-find-package-core.qdocinc 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/qioring_p.h b/src/corelib/io/qioring_p.h index 0db832bc6bf..8fdaf48f8f6 100644 --- a/src/corelib/io/qioring_p.h +++ b/src/corelib/io/qioring_p.h @@ -91,6 +91,10 @@ enum class Operation : quint8 { // clang-format on Q_ENUM_NS(Operation); #undef DEFINE_ENTRY + +#ifdef Q_OS_WIN +struct IORingApiTable; +#endif }; // namespace QtPrivate template <QtPrivate::Operation Op> @@ -221,9 +225,11 @@ private: std::optional<QWinEventNotifier> notifier; HIORING ioRingHandle = nullptr; HANDLE eventHandle = INVALID_HANDLE_VALUE; + const QtPrivate::IORingApiTable *apiTable; bool initialized = false; bool queueWasFull = false; + [[nodiscard]] RequestPrepResult prepareRequest(GenericRequestType &request); QIORing::ReadWriteStatus handleReadCompletion( diff --git a/src/corelib/io/qioring_win.cpp b/src/corelib/io/qioring_win.cpp index 42c51f428d6..b2f188486d0 100644 --- a/src/corelib/io/qioring_win.cpp +++ b/src/corelib/io/qioring_win.cpp @@ -24,6 +24,59 @@ static_assert(sizeof(qsizetype) > sizeof(UINT32), using namespace Qt::StringLiterals; +namespace QtPrivate { +#define FOREACH_WIN_IORING_FUNCTION(Fn) \ + Fn(BuildIoRingReadFile) \ + Fn(BuildIoRingWriteFile) \ + Fn(BuildIoRingFlushFile) \ + Fn(BuildIoRingCancelRequest) \ + Fn(QueryIoRingCapabilities) \ + Fn(CreateIoRing) \ + Fn(GetIoRingInfo) \ + Fn(SubmitIoRing) \ + Fn(CloseIoRing) \ + Fn(PopIoRingCompletion) \ + Fn(SetIoRingCompletionEvent) \ + /**/ +struct IORingApiTable +{ +#define DefineIORingFunction(Name) \ + using Name##Fn = decltype(&::Name); \ + Name##Fn Name = nullptr; + + FOREACH_WIN_IORING_FUNCTION(DefineIORingFunction) + +#undef DefineIORingFunction +}; + +static const IORingApiTable *getApiTable() +{ + static const IORingApiTable apiTable = []() { + IORingApiTable apiTable; + const HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (Q_UNLIKELY(!kernel32)) // how would this happen + return apiTable; + +#define ResolveFunction(Name) \ + apiTable.Name = IORingApiTable::Name##Fn(QFunctionPointer(GetProcAddress(kernel32, #Name))); + + FOREACH_WIN_IORING_FUNCTION(ResolveFunction) + +#undef ResolveFunction + return apiTable; + }(); + +#define TEST_TABLE_OK(X) \ + apiTable.X && /* chain */ +#define BOOL_CHAIN(...) (__VA_ARGS__ true) + const bool success = BOOL_CHAIN(FOREACH_WIN_IORING_FUNCTION(TEST_TABLE_OK)); +#undef BOOL_CHAIN +#undef TEST_TABLE_OK + + return success ? std::addressof(apiTable) : nullptr; +} +} // namespace QtPrivate + static HRESULT buildReadOperation(HIORING ioRingHandle, qintptr fd, QSpan<std::byte> destination, quint64 offset, quintptr userData) { @@ -32,8 +85,10 @@ static HRESULT buildReadOperation(HIORING ioRingHandle, qintptr fd, QSpan<std::b const IORING_BUFFER_REF bufferRef(destination.data()); const auto maxSize = q26::saturate_cast<UINT32>(destination.size()); Q_ASSERT(maxSize == destination.size()); - return BuildIoRingReadFile(ioRingHandle, fileRef, bufferRef, maxSize, offset, userData, - IOSQE_FLAGS_NONE); + const auto *apiTable = QtPrivate::getApiTable(); + Q_ASSERT(apiTable); // If we got this far it needs to be here + return apiTable->BuildIoRingReadFile(ioRingHandle, fileRef, bufferRef, maxSize, offset, + userData, IOSQE_FLAGS_NONE); } static HRESULT buildWriteOperation(HIORING ioRingHandle, qintptr fd, QSpan<const std::byte> source, @@ -44,16 +99,18 @@ static HRESULT buildWriteOperation(HIORING ioRingHandle, qintptr fd, QSpan<const const IORING_BUFFER_REF bufferRef(const_cast<std::byte *>(source.data())); const auto maxSize = q26::saturate_cast<UINT32>(source.size()); Q_ASSERT(maxSize == source.size()); + const auto *apiTable = QtPrivate::getApiTable(); + Q_ASSERT(apiTable); // If we got this far it needs to be here // @todo: FILE_WRITE_FLAGS can be set to write-through, could be used for Unbuffered mode. - return BuildIoRingWriteFile(ioRingHandle, fileRef, bufferRef, maxSize, offset, - FILE_WRITE_FLAGS_NONE, userData, IOSQE_FLAGS_NONE); + return apiTable->BuildIoRingWriteFile(ioRingHandle, fileRef, bufferRef, maxSize, offset, + FILE_WRITE_FLAGS_NONE, userData, IOSQE_FLAGS_NONE); } QIORing::~QIORing() { if (initialized) { CloseHandle(eventHandle); - CloseIoRing(ioRingHandle); + apiTable->CloseIoRing(ioRingHandle); } } @@ -62,8 +119,13 @@ bool QIORing::initializeIORing() if (initialized) return true; + if (apiTable = QtPrivate::getApiTable(); !apiTable) { + qCWarning(lcQIORing, "Failed to retrieve API table"); + return false; + } + IORING_CAPABILITIES capabilities; - QueryIoRingCapabilities(&capabilities); + apiTable->QueryIoRingCapabilities(&capabilities); if (capabilities.MaxVersion < IORING_VERSION_3) // 3 adds write, flush and drain return false; if ((capabilities.FeatureFlags & IORING_FEATURE_SET_COMPLETION_EVENT) == 0) @@ -75,7 +137,8 @@ bool QIORing::initializeIORing() IORING_CREATE_FLAGS flags; memset(&flags, 0, sizeof(flags)); - HRESULT hr = CreateIoRing(IORING_VERSION_3, flags, sqEntries, cqEntries, &ioRingHandle); + HRESULT hr = apiTable->CreateIoRing(IORING_VERSION_3, flags, sqEntries, cqEntries, + &ioRingHandle); if (FAILED(hr)) { qErrnoWarning(hr, "failed to initialize QIORing"); return false; @@ -83,7 +146,7 @@ bool QIORing::initializeIORing() auto earlyExitCleanup = qScopeGuard([this]() { if (eventHandle != INVALID_HANDLE_VALUE) CloseHandle(eventHandle); - CloseIoRing(ioRingHandle); + apiTable->CloseIoRing(ioRingHandle); }); eventHandle = CreateEvent(nullptr, TRUE, FALSE, nullptr); if (eventHandle == INVALID_HANDLE_VALUE) { @@ -91,13 +154,13 @@ bool QIORing::initializeIORing() return false; } notifier.emplace(eventHandle); - hr = SetIoRingCompletionEvent(ioRingHandle, eventHandle); + hr = apiTable->SetIoRingCompletionEvent(ioRingHandle, eventHandle); if (FAILED(hr)) { qErrnoWarning(hr, "Failed to assign the event handle to QIORing"); return false; } IORING_INFO info; - if (SUCCEEDED(GetIoRingInfo(ioRingHandle, &info))) { + if (SUCCEEDED(apiTable->GetIoRingInfo(ioRingHandle, &info))) { sqEntries = info.SubmissionQueueSize; cqEntries = info.CompletionQueueSize; qCDebug(lcQIORing) << "QIORing configured with capacity for" << sqEntries @@ -274,7 +337,7 @@ void QIORing::completionReady() { ResetEvent(eventHandle); IORING_CQE entry; - while (PopIoRingCompletion(ioRingHandle, &entry) == S_OK) { + while (apiTable->PopIoRingCompletion(ioRingHandle, &entry) == S_OK) { // NOLINTNEXTLINE(performance-no-int-to-ptr) auto *request = reinterpret_cast<GenericRequestType *>(entry.UserData); if (!addrItMap.contains(request)) { @@ -458,7 +521,8 @@ void QIORing::submitRequests() const bool shouldTryWait = std::exchange(queueWasFull, false); const auto submitToRing = [this, &shouldTryWait] { quint32 submittedEntries = 0; - HRESULT hr = SubmitIoRing(ioRingHandle, shouldTryWait ? 1 : 0, 1, &submittedEntries); + HRESULT hr = apiTable->SubmitIoRing(ioRingHandle, shouldTryWait ? 1 : 0, 1, + &submittedEntries); qCDebug(lcQIORing) << "Submitted" << submittedEntries << "requests"; unstagedRequests -= submittedEntries; if (FAILED(hr)) { @@ -558,9 +622,9 @@ auto QIORing::prepareRequest(GenericRequestType &request) -> RequestPrepResult auto *closeRequest = request.requestData<Operation::Close>(); // NOLINTNEXTLINE(performance-no-int-to-ptr) const IORING_HANDLE_REF fileRef(HANDLE(closeRequest->fd)); - hr = BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_MIN_METADATA, - quintptr(std::addressof(request)), - IOSQE_FLAGS_DRAIN_PRECEDING_OPS); + hr = apiTable->BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_MIN_METADATA, + quintptr(std::addressof(request)), + IOSQE_FLAGS_DRAIN_PRECEDING_OPS); break; } case Operation::Read: { @@ -645,9 +709,9 @@ auto QIORing::prepareRequest(GenericRequestType &request) -> RequestPrepResult auto *flushRequest = request.requestData<Operation::Flush>(); // NOLINTNEXTLINE(performance-no-int-to-ptr) const IORING_HANDLE_REF fileRef(HANDLE(flushRequest->fd)); - hr = BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_DEFAULT, - quintptr(std::addressof(request)), - IOSQE_FLAGS_DRAIN_PRECEDING_OPS); + hr = apiTable->BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_DEFAULT, + quintptr(std::addressof(request)), + IOSQE_FLAGS_DRAIN_PRECEDING_OPS); break; } case QtPrivate::Operation::Stat: { @@ -703,8 +767,8 @@ auto QIORing::prepareRequest(GenericRequestType &request) -> RequestPrepResult } // NOLINTNEXTLINE(performance-no-int-to-ptr) const IORING_HANDLE_REF fileRef((HANDLE(fd))); - hr = BuildIoRingCancelRequest(ioRingHandle, fileRef, quintptr(otherOperation), - quintptr(std::addressof(request))); + hr = apiTable->BuildIoRingCancelRequest(ioRingHandle, fileRef, quintptr(otherOperation), + quintptr(std::addressof(request))); break; } case Operation::NumOperations: 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/kernel/qmetacontainer.h b/src/corelib/kernel/qmetacontainer.h index c9d3a6bf9c6..66047afefd4 100644 --- a/src/corelib/kernel/qmetacontainer.h +++ b/src/corelib/kernel/qmetacontainer.h @@ -971,18 +971,11 @@ public: Iterator mutableEnd(); QVariant at(qsizetype idx) const; - void set(qsizetype idx, const QVariant &value); + void setAt(qsizetype idx, const QVariant &value); void append(const QVariant &value); void prepend(const QVariant &value); void removeLast(); void removeFirst(); - -#if QT_DEPRECATED_SINCE(6, 11) - enum Position: quint8 { Unspecified, AtBegin, AtEnd }; - void addValue(const QVariant &value, Position position = Unspecified); - void removeValue(Position position = Unspecified); - QMetaType valueMetaType() const; -#endif // QT_DEPRECATED_SINCE(6, 11) }; #else using Iterable = QtMetaContainerPrivate::Sequence; diff --git a/src/corelib/kernel/qmetasequence.cpp b/src/corelib/kernel/qmetasequence.cpp index 2a3a923d5ca..018dd610146 100644 --- a/src/corelib/kernel/qmetasequence.cpp +++ b/src/corelib/kernel/qmetasequence.cpp @@ -531,39 +531,6 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con */ /*! - \enum QMetaSequence::Iterable::Position - \deprecated [6.11] Use append(), prepend(), removeFirst(), or removeLast() - - Specifies the position at which an element shall be added to or removed from - the iterable. - - \value AtBegin - Add or remove at the beginning of the iterable. - \value AtEnd - Add or remove at the end of the iterable. - \value Unspecified - Add or remove at an unspecified position in the iterable. - */ - -/*! - \fn void QMetaSequence::Iterable::addValue(const QVariant &value, Position position) - \deprecated [6.11] Use append() or prepend() - Adds \a value to the container, at \a position, if possible. - */ - -/*! - \deprecated [6.11] Use removeFirst() or removeLast() - \fn void QMetaSequence::Iterable::removeValue(Position position) - Removes a value from the container, at \a position, if possible. - */ - -/*! - \deprecated [6.11] Use QMetaSequence::valueMetaType() - \fn QMetaType QMetaSequence::Iterable::valueMetaType() const - Returns the meta type for values stored in the underlying container. - */ - -/*! \fn QVariant QMetaSequence::Iterable::at(qsizetype idx) const Returns the value at position \a idx in the container. @@ -574,13 +541,8 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con */ /*! - \fn void QMetaSequence::Iterable::set(qsizetype idx, const QVariant &value) + \fn void QMetaSequence::Iterable::setAt(qsizetype idx, const QVariant &value) Sets the element at position \a idx in the container to \a value. - - \note If the underlying container does not provide a native way to assign - an element at an index, this method will synthesize the assignment - using iterators. This behavior is deprecated and will be removed in a - future version of Qt. */ /*! diff --git a/src/corelib/kernel/qmetasequence.h b/src/corelib/kernel/qmetasequence.h index 26156e7924f..f8052476d79 100644 --- a/src/corelib/kernel/qmetasequence.h +++ b/src/corelib/kernel/qmetasequence.h @@ -196,25 +196,11 @@ public: }); } - void set(qsizetype idx, const QVariant &value) + void setAt(qsizetype idx, const QVariant &value) { const QMetaSequence meta = metaContainer(); QtPrivate::QVariantTypeCoercer coercer; - const void *dataPtr = coercer.coerce(value, meta.valueMetaType()); - if (meta.canSetValueAtIndex()) { - meta.setValueAtIndex(mutableIterable(), idx, dataPtr); - return; - } - -#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) - // We shouldn't second-guess the underlying container - QtPrivate::warnSynthesizedAccess( - "set() called on an iterable without native indexed accessors. This is slow"); - void *it = meta.begin(m_iterable.mutablePointer()); - meta.advanceIterator(it, idx); - meta.setValueAtIterator(it, dataPtr); - meta.destroyIterator(it); -#endif + meta.setValueAtIndex(mutableIterable(), idx, coercer.coerce(value, meta.valueMetaType())); } void append(const QVariant &value) @@ -261,6 +247,9 @@ public: QMetaType valueMetaType() const Q_DECL_EQ_DELETE_X("Use QMetaSequence::valueMetaType() instead."); + void set(qsizetype idx, const QVariant &value) + Q_DECL_EQ_DELETE_X("Use setAt() instead."); + QT_WARNING_POP #endif // QT_DEPRECATED_SINCE(6, 11) }; 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/network/access/qnetworkaccesscache.cpp b/src/network/access/qnetworkaccesscache.cpp index 6ff70cd546d..1f2bbd321cf 100644 --- a/src/network/access/qnetworkaccesscache.cpp +++ b/src/network/access/qnetworkaccesscache.cpp @@ -176,18 +176,6 @@ void QNetworkAccessCache::updateTimer() timer.start(interval + 10, this); } -bool QNetworkAccessCache::emitEntryReady(Node *node, QObject *target, const char *member) -{ - if (!connect(this, SIGNAL(entryReady(QNetworkAccessCache::CacheableObject*)), - target, member, Qt::QueuedConnection)) - return false; - - emit entryReady(node->object); - disconnect(SIGNAL(entryReady(QNetworkAccessCache::CacheableObject*))); - - return true; -} - void QNetworkAccessCache::timerEvent(QTimerEvent *) { while (firstExpiringNode && firstExpiringNode->timer.hasExpired()) { diff --git a/src/network/access/qnetworkaccesscache_p.h b/src/network/access/qnetworkaccesscache_p.h index 4d4ff325f98..5d7dc819461 100644 --- a/src/network/access/qnetworkaccesscache_p.h +++ b/src/network/access/qnetworkaccesscache_p.h @@ -69,9 +69,6 @@ public: void releaseEntry(const QByteArray &key); void removeEntry(const QByteArray &key); -signals: - void entryReady(QNetworkAccessCache::CacheableObject *); - protected: void timerEvent(QTimerEvent *) override; @@ -86,7 +83,6 @@ private: void linkEntry(const QByteArray &key); bool unlinkEntry(const QByteArray &key); void updateTimer(); - bool emitEntryReady(Node *node, QObject *target, const char *member); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QNetworkAccessCache::CacheableObject::Options) 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(); diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp index 64ffba2d6f8..36b5d0f0143 100644 --- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp +++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp @@ -16,6 +16,9 @@ #include <private/qapplication_p.h> #include <private/qsystemlibrary_p.h> #include <private/qwindowsthemecache_p.h> +#if QT_CONFIG(tooltip) +#include "private/qtooltip_p.h" +#endif #include "qdrawutil.h" // for now #include <qbackingstore.h> @@ -4676,7 +4679,7 @@ void QWindowsVistaStyle::polish(QWidget *widget) widget->setPalette(pal); } else #endif // QT_CONFIG(commandlinkbutton) - if (widget->inherits("QTipLabel")) { + if (qobject_cast<const QTipLabel *>(widget)) { //note that since tooltips are not reused //we do not have to care about unpolishing widget->setContentsMargins(3, 0, 4, 0); diff --git a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp index deb257be01c..d3b7d669ec7 100644 --- a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp +++ b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp @@ -407,8 +407,13 @@ QList<QSslCertificate> systemCaCertificates() for (const QByteArray &directory : directories) { for (const auto &dirEntry : QDirListing(QFile::decodeName(directory), flags)) { // use canonical path here to not load the same certificate twice if symlinked - if (hasMatchingExtension(dirEntry.fileName())) - certFiles.insert(dirEntry.canonicalFilePath()); + if (hasMatchingExtension(dirEntry.fileName())) { + QString canonicalPath = dirEntry.canonicalFilePath(); + // skip broken symlinks to not end up adding "" to the list which will then + // just be rejected by `QSslCertificate::fromFile` + if (!canonicalPath.isEmpty()) + certFiles.insert(canonicalPath); + } } } for (const QString& file : std::as_const(certFiles)) diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp index 29cafe9aea4..f3db4ece49e 100644 --- a/src/testlib/qtestlog.cpp +++ b/src/testlib/qtestlog.cpp @@ -305,9 +305,7 @@ namespace QTest { { static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(QTest::maxWarnings); - auto loggerCapture = loggers->allLoggers(); - - if (loggerCapture.isEmpty()) { + if (loggers.isDestroyed() || loggers->allLoggers().isEmpty()) { // the message handler may be called from a worker thread, after the main thread stopped // logging. Forwarding to original message handler to avoid swallowing the message Q_ASSERT(oldMessageHandler); @@ -326,6 +324,8 @@ namespace QTest { return; } + auto loggerCapture = loggers->allLoggers(); + if (type != QtFatalMsg) { if (counter.loadRelaxed() <= 0) return; diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 9499c88af12..bd2b5be11aa 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -32,7 +32,7 @@ #include "private/qwidgetwindow_p.h" #include "qpainter.h" #if QT_CONFIG(tooltip) -#include "qtooltip.h" +#include "private/qtooltip_p.h" #endif #if QT_CONFIG(whatsthis) #include "qwhatsthis.h" @@ -1435,7 +1435,9 @@ void QWidgetPrivate::createTLSysExtra() if (extra->topextra->opacity != 255 && q->isWindow()) extra->topextra->window->setOpacity(qreal(extra->topextra->opacity) / qreal(255)); - const bool isTipLabel = q->inherits("QTipLabel"); +#if QT_CONFIG(tooltip) + const bool isTipLabel = qobject_cast<const QTipLabel *>(q) != nullptr; +#endif const bool isAlphaWidget = !isTipLabel && q->inherits("QAlphaWidget"); #ifdef Q_OS_WIN // Pass on native parent handle for Widget embedded into Active X. diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 25b048db65e..e0fdd56e6d8 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -35,7 +35,7 @@ #include <qabstractscrollarea.h> #include "private/qabstractscrollarea_p.h" #if QT_CONFIG(tooltip) -#include <qtooltip.h> +#include "private/qtooltip_p.h" #endif #include <qshareddata.h> #if QT_CONFIG(toolbutton) @@ -950,7 +950,7 @@ QRenderRule::QRenderRule(const QList<Declaration> &declarations, const QObject * hasFont = v.extractFont(&font, &adj); #if QT_CONFIG(tooltip) - if (object && qstrcmp(object->metaObject()->className(), "QTipLabel") == 0) + if (qobject_cast<const QTipLabel *>(object) != nullptr) palette = QToolTip::palette(); #endif @@ -1495,7 +1495,7 @@ bool QRenderRule::hasModification() const static inline QObject *parentObject(const QObject *obj) { #if QT_CONFIG(tooltip) - if (qobject_cast<const QLabel *>(obj) && qstrcmp(obj->metaObject()->className(), "QTipLabel") == 0) { + if (qobject_cast<const QTipLabel *>(obj) != nullptr) { QObject *p = qvariant_cast<QObject *>(obj->property("_q_stylesheet_parent")); if (p) return p; @@ -1515,7 +1515,7 @@ public: return QStringList(); const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject(); #if QT_CONFIG(tooltip) - if (qstrcmp(metaObject->className(), "QTipLabel") == 0) + if (metaObject == &QTipLabel::staticMetaObject) return QStringList("QToolTip"_L1); #endif QStringList result; @@ -1581,7 +1581,7 @@ public: return false; const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject(); #if QT_CONFIG(tooltip) - if (qstrcmp(metaObject->className(), "QTipLabel") == 0) + if (metaObject == &QTipLabel::staticMetaObject) return nodeName == "QToolTip"_L1; #endif do { @@ -1747,7 +1747,7 @@ int QStyleSheetStyle::nativeFrameWidth(const QWidget *w) } #endif - if (qstrcmp(w->metaObject()->className(), "QTipLabel") == 0) + if (w->metaObject() == &QTipLabel::staticMetaObject) return base->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, nullptr, w); return base->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, w); |
